Improved JavaScript Model Binding in ASP.NET MVC 3 Preview 1
Posted by: Malcolm Sheridan ,
on 10/8/2010,
in
Category ASP.NET MVC
Abstract: A new addition to ASP.NET MVC 3 Preview 1 has been the improvement in model binding JSON data posted to an action through an Ajax form post. This makes it simple to post JSON data to any action method. Sometimes in ASP.NET MVC 2 this was difficult to do, but not anymore.
A new addition to ASP.NET MVC 3 Preview 1 has been the improvement in model binding JSON data posted to an action through an Ajax form post. This makes it simple to post JSON data to any action method. Sometimes in ASP.NET MVC 2 this was difficult to do, but not anymore. Instead of me talking about it, let's jump into an example to show you how the improvement works. To see this in action, you'll need to download ASP.NET MVC 3 Preview 1 which can be found here. For beta software, I always recommend installing this on a virtual machine, just in case something goes wrong.
Open Visual Studio 2010 and create a new ASP.NET MVC 3 Web Application (Razor) project. I've got a simple class that is going to be the model and it is an Order. Here's the properties of this class:
public class Order
{
public int Id { get; set; }
public string GivenName { get; set; }
public string Surname { get; set; }
public string Address { get; set; }
public DateTime DateOrdered { get; set; }
public int Quantity { get; set; }
public static List<Order> GetOrders()
{
return new List<Order>
{
new Order { Id = 1, GivenName = "John", Surname = "Smith", Address = "100 Tom Street", DateOrdered = DateTime.Now.AddDays(-2), Quantity = 3 },
new Order { Id = 2, GivenName = "Steve", Surname = "Hello", Address = "777 Hello Lane", DateOrdered = DateTime.Now.AddDays(-7), Quantity = 15 },
new Order { Id = 3, GivenName = "Kevin", Surname = "Rudd", Address = "666 Lane", DateOrdered = DateTime.Now.AddDays(12), Quantity = 8 }
};
}
}
There's a static method called GetOrders that returns a list of orders. Nothing special yet. The next step is to create a form that allows the user to edit the data then post it to the server. Here it is:
<form method="post" action="/Order/Edit">
<fieldset>
<legend>Fields</legend>
@Html.EditorForModel();
<p>
<input type="submit" value="Save" />
</p>
</fieldset>
</form>
I'm making full use of the built-in EditorTemplates in MVC 2. To make this application really slick, when the user hits the submit button, I want to do something called Form Hijacking. This is a process of making an Ajax request perform the HTTP post, thus eliminating the need for a full page refresh. Here's the JavaScript:
$(function () {
$("form:first").submit(function (e) {
e.preventDefault();
var order = {
Id: $("#Id").val(),
GivenName: $("#GivenName").val(),
Surname: $("#Surname").val(),
Address: $("#Address").val(),
DateOrdered: $("#DateOrdered").val(),
Quantity: $("#Quantity").val()
};
$.ajax({
url: $(this).attr("action"),
type: "POST",
data: JSON.stringify(order),
dataType: "json",
contentType: "application/json; charset=utf-8",
success: function (data) {
}
});
});
});
In the code above I'm creating an object literal and passing that as the data to the Ajax request. All looks good until you run the code. If you put a breakpoint on the Edit/Action method, you'll notice the parameter is empty:
This is happening because the framework can't model bind the JSON data to the .Net object. The DefaultModelBinder is the class responsible for this. Thankfully there's a simple fix. ASP.NET MVC 3 Preview 1 has a new factory class called ValueProviderFactories. This class is a value provider which means it gathers values from different sources for an action method. The factory to model bind the JSON data is JsonValueProviderFactory. You ad this new value provider factory to your global.asax file:
ValueProviderFactories.Factories.Add(new JsonValueProviderFactory());
Now when you run your code, you'll see the data is being sent correctly to the action:
What this code means is whenever an action receives parameters from JSON, it will use the JsonValueProviderFactory class to break down the data and transform that into something more meaningful to you. If you need to do something similar in ASP.NET MVC 2, you could write a custom JSON model binder like the following:
public class JsonOrderModelBinder : IModelBinder
{
public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
{
if (!controllerContext.HttpContext.Request.ContentType.StartsWith("application/json", StringComparison.OrdinalIgnoreCase))
{
// not JSON request
return null;
}
var request = controllerContext.HttpContext.Request;
var incomingData = new StreamReader(request.InputStream).ReadToEnd();
if (String.IsNullOrEmpty(incomingData)) {
// no JSON data
return null;
}
JavaScriptSerializer serializer = new JavaScriptSerializer();
return serializer.Deserialize(incomingData, bindingContext.ModelType);
}
}
And to use it do this:
[HttpPost]
public ActionResult Edit([ModelBinder(typeof(JsonOrderModelBinder))] Order order)
{
return View();
}
Both achieve the same result, but using the JsonValueProvider Factory means you register it once and that's it. This makes it simple to receive JSON data.
The entire source code of this article can be downloaded over here
This article has been editorially reviewed by Suprotim Agarwal.
C# and .NET have been around for a very long time, but their constant growth means there’s always more to learn.
We at DotNetCurry are very excited to announce The Absolutely Awesome Book on C# and .NET. This is a 500 pages concise technical eBook available in PDF, ePub (iPad), and Mobi (Kindle).
Organized around concepts, this Book aims to provide a concise, yet solid foundation in C# and .NET, covering C# 6.0, C# 7.0 and .NET Core, with chapters on the latest .NET Core 3.0, .NET Standard and C# 8.0 (final release) too. Use these concepts to deepen your existing knowledge of C# and .NET, to have a solid grasp of the latest in C# and .NET OR to crack your next .NET Interview.
Click here to Explore the Table of Contents or Download Sample Chapters!
Was this article worth reading? Share it with fellow developers too. Thanks!
Malcolm Sheridan is a Microsoft awarded MVP in ASP.NET, a Telerik Insider and a regular presenter at conferences and user groups throughout Australia and New Zealand. Being an ASP.NET guy, his focus is on web technologies and has been for the past 10 years. He loves working with ASP.NET MVC these days and also loves getting his hands dirty with jQuery and JavaScript. He also writes technical articles on ASP.NET for SitePoint and other various websites. Follow him on twitter @
malcolmsheridan