How do I pass a Dictionary as a parameter to an ActionResult method from jQuery/Ajax?

actionresult, ajax, asp.net-mvc, jquery

Solution

At last I figured it out!! Thanks for the suggestions everyone! I finally figured out the best solution is to pass JSON via the Http Post and use a custom ModelBinder to convert the JSON to a Dictionary. One thing I did in my solution is created a JsonDictionary object that inherits from Dictionary so that I can attach the custom ModelBinder to the JsonDictionary type, and it wont cause any conflicts in the future if I use Dictionary as a ActionResult parameter later on for a different purpose than JSON.

Here's the final ActionResult method:

public ActionResult AddItems([Bind(Include="values")] JsonDictionary values)
{
    // do something
}

And the jQuery "$.post" call:

$.post("/Controller/AddItems",
{
    values: Sys.Serialization.JavaScriptSerializer.serialize(
            {
                id: 200,
                "name": "Chris"
            }
        )
},
function(data) { },
"json");

Then the JsonDictionaryModelBinder needs to be registered, I added this to the Application_Start method within the Global.asax.cs:

protected void Application_Start()
{
    ModelBinders.Binders.Add(typeof(JsonDictionary), new JsonDictionaryModelBinder());
}

And, finally here's the JsonDictionaryModelBinder object and JsonDictionary object I created:

public class JsonDictionary : Dictionary<string, object>
{
    public JsonDictionary() { }

    public void Add(JsonDictionary jsonDictionary)
    {
        if (jsonDictionary != null)
        {
            foreach (var k in jsonDictionary.Keys)
            {
                this.Add(k, jsonDictionary[k]);
            }
        }
    }
}

public class JsonDictionaryModelBinder : IModelBinder
{
    #region IModelBinder Members

    public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
    {
        if (bindingContext.Model == null) { bindingContext.Model = new JsonDictionary(); }
        var model = bindingContext.Model as JsonDictionary;

        if (bindingContext.ModelType == typeof(JsonDictionary))
        {
            // Deserialize each form/querystring item specified in the "includeProperties"
            // parameter that was passed to the "UpdateModel" method call

            // Check/Add Form Collection
            this.addRequestValues(
                model,
                controllerContext.RequestContext.HttpContext.Request.Form,
                controllerContext, bindingContext);

            // Check/Add QueryString Collection
            this.addRequestValues(
                model,
                controllerContext.RequestContext.HttpContext.Request.QueryString,
                controllerContext, bindingContext);
        }

        return model;
    }

    #endregion

    private void addRequestValues(JsonDictionary model, NameValueCollection nameValueCollection, ControllerContext controllerContext, ModelBindingContext bindingContext)
    {
        foreach (string key in nameValueCollection.Keys)
        {
            if (bindingContext.PropertyFilter(key))
            {
                var jsonText = nameValueCollection[key];
                var newModel = deserializeJson(jsonText);
                // Add the new JSON key/value pairs to the Model
                model.Add(newModel);
            }
        }
    }

    private JsonDictionary deserializeJson(string json)
    {
        // Must Reference "System.Web.Extensions" in order to use the JavaScriptSerializer
        var serializer = new System.Web.Script.Serialization.JavaScriptSerializer();
        return serializer.Deserialize<JsonDictionary>(json);
    }
}

Problem

I'm using jQuery to make an Ajax call using an Http Post in ASP.NET MVC. I would like to be able to pass a Dictionary of values. The closest thing I could think of was to pass in a multi-dimensional array of strings, but the result that actually gets passed to the ActionResult method is a single dimensional string array containing a string concatenation of the "key/value" pair. For instance the first item in the below "values" array contains the below value: ``` "id,200" ``` Here's an example of my ActionResult method: ``` public ActionResult AddItems(string[] values) { // do something } ``` Here's an example of how I'm calling the method from jQuery: ``` $.post("/Controller/AddItems", { values: [ ["id", "200"], ["FirstName", "Chris"], ["DynamicItem1", "Some Value"], ["DynamicItem2", "Some Other Value"] ] }, function(data) { }, "json"); ``` Does anyone know how to pass a Dictionary object from jQuery to the ActionResult method instead of an Array? I would really like to define my ActionResult like this: ``` public ActionResult AddItems(Dictionary<string, object> values) { // do something } ``` Any suggestions? UPDATE: I tried passing in a comma within the value and it basically just makes it impossible to actually parse the key/value pair using string parsing. Pass this: ``` values: [ ["id", "200,300"], ["FirstName", "Chris"] ] ``` results in this: ``` values[0] = "id,200,300"; values[1] = "FirstName,Chris"; ```

Original source