1

Lets say I have a a form that can have new text inputs created in JavaScript at runtime. And I want to bind the values to a NameValueCollection (or a Dictionary). Does ASP.NET MVC3 natively allow this?

In other words, how do I get this to work?

Assuming this is the HTML form...

<!-- if someone posted this form -->
<form action="MyExample">
    <input type="hidden" name="id" value="123" />
    <input type="text" name="things.abc" value="blah" />
    <input type="text" name="things.def" value="happy" />
    <input type="text" name="things.ghi" value="pelicans" />
    <input type="submit" />
</form>

... and this is is the "Action" in the Controller ...

public ActionResult MyExample(int id, NameValueCollection things)
{
    // At this point, `things["abc"]` should equal `"blah"`
    return Content(string.Format("Things has {0} values.", things.Count));
}

Do I need to make my own custom model binder? Or am I just naming the input boxes incorrectly?

2
  • I've never found a great solution for this using default model binding. Custom model binder might work but I haven't tried. For me it's easier (dirtier, yes) to just get at Request.Form values.. Commented Feb 2, 2012 at 15:25
  • Request.Form would be easy... not really good for TDD :) - I'm architecting a project, and one of the requirements I've set out is that no MVC developers can access "Session", "Request", "Cookies", etc (directly). Commented Feb 2, 2012 at 15:28

1 Answer 1

1

I don't think the default ASP.NET MVC3 model binder does this, so I've made the following helper class. It works, I just didn't want to make this if the DefaultModelBinder handles this already.

I won't mark this as the answer for a while in hopes that someone will tell me how to get this to work correctly without a custom class. But for those of you who have the same need, here's the code.

Global.asax.cs

// Add this line in the Application_Start() method in the Global.asax.cs
ModelBinders.Binders.DefaultBinder = new NameValueAwareModelBinder();

Custom model binder

using System.Collections.Specialized;
using System.Web.Mvc;

namespace Lil_Timmys_Example.Helpers
{
    public class NameValueAwareModelBinder : DefaultModelBinder
    {
        public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
        {
            if (bindingContext.ModelMetadata.ModelType == typeof(NameValueCollection))
            {
                var result = new NameValueCollection();

                string prefix = bindingContext.ModelName + ".";

                var queryString = controllerContext.HttpContext.Request.QueryString;
                foreach (var key in queryString.AllKeys)
                {
                    if (key.StartsWith(prefix))
                    {
                        result[key.Substring(prefix.Length)] = queryString.Get(key);
                    }
                }

                var form = controllerContext.HttpContext.Request.Form;
                foreach (var key in form.AllKeys)
                {
                    if (key.StartsWith(prefix))
                    {
                        result[key.Substring(prefix.Length)] = form.Get(key);
                    }
                }

                return result;
            }
            else
            {
                return base.BindModel(controllerContext, bindingContext);
            }
        }
    }
}
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.