There is a lot on conversation going on about binding complex JavaScript objects to ASP.NET MVC actions. Complex objects are objects that have sub objects and/or arrays.
Let’s assume the following complex model:
![Complex Model Complex Model](http://69.89.31.214/~nickrigg/wp-content/uploads/2009/08/ClassDiagram1.png)
I have a Person object with some properties, an array of phone numbers and an Address object. I would like to pass a JavaScript representation of this object to our Controller’s Create action:
1 | [AcceptVerbs(HttpVerbs.Post)] |
2 | public ActionResult Create(Person person) |
4 | //Code to add the person goes here |
On the client, the JavaScript representation of a Person would be:
06 | Street: "2780 Somewhere Far" , |
One way to send this object to our Controller is to “stringify” the object into a JSON string using a plugin like toJSON. However, this requires us to change the Action to accept a string instead of a typed parameter, and then deserialize the string using the JavaScriptSerializer. I can get around this by automating the deserialization with a custom ActionFilterAttribute or ModelBinder. But, what if I want to use the built-in DefaultModelBinder functionality?
The default model binding in ASP.NET MVC works based on form post data. For example, if I were going to post a simple version of Person and have ASP.NET MVC map it to our action’s person parameter, I could post:
ASP.NET MVC does a good job of recognizing this post data as being a Person and mapping it as such. On top of that, it has its own simple yet powerful syntax for representing more complex objects, such as this:
4 | person.PhoneNumbers[0]: 205-555-5634 |
5 | person.PhoneNumbers[1]: 205-555-5634 |
6 | person.PhoneNumbers[2]: 205-555-5634 |
7 | person.Address.Street: 2780 Somewhere Far |
8 | person.Address.City: Birmingham |
9 | person.Address.State: AL |
So, instead of stringifying my JavaScript objects, I will postify them! (I made the word postify™ up, it’s mine now). My custom postify plug-in will do the work. Here is the source code:
01 | $.postify = function (value) { |
04 | var buildResult = function (object, prefix) { |
05 | for ( var key in object) { |
07 | var postKey = isFinite(key) |
08 | ? (prefix != "" ? prefix : "" ) + "[" + key + "]" |
09 | : (prefix != "" ? prefix + "." : "" ) + key; |
11 | switch ( typeof (object[key])) { |
12 | case "number" : case "string" : case "boolean" : |
13 | result[postKey] = object[key]; |
17 | if (object[key].toUTCString) |
18 | result[postKey] = object[key].toUTCString().replace( "UTC" , "GMT" ); |
20 | buildResult(object[key], postKey != "" ? postKey : key); |
26 | buildResult(value, "" ); |
This is the first cut of the plug-in, and I’m sure it’s missing something – I’ll update the source code as I make updates. That said, the plug-in greatly simplifies posting complex objects to ASP.NET MVC controllers. Here is a sample in jQuery that posts myPerson:
4 | data: $.postify(myPerson) |
That’s it! The plugin will handle formatting the data in an ASP.NET MVC post-friendly manner. On the server side, the parameter inflates nicely using the default model binder:
![Inflated-Person Inflated-Person](http://69.89.31.214/~nickrigg/wp-content/uploads/2009/08/Inflated-Person.png)
If you need to post to an action that takes multiple parameters, the complex object must be prefixed with the name of the parameter – in our case, Person. To include another parameter, use this syntax:
3 | url: "/JSON/DoSomething" , |