Adventures in HttpContext All the stuff after 'Hello, World'

The New Web App Architecture: ASP.NET MVC 3, jQuery Templating with PURE and the Json Value Provider

Over the past couple of years there has been a slow progression in the .NET web app world to fully separate out client/server interaction.  Long gone are the horrible days of ViewState and Events; MVC provided a nice step to better structure web applications for powerful Web 2.0 experiences.  But the barrier between client and server interaction has never really been clean-  MVC markup has always been littered with C# code and there hasn’t always been widespread tools available to easily build desktop class applications in the browser.  Sure, spark and haml provide alternatives, but these are essentially make a core problem easier to bear.

With the new preview of MVC 3, we can eliminate that core problem of server based html rendering: the built in Json Support via the JsonValueProviderFactory along with some jQuery goodies presents us with the new web app architecture: service- orientated web apps built with a rich, js based client driven by Json based services.  Using core tools of html, css, and js and not requiring the overhead of Silverlight, Flash, or JS based web frameworks.  This JSON functionality, combined with javascript templating using PURE gives us the ability to break free from the static html navigation and build dynamic apps in much more efficient ways.

ASP.NET MVC 3 and the JsonValueProviderFactory

Scott Guthrie writes about the new ASP.NET MVC 3 preview features, and among the hype is the default Json support for action methods.  In his blog post he forgets one crucial step to actually make this work, which is adding the new JsonValueProviderFactory to the global value provider factories class in the Application start method of the global.asax, like so:

protected void Application_Start()
{
    AreaRegistration.RegisterAllAreas();

    //Must add this factory explicitly (for now, at least):
    ValueProviderFactories.Factories.Add(new JsonValueProviderFactory());

    RegisterGlobalFilters(GlobalFilters.Filters);
    RegisterRoutes(RouteTable.Routes);
}

Once this is in place we can treat our controller actions as usual, even when using Json.  The serialization mechanism is agnostic (this is pretty much exactly the same as Scott’s code):

[HttpPost]
public ActionResult Search(ImageSearchInput input)
{
    //AssetSearchInput can be posted via Json
    return new JsonResult() { Data = new { ImageInfo = new Repository.ImageRepository().Search(input).Images } };
}

ImageSearchInput, with a string property of “Caption”, will be built from the Json data posted to the server by the following Ajax call:

$('#search').submit(function () {
  var input = { Caption: $('#caption').val() };

  $.ajax({url: '/Home/Search',
    type: 'POST',
    data: JSON.stringify(input),
    dataType: 'json',
    contentType: 'application/json; charset=utf-8',
    success: function (data) {
        $('.imgContainer').autoRender(data);
    }
  });

  return false;
});

The server will route the request to the Home/Search method, and will serialize the posted data in the ImageSearchInput class.  As long the properties match up and are of the correct type, the deserialization will be fluid.  Notice how we don’t actually need to specify the ImageSearchInput class name when building the Json object.

Those with keen eyes may have noticed the success: callback containing the autoRender() function.  This is the [Over the past couple of years there has been a slow progression in the .NET web app world to fully separate out client/server interaction.  Long gone are the horrible days of ViewState and Events; MVC provided a nice step to better structure web applications for powerful Web 2.0 experiences.  But the barrier between client and server interaction has never really been clean-  MVC markup has always been littered with C# code and there hasn’t always been widespread tools available to easily build desktop class applications in the browser.  Sure, spark and haml provide alternatives, but these are essentially make a core problem easier to bear.

With the new preview of MVC 3, we can eliminate that core problem of server based html rendering: the built in Json Support via the JsonValueProviderFactory along with some jQuery goodies presents us with the new web app architecture: service- orientated web apps built with a rich, js based client driven by Json based services.  Using core tools of html, css, and js and not requiring the overhead of Silverlight, Flash, or JS based web frameworks.  This JSON functionality, combined with javascript templating using PURE gives us the ability to break free from the static html navigation and build dynamic apps in much more efficient ways.

ASP.NET MVC 3 and the JsonValueProviderFactory

Scott Guthrie writes about the new ASP.NET MVC 3 preview features, and among the hype is the default Json support for action methods.  In his blog post he forgets one crucial step to actually make this work, which is adding the new JsonValueProviderFactory to the global value provider factories class in the Application start method of the global.asax, like so:

protected void Application_Start()
{
    AreaRegistration.RegisterAllAreas();

    //Must add this factory explicitly (for now, at least):
    ValueProviderFactories.Factories.Add(new JsonValueProviderFactory());

    RegisterGlobalFilters(GlobalFilters.Filters);
    RegisterRoutes(RouteTable.Routes);
}

Once this is in place we can treat our controller actions as usual, even when using Json.  The serialization mechanism is agnostic (this is pretty much exactly the same as Scott’s code):

[HttpPost]
public ActionResult Search(ImageSearchInput input)
{
    //AssetSearchInput can be posted via Json
    return new JsonResult() { Data = new { ImageInfo = new Repository.ImageRepository().Search(input).Images } };
}

ImageSearchInput, with a string property of “Caption”, will be built from the Json data posted to the server by the following Ajax call:

$('#search').submit(function () {
  var input = { Caption: $('#caption').val() };

  $.ajax({url: '/Home/Search',
    type: 'POST',
    data: JSON.stringify(input),
    dataType: 'json',
    contentType: 'application/json; charset=utf-8',
    success: function (data) {
        $('.imgContainer').autoRender(data);
    }
  });

  return false;
});

The server will route the request to the Home/Search method, and will serialize the posted data in the ImageSearchInput class.  As long the properties match up and are of the correct type, the deserialization will be fluid.  Notice how we don’t actually need to specify the ImageSearchInput class name when building the Json object.

Those with keen eyes may have noticed the success: callback containing the autoRender() function.  This is the]3 javascript templating engine at work.  I came across PURE when reading about the jQuery templating proposal on GitHub and was immediately drawn to its simplistic syntax.

The philosophy behind PURE is simple: instead of interleaving markup and template directives (which, to be honest, is just as bad as mixing code with markup), PURE can make assumptions about what to repeat and what to bind based on css class names and Json property names.

Let’s say I had the following json markup:

var data = {
    Image:
        { Filename: 'mypic1.jpg', ImageUrl: '/images/mypic1.jpg'},
        { Filename: 'agoodphoto.jpg', ImageUrl: '/images/agoodphoto.jpg'}
}

This is simply an Array with two objects in it.  Using PURE’s autoRender function, we can specify binding directives using CSS classes, building li elements and populating content as appropriate:

<ul class="imgContainer">
    <li class="Image">
        <p><img class="ImageUrl@src" /></p>
        <p class="info"><span class="Filename"></span></p>
    </li>
</ul>

Because the li has the Image css class, and we have an array of Image objects, PURE will duplicate the li contents for each element in the array.  The span tag will show the filename property because it has the Filename css class.  The src attribute of the img tag will get the ImageUrl property because it is using the @ directive, which simply says “put the ImageUrl property in the src attribute”.  PURE can easily get it’s own post, but the point is simple:  we no longer need to generate server side html for displaying complex content.  Even though this has always been possible before, it hasn’t been as fluid as PURE.  Another primary benefit is that we can send incredibly complex Json data back to the client which can update numerous page snippets.  Orchestrating multi-updates, like a detail page, shopping cart, or other areas simultaneously has not been trivial, but because we have json data and templating these complex scenarios are easily achievable.

Gotchas

Client side templating is dangerous- you don’t really know how well the client’s computer it is.  Be mindful of performance and memory requirements, and ensure you’re targeting the right browsers.  Chrome’s V8 javascript engine has evolved remarkably well in handling javascript intensive applications.

As for the MVC 3 preview, I wish we saw dynamic results from controllers: specifically, one action to return either  Json, Xml, or Html output based on some request directive.  This is possible with various ActionResults or ActionFilters, and there’s some functionality already out there to do it, but it isn’t as nice as Ruby on Rail’s respond_to functionality.  A single action supporting multiple outputs will allow developers to easily target various platforms and scenarios in the web world.

Final Thoughts

Despite techniques of Json serialization and jQuery templating already existing in the ecosystem, it has never been as robust and integrated as with the new MVC 3 support (sure, Rails has had this for a while).  Combining this functionality with templating tools like PURE will open up new development paths for rich web applications based entirely on standard tools like javascript, html, and css without relying on chunky js frameworks.  Keeping core tools simple means having the ability to build out specific functionality as needed, rather than getting boxed into more complete frameworks.  From the managing side, it also keeps the available pool of developers large so you’re not requiring knowledge on a specific tool.  Play around with these tools and see what you can do!

Shout it