I have the following controller action:
[HttpPost]
public ViewResult DoSomething(MyModel model)
{
// do something
return View();
}
Where MyModel
looks like this:
public class MyModel
{
public string PropertyA {get; set;}
public IList<int> PropertyB {get; set;}
}
So DefaultModelBinder should bind this without a problem. The only thing is that I want to use special/custom binder for binding PropertyB
and I also want to reuse this binder. So I thought that solution would be to put a ModelBinder attribute before the PropertyB which of course doesn't work (ModelBinder attribute is not allowed on a properties). I see two solutions:
To use action parameters on every single property instead of the whole model (which I wouldn't prefer as the model has a lot of properties) like this:
public ViewResult DoSomething(string propertyA, [ModelBinder(typeof(MyModelBinder))] propertyB)
To create a new type lets say
MyCustomType: List<int>
and register model binder for this type (this is an option)Maybe to create a binder for MyModel, override
BindProperty
and if the property is"PropertyB"
bind the property with my custom binder. Is this possible?
Is there any other solution?
It has been 6 years since this question was asked, I would rather take this space to summarize the update, instead of providing a brand new solution. At the time of writing, MVC 5 has been around for quite a while, and ASP.NET Core has just come out.
I followed the approach examined in the post written by Vijaya Anand (btw, thanks to Vijaya): http://www.prideparrot.com/blog/archive/2012/6/customizing_property_binding_through_attributes. And one thing worth noting is that, the data binding logic is placed in the custom attribute class, which is the BindProperty method of the StringArrayPropertyBindAttribute class in Vijaya Anand's example.
However, in all the other articles on this topic that I have read (including @jonathanconway's solution), custom attribute class is only a step stone that leads the framework to find out the correct custom model binder to apply; and the binding logic is placed in that custom model binder, which is usually an IModelBinder object.
The 1st approach is simpler to me. There may be some shortcomings of the 1st approach, that I haven't known yet, though, coz I am pretty new to MVC framework at the moment.
In addition, I found that the ExtendedModelBinder class in Vijaya Anand's example is unnecessary in MVC 5. It seems that the DefaultModelBinder class which comes with MVC 5 is smart enough to cooperate with custom model binding attributes.
@jonathanconway's answer is great, but I would like to add a minor detail.
It's probably better to override the
GetPropertyValue
method instead ofBindProperty
in order to give the validation mechanism of theDefaultBinder
a chance to work.That's a good solution, though instead of checking "is PropertyB" you better check for your own custom attributes that define property-level binders, like
You can see an example of BindProperty override here.
I actually like your third solution, only, I would make it a generic solution for all ModelBinders, by putting it in a custom binder that inherits from
DefaultModelBinder
and is configured to be the default model binder for your MVC application.Then you would make this new
DefaultModelBinder
automatically bind any property that is decorated with aPropertyBinder
attribute, using the type supplied in the parameter.I got the idea from this excellent article: http://aboutcode.net/2011/03/12/mvc-property-binder.html.
I'll also show you my take on the solution:
My
DefaultModelBinder
:My
IPropertyBinder
interface:My
PropertyBinderAttribute
:An example of a property binder:
Example of the above property binder being used: