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

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


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);    }}


This is what I tried. Saves a lot of work.Javascript:

  var dict = {};               dict["id"] = "200";        dict["FirstName"] = "Chris";        dict["DynamicItem1"] = "Some Value";        dict["DynamicItem2"] = "Some Other Value";        var theObject = {};        theObject.dict = dict;        $.post(URL, theObject, function (data, textStatus, XMLHttpRequest) {            console.log("success");        }, "json");

Action Method:

public ActionResult MethodName(DictionaryModel obj)    {       //Action method logic    }public class DictionaryModel{    public Dictionary<string, string> dict { get; set; }}


It's possible with custom model binders or filters. Behind the scenes - you will have to do it manually anyway (Request.Form, parse strings, create dictionary tralala), but at least - your controller will be clean and code will be reusable for another actions.