Reputation: 1686
So I have a action method that takes a fancy Cart
object:
[HttpPost]
public JsonResult BuildTransaction(Cart cart) { }
The Cart
model:
public class Cart
{
public Guid UserId { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public Address Address { get; set; }
}
I throw some JSON at the route, that looks like this:
object cart = new {
UserId = uid,
FirstName = "John",
LastName = "Travlota",
Address = new {
Line1 = "Ramsdean Grange",
Town = "boom town",
PostCode = "dd7 7sx"
}
};
var request = client.PostAsJsonAsync("BuildTransaction", cart);
The result, I have a cart of type Cart to play with in my controller. Fantastic!
My question is, how does .NET do this mapping? I imagine its someplace in the OnActionExecute
but what/how does it do this.
If I wanted to mimic this functionality, what would I do? Do I really need an external tool like AutoMapper if MVC seems perfectly capable of doing it without it?
Upvotes: 2
Views: 406
Reputation: 3176
This is Mvc Model Binding. MVC has a set of a default model binders. It uses the DefaultModelBinder
object as default for your post requests, but it also have the 3 following objects registered by default.
HttpPostedFiledModelBinder
ByteArrayModelBinder
LinqBinaryModelBinder
You can also create your own binders and associate them to a parameter with an attribute on a parameter as @Mansfield pointed out. But you can also register them globally for a specific type as follow (In Application_Start
for example)
//Register FooModelBinder for all posted objects that are of type Foo
ModelBinders.Binders.Add(typeof(Foo),new FooModelBinder());
And if for some reason you want to reinvent the wheel you can also change de DefaultModelBinder
ModelBinders.Binders.DefaultBinder = new CustomDefaultModelBinder();
Here's a very simple implemention of a ModelBinder for Foo type
public class FooModelBinder: IModelBinder
{
#region IModelBinder Members
public object BindModel(ControllerContext controllerContext,ModelBindingContext bindingContext) {
IUnvalidatedValueProvider provider = (IUnvalidatedValueProvider)bindingContext.ValueProvider;
return new Foo {
Bar = provider.GetValue("Bar", true).AttemptedValue,
Banana= provider.GetValue("Banana", true).AttemptedValue
};
}
#endregion
}
Upvotes: 1
Reputation: 16646
The ASP.NET MVC model binder is what does this translation of request parameter to class instances. This great piece of functionality operates based on conventions, so as long as you follow default conventions (which means that your request parameters need to have the same name as the names of the properties of your class). So yes, in most cases the default model binder behavior is fine and you don't need a library like AutoMapper.
If you want to know more about when model binding occurs, this article goes into the MVC pipeline in great detail. If you just want to know more about model binding, I found this two page tutorial a great help: part 1 and part 2.
Upvotes: 0
Reputation: 3105
First MVC receives a post (for example) which contains your html input
values and the name
associated with each of them.
Then it checks the properties in the expected object (the model type) and tries to find a name
which matches in the form received, and so on.
It all happens in the ModelBinder
, you can even change the way it is done since this is an extension point.
So this is for the how, and about using AutoMapper, you don't need it here.
Upvotes: 1
Reputation: 15170
This is done by the Model Binder. (System.Web.Mvc.DefaultModelBinder
)
You can implement a custom model binder like so:
Controller:
public ActionResult Create([ModelBinder(typeof(CreateModelBinder))] CreateViewModel vModel)
{
}
Model Binder:
public class CreateModelBinder : DefaultModelBinder
{
public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
{
//assign request parameters here, and return a CreateViewModel
//for example
CreateViewModel cVM = new CreateViewModel();
cVM.Name = controllerContext.HttpContext.Request.Params["Name"];
return cVM;
}
}
More info: http://www.dotnetcurry.com/ShowArticle.aspx?ID=584 https://stackoverflow.com/a/1249602/1324019
Upvotes: 1