tags:

views:

180

answers:

2

I have a custom model binding:

using System.Web.Mvc;
using MyProject.Model;

namespace MyProject.ModelBinders
{
    public class VersionedIdModelBinder : IModelBinder
    {
        public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
        {
            //Not completely happy with this.  What if the parameter was named something besides id?
            return VersionedId.Parse(bindingContext.ValueProvider["id"].RawValue.ToString());
        }
    }
}

which works as long as the id is passed in the url (either explicitly or via a route definition.) However, if the Id is passed in a form as a hidden input field:

<input type="hidden" id="id" name="id" value="12a" />

Then ValueProvider["id"].RawValue is a string array, so the code below doesn't behave as expected.

In the controller code, I expect to simply be able to do:

public ActionResult MyAction(VersionedId id)
{
 ...
}

Two questions:

  1. I am surprised that passing the id via form post causes the RawValue to be a string array. Is this the expected behavior, and is the "standard" way to handle this to check the type of the RawValue? I need to be able to handle both form posts and url routes.
  2. Is it normal to check for the Name of the parameter in the model binder, or is there another way to do this whereby the controller action can use whatever parameter name it likes?
A: 

You could directly access

controllerContext.HttpContext.Request["id"]

and get the value from there. Should be a simple string in that case.

Lck
+1  A: 

Regarding your question 1, there is some interesting discussion posted Custom ModelBinder and Release Candidate.

The RawValue property is what is consumed by the ConvertTo() method, while the AttemptedValue property is what is consumed by the validation system to provide an error message. To see an example of this, break into one of your action methods and inspect the Controller.ValueProvider entries. Some of the RawValue entries will be strings (like those from Routing), some of them will be string arrays (like those from QueryString or Form), etc. The reason for the differentiation between RawValue and AttemptedValue is that RawValue supports passing array types to the ConvertTo() method. We can't convert to a multi-element array from a single AttemptedValue, but we can convert to a multi-element array from a RawValue that is itself an array. This supports the infrastructure to allow binding to collection types.

I agree about the unfortunate naming, though unfortunately this isn't likely to change. :(

J.W.