More Awesomeness: Post JSON to an Action Method

Tags: Knockout, pubsub, observer, MVC, jQuery, Ajax, EF, Validation, FluentValidation, Visual Studio 2010, ASP.NET, JSON, FullCalendar, Silverlight, Architecture, Vista, IIS, Generics, NHibernate, WCF, RIA Services, Visual Studio 2008, SQL, STORM!, Nullable, ChannelFactory, netTCPBinding, VSPAT, responsive, design, HTML5, CSS3, MVC WebAPI, MVC 4, WebAPI, JQuery Mobile, ScheduleWidget, recurring events, Ninject, Pluggable, CQRS DDD, Windows

Fortunately I came late to the party and didn't develop MVC 2 web apps. I understand that back in those ancient days (about 6 months ago) you had to walk uphill both ways to post JSON data back to an action method. Phil Haack has a great blog post on the topic. Basically, you had to write a custom filter, register a JsonValueProviderFactory in application startup, and decorate your action method with the JSON serializer attributes. What a pain. In MVC 3 it's super easy to use AJAX to post JSON back to an action method. Here are the steps.

Create a new MVC 3 web application. Add a new Model called Widget (what else?):

public class Widget
{
    public int ID { get; set; }
    public string Shape { get; set; }
    public string Color { get; set; }
}

In the HomeController add an action method to take a Widget instance:

public ActionResult GetData(Widget widget)
{
    // using System.Diagnostics
    Debug.WriteLine("Got a " + 
        widget.Shape + " " + 
        widget.Color + " widget with id " + 
        widget.ID);
    return null;
}

Add a route to the map for this new action method:

routes.MapRoute(
    "Widget", 
    "{Home}/{GetData}", 
    new { controller = "Home", action = "GetData" }
);

Get the json2.js script so you can use the stringify function. Put it in your Scripts folder and reference it at the top of your shared _Layout.cshtml page so it's available application wide. Now go to the Home Index.cshml file and add some javascript below the awesome "learn more about ASP.NET MVC" p tag and link:

<script type="text/javascript">
    $(document).ready(function () {
        $('a').click(function () {
            var widget = {
                ID: "" + "666" + "",
                Shape: "" + "purple" + "",
                Color: "" + "octagonal" + ""
            };
            $.ajax({
                url: "/Home/Index",
                async: true,
                type: "post",
                datatype: 'json',
                data: JSON.stringify(widget),
                contentType: 'application/json',
                error: function (xhr) {
                    alert('Something went wrong buddy! ' + xhr.statusText);
                }
            });
        });
    });
</script>

That's it. What's going on here? After the DOM has fully loaded I'm registering a function on the a tag click event. So when you click the oddly compelling "learn more" link on the home page a widget will get created and posted asynchronously to our action method. Put a break on the Debug.WriteLine if you want or just watch your Output window. Fire up the app and click on the very persuasive ASP.NET MVC learn more link. If everything is wired up correctly you'll see the debug output:

Got a purple octagonal widget with id 666

This is a very simple example. The point here is that you're not stuck building url strings like "/Home/Index/6" but rather in MVC 3 you can post complex JSON data to an action method with very little plumbing.