Problem
Given a form I've created for my web site users, how do I submit the data to a controller action using jQuery?
Solution
Depending on the type of data and even the type of client you are working with there can be a number of ways to deal with sending the data to a controller action. ASP.NET MVC continues to evolve in this area and make data submission friendly to the developer.
Using Form-URLEncoded values
When we do a request via POST the server sees the values we pass in as
form-urlencoded content. This is perfect for most scenarios in ASP.NET MVC, as the framework provides built in mechanisms for model binding and validation.
A Simple Example
Let's look at the simplest of scenarios, passing in just one value.
Try Me!Here, we're anticipating a single string as input from the user. To send this information from the client to the action, we'll use a bit of jQuery to add an event handler to our button click. In the handler we'll capture the name that was entered and then send the data by calling
$.post().
// jQuery's doc ready handler
$(function () {
$("#submit-name").button().click(function () {
var nameEntered = $("#your-name").val()
$.post(
'<%= Url.Action("SimplePost") %>',
{ submittedName: nameEntered },
handleSuccess
);
});
});
function handleSuccess(content) {
$("#name-input").html(content);
$("#name-input").addClass("easy-notification");
}
The data that is posted is packed into a data map where we specify that the parameter
submittedName will have the value
nameEntered, which was pulled from the form value.
Capturing this data in our controller is as simple as writing a method that accepts a single parameter. This parameter must be the same as the parameter name we used in our data map,
submittedName.
[HttpPost]
public ContentResult SimplePost(string submittedName)
{
string result = string.Format("See how easy that was, {0}!?", submittedName);
return new ContentResult { Content = result };
}
Sending A List of Data
There are obviously more interesting sets of data that our users will work with. Let's consider the example of sorting some data using jQuery UI and extracting the result.
Try Me!Here the user is asked to drag and drop the list into the order they prefer. This list uses the jQuery UI library's
sortable plugin to give us drag-and-drop support for a simple unordered list. The sortable plugin also provides a way to extract the element IDs from the list using the
toArray method. Our script to prepare the data will look as follows:
// submit the data from our sorted list
function postSortOrder() {
$.ajax({
data: { orderedHeroIds: $("#hero-list").sortable('toArray') },
type: 'POST',
traditional: true,
success: updateMessage
});
}
We would call the above
postSortOrder() method in the click handler of a button on our page. Here, we are still doing a
POST, but we have to use the
$.ajax() method for a little more control over the array serialization. Namely, we are setting the
traditional property to true so that the array is encoded in a format that works with the MVC framework. Finally, we call
updateMessage, which is a function that will use the returned value to update the client.
Folks, here is were the MVC Framework really shines. Take a look at the important parts of our controller action:
[HttpPost]
public ContentResult SortedList(List<int> orderedHeroIds)
{
foreach (var heroId in orderedHeroIds)
{
// do something interesting with the new order
// (update db, etc)
}
// build our result
// ...
return result;
}
As you can see, we can create our signature with a generic list of
int as a parameter. The serialized list of ids that we posted to the controller is converted to
List<int> by the MVC framework.
Now that you see how it's done, why not give it one more try?
Try Me!Submitting a Form
Let's have a look at another set up where we implement a form on the page. Here we want to submit the request and process the response with jQuery. In the following code
create-hero is the ID of the form element on the page. We intercept the submit event and then stop the default post from firing by calling
preventDefault().
$(function () {
$("#create-hero").submit(function (event) {
// url-encode the form data
var formData = $(this).serialize();
// post the data to the controller
$.post(
'<%= Url.Action("Index") %>',
formData,
processResult // our success callback
);
event.preventDefault();
});
});

Calling
.serialize() transforms our form values to the form-urlencoded values required to send the data to the controller, resulting in the string
FullName=Lazino&Power=procrastination.
Try Me!To handle this in our action we work much the same way as we have so far: specify the type of object we want to accept and allow the MVC framework to take care of the mapping. We can then manipulate the data in whatever way we need to and save it to our database.
[HttpPost]
public ActionResult Index(SuperHero newHero)
{
// add the hero to the database, example:
// heroRepository.AddHero(newHero)
// heroRepository.Save()
return PartialView("HeroAdded", newHero);
}
Posting using JSON
But what if we're working with a front end that is trying to send us JSON-formatted data? There are a number of issues that surface right away. Before we get to the solution, I want to walk through the pitfalls and see where the complications arise.

Here is a form that has a number of fields on it. Let's assume there is some driver (perhaps alternate intefaces) that requires us to POST new recipes as JSON data.
Only recently have the leading browsers started implementing a native method for converting objects to JSON data. This has lead to a number of plugins and scripts that have surfaced with varying implementations.
JSON.org has provided a library,
json2.js, that allows for these native implementations to execute if the
toJSON() method exists in the browser; otherwise it will transform our object for us internally using the
JSON.stringify() method.
Now that we have a way to convert the data to JSON, we need to next deal with the fact that JSON encoded data is stored in a string. If we do a standard
$.post(...) the server interprets the data as
application/x-www-form-urlencoded. If the data is serialized as JSON and passed in as the data parameter for the post there will be just one form value: the string of JSON data.
To see the implications here, let's look at the JavaScript version of an object designed to store recipes for sweets which, by name, matches a corresponding class defined in our code base. The client-side object is defined as such:
function CookieRecipe() {
this.Name = "";
this.Description = "";
this.PrepTimeMinutes = 0;
this.BakingTimeMinutes = 0;
this.Servings = 0;
}
When the user completes entry on the page, they click a button to send the recipe information to our controller action. The jQuery handler for the event is defined as follows:
$("#create-recipe").click(function () {
var myRecipe = new CookieRecipe();
myRecipe.Name = $("#Name").val();
myRecipe.Description = $("#Description").val();
myRecipe.PrepTimeMinutes = $("#PrepTimeMinutes").val();
myRecipe.BakingTimeMinutes = $("#BakingTimeMinutes").val();
myRecipe.Servings = $("#Servings").val();
var postData = JSON.stringify(myRecipe);
$.post('<%= Url.Action("SaveRecipeModel") %>', postData, recipeSuccess);
});
The data is entered in the form, stored in our object, converted to JSON and sent to our controller action. Now, we're getting somewhere...or are we?
We might take the next step of defining a controller action with a signature similar to the following:
[HttpPost]
public ActionResult SaveRecipe(CookieRecipe recipe)
{
// ...
}
Unfortunately this approach will not work out-of the box, and this is where the single-string, form-urlencoded data has kicked us in the proverbial rear-end: we've lost the MVC framework's model binding! The
recipe parameter will be
null.
But we do have the string...let's not forget that we can modify the signature of that method and get the form values out of the request. We can then use the
JavaScriptSerializer object to convert the string to our desired object type. The updated method might look like this:
[HttpPost]
public ActionResult SaveRecipe(FormCollection form)
{
JavaScriptSerializer js = new JavaScriptSerializer();
var recipe = js.Deserialize<CookieRecipe>(form[0]);
// do some processing...
// ...
return PartialView(recipe);
}
Again, you might think we're flying, but we've lost another important aspect of what the MVC framework has to offer: model validataion. If the user has entered invalid data we don't know until the binding fails. Rather than getting a graceful error message on the client, we get an exception on the server and the controller action bails out.
Thankfully a number of folks have been working through this.
Phil Haack posted a
blog entry on how to sort through the above problems by using a custom value provider, something you could do on your own, but is now available through the ASP.NET MVC futures library.
To get started, you need to download the ASP.NET MVC futures library (
available here) and reference the DLL in your project. Next, modify your Global.asax file's
Application_Start() method to register the
JsonValueProviderFactory:
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
RegisterRoutes(RouteTable.Routes);
ValueProviderFactories.Factories.Add(new JsonValueProviderFactory());
}
Finally, we need to revist our code that performs the POST to our controller. The
JsonValueProvider will look for requests that are sent with a content type of
application/json so we can't use the default
$.post() method. We'll update our code to make the call through
$.ajax() and specify our
contentType explicitly.
$.ajax({
url: '<%= Url.Action("SaveRecipe") %>',
type: 'POST',
data: postData,
contentType: 'application/json; charset=utf-8',
success: recipeSuccess
});
Now, back on our controller, we can update our action to accept the model type we originally had hoped for. The updated action is closer to our first version, except that now the
application/json content type tells the MVC framework to use our new value provider. Our object is correctly populated and we can implement the method much like any other action:
[HttpPost]
public ActionResult SaveRecipe(CookieRecipe recipe)
{
// save the recipe in the database, ex.
// recipeRepository.AddRecipe(recipe);
// recipeRepository.Save();
return PartialView(recipe);
}
Try Me!Let's quickly recap the above steps to send JSON data to the controller:
- Download the json2 library for JSON serialization on the client
- Download the MVC futures library to use the JSON value provider
- Modify Global.asax's
ApplicationStart to register the factory - Use
$.ajax() to make the request with the proper content type
Wrapping Up
As you can see, posting different kinds of data with jQuery can be quite straightforward. With powerful helpers, plugins and freely available libraries, data from your pages can easily be interpretted by the MVC framework. JSON-style posting still requires a bit of setup, but support through the futures library provides a good, streamlined approach to model binding the data in our controller actions.
About the Author
James Chambers is a Senior Software Developer in Canada, where he has the local record for the 100m dash with snow shoes (currenly posting a 48.94s time). His development passions are fueled by new tech, new tools and mentoring others. Follow his coding adventures at
Mister James.