Okay, lets say I have a URL like so, which is mapped via HTTP verb GET
to the controller action I have below:
GET /foo/bar?sort=asc&r=true
<
The model binder matches the parameters it gets from the view to the model you have in the action by the Names, so if they won't match the binding will not work.
options you got:
so basically, You can't do exactly what you want.
Update:
You wrote in a comment that the properties CAN match the parameters names, so instead of write custom attributes that maybe will succeeded to do the binding, just write a ViewModel (The VM fromMVC...) to adjust the url parameters names.
Writing custom model binder is not recommended by the MVC team:
In general, we recommend folks don’t write custom model binders because they’re difficult to get right and they’re rarely needed
from here
You could implement IModelBinder to map your incoming parameters to the object of your choosing provided the incoming parameter names are defined. Otherwise you would have to rely on parameter order and/or type to infer the proper binding which seems to be a very poor choice.
It's not supported out of the box, but you could do this:
class BarQuery : Bar {
public string sort { get { return SortOrder; } set { SortOrder = value; } }
public bool r { get { return Random; } set { Random = value; } }
}
public ActionResult FooBar(BarQuery bar) {
// Do something with bar
}
You could implement a custom IModelBinder
, but it's much easier to do manual mapping.
class FromQueryAttribute : CustomModelBinderAttribute, IModelBinder {
public string Name { get; set; }
public FromQueryAttribute() { }
public FromQueryAttribute(string name) {
this.Name = name;
}
public override IModelBinder GetModelBinder() {
return this;
}
public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext) {
return controllerContext.HttpContext.QueryString[this.Name ?? bindingContext.ModelName];
}
}
class Bar {
[FromQuery("sort")]
string SortOrder { get; set; }
[FromQuery("r")]
bool Random { get; set; }
}
public ActionResult FooBar(Bar bar) {
// Do something with bar
return null;
}
There is no free MVC.Net Modelbinding feature that gives you what you want out of the box. When I need to do something like this, it really makes me think about my modeling which almost always makes me create a ViewModel for my view binding and a EntityModel for my repository storage.
I like to use AutoMapper to convert between these different types. Best part of using AutoMapper is that it drives you away from having to write the mapping logic yourself over and over for each Action in your controller. Just set it up once with AutoMapper in your initialization sections and just execute something like this in the future.
Mapper.Map<Bar>(barViewModel);
I had the same problem a long time ago and used this stack solution by Andras Zoltan: Asp.Net MVC 2 - Bind a model's property to a different named value
I set the ModelBinder attribute on my class and the BindAlias on the property:
[ModelBinder(typeof(DefaultModelBinderEx))]
public class MyModel
{
[Required]
[BindAlias("new")]
public int? Amount { get; set; }
If you can't change or haven't access your model file to set the Attributes, you still can create a custom model binder, OR, make a specific object than you will map to your Model (AutoMapper is usefull)