MVC 3 custom ModelBinder not being used

1.7k views Asked by At

I have a form that posts a bunch of hidden variables, some with the same name. Here's the post body:

OfferId=3802&DeliveryDate=11%2F02%2F2011&DeliveryTime=12%3A00&location=1&location=698

It posts it to an MVC action:

[HttpPost]
public ActionResult DeliveryOptions(DeliveryOptions model)
{
    ...
}

The DeliveryOptions model looks like this:

public class DeliveryOptions
{
    public long? OfferId { get; set; }

    [CustomValidation(typeof(CustomValidator), "IsDeliveryDateValid")]
    public DateTime? DeliveryDate { get; set; }

    public DateTime? DeliveryTime { get; set; }

    [CustomValidation(typeof(CustomValidator), "IsLocationsValid")]
    public OfferLocations Locations { get; set; }
}

Now, I would like to parse the posted location variables into the OfferLocations object, which looks like this:

[ModelBinder(typeof(OfferLocationsModelBinder))]
public class OfferLocations
{
    [Required]
    public int[] LocationIds { get; set; }
}

The model binder currently looks like this:

public class OfferLocationsModelBinder : IModelBinder
{
    public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
    {
        throw new NotImplementedException();
    }
}

The problem is, I cannot break on the NotImplementedException. The model binder does not execute. I've probably missed something obvious; any ideas?

3

There are 3 answers

0
Edgar On BEST ANSWER

Couldn't get this to work. Had to implement a workaround.

I'm now posting the location IDs as a CSV string, and they are being picked up by the custom model binder, so can be parsed into the array. Shame I couldn't do it the other way.

1
Artiom Chilaru On

Try to inherit your Model Binder from the System.Web.Mvc.DefaultModelBinder, and override the object BindModel(ControllerContext, ModelBindingContext) method. See if this works. If it does - you can work from there :)

This is what I'm doing right now. Basically, I had to make sure that if a specific type comes in the request - a method is executed against this value. The model binder registration code is exactly the same - an attribute applied to the property's class.

The model binder is as follows:

public class TableModelBinder : DefaultModelBinder
{
    public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
    {
        var result = base.BindModel(controllerContext, bindingContext) as ITableModel;
        if (result != null)
            result.UpdateSorter();
        return result;
    }
}

P.S. Deriving from the base model binder gives me the additional benefit of binding all the properties using the standard Mvc code, and I can then extend the deserialized object :)

Hope this helps

1
neontapir On

Is that ModelBinder registered with the DepedencyResolver? I wonder if MVC is having trouble finding your ModelBinder and is falling back on the default one.