ASP.NET MVC - Custom Model Binder on Interface Type
I'm not sure if this behavior is expected or not, but it seems that custom model binding doesn't work when the binding is assigned to an interface type. Has anyone experimented with this?
public interface ISomeModel {}
public class SomeModel : ISomeModel {}
public class MvcApplication : HttpApplication {
protected void Application_Start(object sender, EventArgs e) {
ModelBinders.Binders[typeof(ISomeModel)] = new MyCustomModelBinder();
}
}
With the above code when I bind to a model of type SomeModel, MyCustomModelBinder is never hit; however, if I change the above code and substitute typeof(ISomeModel)
for typeof(SomeModel)
and post the exact same form MyCustomModelBinder is called as expected. Does that seem right?
Edit
I found m开发者_JAVA百科yself back in this predicament over a year after I originally asked this question, and now I have a solution that works. Thank you Matt Hidinger!
http://www.matthidinger.com/archive/2011/08/16/An-inheritance-aware-ModelBinderProvider-in-MVC-3.aspx
I was experimenting with this issue and I came up with a solution of sorts. I made a class called InterfaceModelBinder:
public class InterfaceModelBinder : DefaultModelBinder
{
public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
{
ModelBindingContext context = new ModelBindingContext(bindingContext);
var item = Activator.CreateInstance(
Type.GetType(controllerContext.RequestContext.HttpContext.Request.Form["AssemblyQualifiedName"]));
Func<object> modelAccessor = () => item;
context.ModelMetadata = new ModelMetadata(new DataAnnotationsModelMetadataProvider(),
bindingContext.ModelMetadata.ContainerType, modelAccessor, item.GetType(), bindingContext.ModelName);
return base.BindModel(controllerContext, context);
}
}
Which I registered in my Application_Start as so:
ModelBinders.Binders.Add(typeof(IFormSubmission), new InterfaceModelBinder.Models.InterfaceModelBinder());
The interface and a concrete implementation look like this:
public interface IFormSubmission
{
}
public class ContactForm : IFormSubmission
{
public string Name
{
get;
set;
}
public string Email
{
get;
set;
}
public string Comments
{
get;
set;
}
}
The only downside to this whole approach (as you might have gathered already) is that I need to get the AssemblyQualifiedName from somewhere, and in this example it is being stored as a hidden field on the client side, like so:
<%=Html.HiddenFor(m => m.GetType().AssemblyQualifiedName) %>
I'm not certain though that the downsides of exposing the Type name to the client are worth losing the benefits of this approach. An Action like this can handle all my form submissions:
[HttpPost]
public ActionResult Process(IFormSubmission form)
{
if (ModelState.IsValid)
{
FormManager manager = new FormManager();
manager.Process(form);
}
//do whatever you want
}
Any thoughts on this approach?
Suddenly, an MVC3 solution appears:
http://www.matthidinger.com/archive/2011/08/16/An-inheritance-aware-ModelBinderProvider-in-MVC-3.aspx
I'm not sure if its directly related but yes there are things that you need to think about when using model binding and interfaces... I ran into similar problems with the default model binder, but it may not be directly related depending on how you are doing things...
Have a look at the following: ASP.net MVC v2 - Debugging Model Binding Issues - BUG? ASP.net MVC v2 - Debugging Model Binding Issues - BUG?
精彩评论