Posting JSON Data to an MVC Controller via Ajax
Form posts are a thing of the past. Most new interactive HTML5-Web 2.0-buzzword web apps are trending towards a one-page UI with Ajax requests used to pull and push data dynamically.
So if you are doing a cool new web app that does not use any form posts, why would you make your Ajax posts form-encoded? Building a form-encoded string is messy, you have to worry about escaping characters, they are confusing when it comes to dealing with things like arrays and complex types, and they also make a mess on the controller if you are passing in a lot of parameters.
A simple solution to this problem is to use a stringified JSON object posted to your controller.
Here’s a small sample application that illustrates how the form-encoded posts vs. JSON posts work. I called them “BadSave” and “GoodSave” to prove my point, but there really aren’t bad ways to code something if it solves your problem. The “GoodSave” way is just a bit cleaner code and is easier to maintain, IMO. You can download the sample app from https://github.com/HaymarketDev/Sandbox/tree/master/MVCJsonPost and follow along.
So here’s our app: it’s just a simple form where you enter your first and last name, and then use a multiselect dropdown to pick your favorite bands. It really shouldn’t be a multiselect since there is clearly only one right answer, but we are making it that way for this sample’s sake.
Go ahead and enter your First and Last name, and select your favorite bands:
Now set a break point on the PersonController on both the BadSave and the GoodSave actions and click the Bad Submit and Good Submit buttons in the UI.
The BadSave takes in one parameter for each element posted. I honestly haven’t figured out how to get the “List favoriteBands” parameter to work correctly since I’m not exactly sure how to form encode an array (in fact, that is the precise reason I’m writing this post). Note how it’s putting my array items as a comma-separated list on the first element on the “List”, which is incorrect.
The GoodSave, on the other hand, just takes in an instance of a PersonModel. Note how the “List FavoriteBands” from the model gets mapped correctly.
Server-side PersonModel for reference:
On the client side, the difference is simple. Here’s the BadSave post with the form-encoded string in the data field:
And the GoodSave post:
Just remember to set the contentType to “application/json” on your request. Note that the JSON.stringify() function is natively supported in most modern browsers but you may have to include the json2.js library to ensure backwards compatibility.
Client-side PersonModel for reference:
Note: If you want to post a Knockout.js view model, you will have to serialize your view model as “ko.toJSON(myViewModel)” instead of “JSON.stringify(request)”.