mklein
mklein

Reputation: 1807

ASP.NET MVC 3 Binding nested properties

I've implemented the model binder shown below. Everything is working as expected only that nested properties are not bound:

I'm using MEF to get the data store into the binder. Should the binding for the nested property name work, or am I missing the point? Is calling base.BindModel(...) the right way to go?

[Export(typeof(OrderModelBinder))] public class OrderModelBinder : DefaultModelBinder
{        
    private readonly IProjectEntities _data;
    private const string _orderSessionKey = "OrderSessionKey";

    [ImportingConstructor]
    public OrderModelBinder([Import]IProjectEntities data)
    {
        _data = data;
    }

    public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
    {
        Order order = (Order)controllerContext.HttpContext.Session[_orderSessionKey];
        if (order == null)
        {
            order = new Order();
            order.Customer = new Customer();
            controllerContext.HttpContext.Session[_orderSessionKey] = order;

            _data.Orders.AddObject(order);                
        }

        bindingContext.ModelMetadata.Model = order;
        return base.BindModel(controllerContext, bindingContext);
    }
}

This is the controller where the post lands:

[HttpPost]
public ActionResult ShipmentDetails(Order order)
{
    // do stuff here
}

This is a part of the razor view with the form:

@using(Html.BeginForm()) 
{    
    @Html.ValidationSummary()    
    <table class="formTable">
        <tbody>
        ...
        <tr>
            <td class="formTableLabel">@Html.LabelFor(model => model.Order.Customer.Name)</td>
            <td>@Html.TextBoxFor(model => model.Order.Customer.Name, new { @class = "formTableLong" })</td>
            <td>@Html.ValidationMessageFor(model => model.Order.Customer.Name)</td>
        </tr>
        ...
        <input type="submit" value="Go on." />

Upvotes: 0

Views: 4972

Answers (2)

mklein
mklein

Reputation: 1807

I solved the problem in my special case. The model binder was not the problem. The problem was that the the actual model class was annotated like this which then correctly (but unwanted) excluded Customer (the nested object) from the binding process:

[MetadataType(typeof(OrderMetatdata))]
[Bind(Include = "EventDate, PaymentProcessor")]
partial class Order
{
    ...

Fixed Version is this:

[MetadataType(typeof(OrderMetatdata))]
[Bind(Include = "EventDate, PaymentProcessor, Customer")]
partial class Order
{
    ...

If you have any problems with databinding I recommend to check any Annotations on your model classes that might be wrong as they were in my case.

Upvotes: 2

Pradeep
Pradeep

Reputation: 3276

@Html.TextBoxFor(model => model.Order.Customer.Name, new { @class = "formTableLong" })

This is the right way if you have nested properties. Try removing your custom model binder and then see if it works. Suggesting this because that's the only alien piece of code for me.

Upvotes: 0

Related Questions