views:

401

answers:

2

I have a custom model binder that takes a comma separated list and cleans out any empty values, then passes it along to the default model binder. This worked in ASP.NET MVC Preview 2, but when I upgraded to RC2, the below won't compile because the interface of ValueProvider only has a GetValue() method, no [] accessor. Is what I'm doing below possible through some other mechanism in the binding context? I'd rather not have to create a full blown model binder for such a simple situation. The main goal is when the values are bound to a List<SomeEnum>, any empty values are skipped.

public class EnumListModelBinder : IModelBinder
{
    public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
    {
        var result = bindingContext.ValueProvider[bindingContext.ModelName];
        string[] rawValues = (string[])result.RawValue;
        var newValues = new List<string>();
        foreach (string value in rawValues)
        {
            if (!String.IsNullOrEmpty(value))
            {
                newValues.Add(value);
            }
        }

        string newValuesAttempted = String.Join(",", newValues.ToArray());
        // overwrite the ValueProviderResult with the cleaned up csv list
        // this is the part I'm not sure how to implement using the interface
        bindingContext.ValueProvider[bindingContext.ModelName] = 
           new ValueProviderResult(newValues.ToArray(), newValuesAttempted, result.Culture);

        return System.Web.Mvc.ModelBinders.Binders.DefaultBinder.BindModel(controllerContext, bindingContext);
    }
}
A: 

What, exactly, is wrong with using GetValue() instead of [] here? It does the same thing. But ValueProvider is an interface now, and interfaces can't have indexers. Hence, GetValue().

Change your code to:

var result = bindingContext.ValueProvider.GetValue(bindingContext.ModelName);

I'm a little surprised that the cast on the next line ever worked, though. Seems highly dependent on what the user actually submits and what the particular property type is. That's unrelated to your question, though.

Craig Stuntz
That's not the part that the change to the interface doesn't allow me to do. It's 2nd to last line where I overwrite the result in the ValueProvider collection
jayrdub
As far as the cast, I only use this model binder for properties that I know the form data will comply
jayrdub
You would need to update the *specific source* of the value (e.g., controllerContext.HttpContext.Request.QueryString[something].
Craig Stuntz
I get a NotSupportedException "Collection is read-only" when I try to update the Request collections
jayrdub
Then you'll have to give in and use the model binder the way it was intended: Return a bound value instead of fiddling with the collection and calling `base`.
Craig Stuntz
A: 

There wasn't much of a solution here now that the ValueProvider collection is readonly. Instead I ended up using a custom model binder

http://stackoverflow.com/questions/2337374/is-there-a-way-to-have-the-defaultmodelbinder-ignore-empty-items-when-binding-to

jayrdub