title: Asp net core rc2. Abstract class model binding
body: <p>In the RC1 I use the following code for abstract classes or interfaces binding:</p>
  
  <pre><code>public class MessageModelBinder : IModelBinder {
  
      public Task&lt;ModelBindingResult&gt; BindModelAsync(ModelBindingContext bindingContext) {
          if(bindingContext.ModelType == typeof(ICommand)) {
              var msgTypeResult = bindingContext.ValueProvider.GetValue("messageType");
              if(msgTypeResult == ValueProviderResult.None) {
                  return ModelBindingResult.FailedAsync(bindingContext.ModelName);
              }
              var type = Assembly.GetAssembly(typeof(MessageModelBinder )).GetTypes().SingleOrDefault(t =&gt; t.FullName == msgTypeResult.FirstValue);
              if(type == null) {
                  return ModelBindingResult.FailedAsync(bindingContext.ModelName);
              }
              var metadataProvider = (IModelMetadataProvider)bindingContext.OperationBindingContext.HttpContext.RequestServices.GetService(typeof(IModelMetadataProvider));
              bindingContext.ModelMetadata = metadataProvider.GetMetadataForType(type);
          }
          return ModelBindingResult.NoResultAsync;
      }
  }
  </code></pre>
  
  <p>This binder only reads model type (<code>messageType</code> parameter) from query string and overrides metadata type. And the rest of the work performed by standard binders such as <code>BodyModelBinder</code>.</p>
  
  <p>In Startup.cs I just add first binder:</p>
  
  <pre><code>services.AddMvc().Services.Configure&lt;MvcOptions&gt;(options =&gt; {
      options.ModelBinders.Insert(0, new MessageModelBinder());
  });
  </code></pre>
  
  <p>Controller:</p>
  
  <pre><code>[Route("api/[controller]")]
  public class MessageController : Controller {
      [HttpPost("{messageType}")]
      public ActionResult Post(string messageType, [FromBody]ICommand message) {
      } 
  }
  </code></pre>
  
  <p>How can I perform this in RC2?</p>
  
  <p>As far as I understand, now I have to use <code>IModelBinderProvider</code>. OK, I tried.
  Startup.cs:</p>
  
  <pre><code>services.AddMvc().Services.Configure&lt;MvcOptions&gt;(options =&gt; {
      options.ModelBinderProviders.Insert(0, new MessageModelBinderProvider());
  });
  </code></pre>
  
  <p>ModelBinderProvider:</p>
  
  <pre><code>public class MessageModelBinderProvider : IModelBinderProvider {
      public IModelBinder GetBinder(ModelBinderProviderContext context) {
          if(context == null) {
              throw new ArgumentNullException(nameof(context));
          }
          return context.Metadata.ModelType == typeof(ICommand) ? new MessageModelBinder() : null;
      }
  }
  </code></pre>
  
  <p>ModelBinder:</p>
  
  <pre><code>public class MessageModelBinder : IModelBinder {
      public Task BindModelAsync(ModelBindingContext bindingContext) {
          if(bindingContext.ModelType == typeof(ICommand)) {
              var msgTypeResult = bindingContext.ValueProvider.GetValue("messageType");
              if(msgTypeResult == ValueProviderResult.None) {
                  bindingContext.Result = ModelBindingResult.Failed(bindingContext.ModelName);
                  return Task.FromResult(0);
              }
              var type = typeof(MessageModelBinder).GetTypeInfo().Assembly.GetTypes().SingleOrDefault(t =&gt; t.FullName == msgTypeResult.FirstValue);
              if(type == null) {
                  bindingContext.Result = ModelBindingResult.Failed(bindingContext.ModelName);
                  return Task.FromResult(0);
              }
              var metadataProvider = (IModelMetadataProvider)bindingContext.OperationBindingContext.HttpContext.RequestServices.GetService(typeof(IModelMetadataProvider));
              bindingContext.ModelMetadata = metadataProvider.GetMetadataForType(type);
              bindingContext.Result = ModelBindingResult.Success(bindingContext.ModelName, Activator.CreateInstance(type));
          }
          return Task.FromResult(0);
      }
  }
  </code></pre>
  
  <p>But I cannot specify <code>NoResult</code>. If I do not specify <code>bindingContext.Result</code>, I get null model in controller.
  If I specify <code>bindingContext.Result</code>, I get empty model without setting model fields.</p>