Tag: JSON
So as some of you know, I’ve spent a lot of the last year working on a web project. I’ve been using ASP.NET MVC3 and it’s going well. I am at the point where we are creating the mobile apps. I service them, I need an API (which will eventually be available as a public API too). I had started creating using MVC and simple routes but I was urged to look at the new Web API stack that is installed with the new ASP.NET MVC4 installer.
NOTE: To write this blog post, I got a lot of Twitter help from Glenn Block, Darrel Miller and and Rick Strahl!
Adding WebAPI to your Project
There are a number of demos out there that work great, but for me I don’t want to upgrade to MVC 4 yet (since at the time of this writing, it’s just in Beta, though it does have a GoLive license I believe). But I want to minimize the possibility of introducing bugs. So I want to use Web API to my existing MVC3 project. It’s actually really easy.
Assuming you’ve already installed the ASP.NET MVC 4 installer (get it here), you can use Nuget to install just the WebAPI pieces. You can use the Nuget Package Manager dialog to do it (search for “webapi” and look on the 2nd page):

Or just use the Package Manager Console and type:
Install-Package AspNetWebApi
You now have all the assemblies required. But now you need to wire it up.
Creating Your First Web API
To create your first API, you’ll need to first add a route to your Global.asax file. First add a using (or Imports for VB) to the System.Web.Http namespace (as this adds some extension methods you’ll need). Then call the MapHttpRoute method which allows you to create routes to the Web API controllers as shown here:
...
using System.Web.Http;
namespace WebApiForTheMvcGuy
{
public class MvcApplication : System.Web.HttpApplication
{
...
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapHttpRoute("Default API Route",
"api/1.0/{controller}/{id}",
new
{
id = RouteParameter.Optional
});
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = UrlParameter.Optional } // Parameter defaults
);
}
...
}
}
Note that we have this controller before the default MapRoute of MVC so that the “api/1.0” part of the route doesn’t get caught in the route list. This implies that these routes are just part of the route list like your standard MVC routes.
Next you need an Web API controller. The HttpRoute I show here will work with any controller, but you’ll likely need multiple routes for different styles of API calls. The best way to add the new controller is to use the Add New Item dialog:

This creates the skeleton of the project. At this point, you can actually navigate to the API to test it:

Great, we have the Web API working. I could delve forth into a discussion of how the Web API stuff works, but I think Jon Galloway’s videos do a great job of this so go watch them right now:
Ok, you’re back! Notice that the result is XML in our example. Why? Because the browser sends the Accept header of “text/xml” and not one for JSON (since the browser can’t display JSON natively). This is different from how you might have exposed data via MVC controllers. Your calls from JavaScript will include the “application/json” accept header so it should return JSON. While I could use Fiddler or other ways to force the JSON header, but wanted it to return JSON in every case. I also did not want to deal with the JSON serialization that is used by default. I wanted to see how to use the same JavaScriptSerializer that MVC uses so that any old code I had didn’t have serialization craziness.
Fun With Formatters
To get the JSON-only format for my Web APIs that I want, there are a number of approaches. But the easiest is to just remove the XML formatter from the Web API’s configuration:
public class MvcApplication : System.Web.HttpApplication
{
...
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
RegisterGlobalFilters(GlobalFilters.Filters);
RegisterRoutes(RouteTable.Routes);
// The Web API Configuration Object
var config = GlobalConfiguration.Configuration;
// Remove the XML Formatter
var xmlFormatter = config.Formatters
.Where(f =>
{
return f.SupportedMediaTypes.Any(v => v.MediaType == "text/xml");
})
.FirstOrDefault();
if (xmlFormatter != null)
{
config.Formatters.Remove(xmlFormatter);
}
}
}
I’m searching for the formatter that supports XML and removing it. When I do this, the Web API stack will default back to JSON as shown here:

A Better JSON Formatter
As stated earlier, I am not alone in my dislike for the DataContractJsonSerializer class. Unfortunately this is the default. To fix that, we can create a new formatter for JSON and include it first in the Formatters for Web API. This means it’ll be used before the built-in one (though I decided to leave it there for back up in case there were content-types I wasn’t aware of). Here is the formatter class:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Net.Http.Formatting;
using System.Net.Http.Headers;
using System.Threading.Tasks;
using System.IO;
using System.Web.Script.Serialization;
using System.Net;
namespace WebApiForTheMvcGuy.Formatters
{
// Adapted from Rick Strahl's he mentioned on Twitter
// http://codepaste.net/dfz984
public class JavaScriptSerializerFormatter : MediaTypeFormatter
{
public JavaScriptSerializerFormatter()
{
SupportedMediaTypes.Add(
new MediaTypeHeaderValue("application/json"));
}
protected override bool CanWriteType(Type type)
{
return true;
}
protected override bool CanReadType(Type type)
{
return true;
}
protected override Task<object> OnReadFromStreamAsync(Type type,
Stream stream,
HttpContentHeaders contentHeaders,
FormatterContext formatterContext)
{
var task = Task.Factory.StartNew(() =>
{
using (var rdr = new StreamReader(stream))
{
var json = rdr.ReadToEnd();
JavaScriptSerializer ser = new JavaScriptSerializer();
object result = ser.Deserialize(json, type);
return result;
}
});
return task;
}
protected override Task OnWriteToStreamAsync(Type type,
object value,
Stream stream,
HttpContentHeaders contentHeaders,
FormatterContext formatterContext,
TransportContext transportContext)
{
var task = Task.Factory.StartNew(() =>
{
JavaScriptSerializer ser = new JavaScriptSerializer();
string json = ser.Serialize(value);
byte[] buf = System.Text.Encoding.Default.GetBytes(json);
stream.Write(buf, 0, buf.Length);
stream.Flush();
});
return task;
}
}
}
And then back in the configuration in Global.asax, I inserted the new formatter:
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
RegisterGlobalFilters(GlobalFilters.Filters);
RegisterRoutes(RouteTable.Routes);
...
// Insert our JSON Formatter First
config.Formatters.Insert(0, new JavaScriptSerializerFormatter());
}
Now I can write my API using the new Web API stack and not have to upgrade to MVC 4 (yet) as well as make some minor modifications to the way it works to be more like my MVC JSON routes I already use. Cool?
Here is the code:

I wasted an evening last night on a simple bug of mine. I was writing a simple HTML data entry page. I was using JSON + $.ajax to POST data to a ASP.NET MVC controller and it used to work. But for the life of me I couldn’t figure out what was wrong. Let’s start with some background.
In ASP.NET MVC3, they made a change to make the JsonValueProviderFactory part of the ValueProviderFactories so that data that comes in as JSON can be mapped to model classes automatically. See this Phil Haack post for how that works:
Essentially the JsonValueProviderFactory is used to match the shape of JSON inputs to model classes. Therefore if you have a piece of JSON that looks like:
{
"id": 1,
"name": "Some Picture",
"picture": "http://wildermuth.com/images/turninghead.gif"
};
And you have an action that looks like this:
[HttpPost]
public JsonResult SaveImage(ImageModel picture)
{
if (picture == null)
{
return Json(new { success = false, message = "Model came through as null" });
}
return Json(new { success = true });
}
The JsonValueProviderFactory’s job is to map the JSON to the ImageModel class:
public class ImageModel
{
public int Id { get; set; }
public string Name { get; set; }
public string Picture { get; set; }
}
It does this by looking at the shape of the JSON and mapping it to properties in the model class. Simple and elegant. Works great…except when it doesn’t.
So how did I lose a full evening to this simple mapping? There are things that can go wrong like not having the routes correct or having bad data sent in the request, but I was reaching the action and my ImageModel was null. No error, no debugging in the output window…it just didn’t work. I stared at this code and cajoled people on twitter to help to no luck. It had to be that the JSON I was sending was incompatible, but I didn’t see how. Fiddler to the rescue.
So I fired up Fiddler2 (www.fiddler2.com) and executed my javascript code that looks like this:
$(document).ready(function () {
$("#send-data").click(function () {
$("#status").text("Saving...");
// Some data in the right shape for the server
var data = {
"id": 1,
"name": "Some Picture",
"picture": "http://wildermuth.com/images/turninghead.gif"
};
$.ajax({
// URI for POST
url: '/Home/SaveImage',
// Turn object into JSON
data: JSON.stringify(data),
contentType: 'application/json; charset=utf-8',
type: 'POST',
success: function (response) {
if (response.success) {
// It worked!
$("#status").text("Saved...");
} else {
//
$("#status").text(response.message);
}
},
error: function (response) {
$("#status").text("Error!");
}
});
});
});
Fiddler captured the traffic and showed what I expected (I can use the inspectors to see both the request and the response as shown here):

You can see the session in the Web Sessions pane. And using the Inspectors, I can see the JSON I sent and the JSON I received (remember on failure, I’m returning a JSON result that explains the failure). Fiddlers let’s you use a tool called the “Composer” that will allow you to create a request and run it directly from Fiddler:

While you could craft a custom request in the composer by just typing all the necessary bits, it also lets you drag a request from the Web Sessions pane to clone it. I cloned the bad request (shown here) and if I press “Execute” it will re-run the request:

Just like the captured request, my re-issuing of the identical request resulted in the model being null. I suspect it has something to do with the property matching in the ModelBinding so to debug this I just removed properties in the JSON request until it worked. Fiddler allows me to use the Composer to just hand-edit the request so I can re-test quickly:

I hand-edit the JSON in the request and remove the picture property. Once I do that (or another part of the JSON request) I can hit execute to see if it still fails:

It worked…huh? Why would removing the picture property make it fail? If we look at the ImageModel class, the property name isn’t misnamed or anything. The solution was obvious once I knew it was the picture property. Let’s see that action again:
[HttpPost]
public JsonResult SaveImage(ImageModel picture)
{
if (picture == null)
{
return Json(new { success = false, message = "Model came through as null" });
}
return Json(new { success = true });
}
The problem is that the name of parameter into the method is picture and MVC is getting confused between wanting to map the picture property of the JSON and the picture parameter of the action. This happens because it would have also mapped our JSON to an action that looked like this perfectly well:
[HttpPost]
public JsonResult SaveImage(int id, string name, string picture)
{
ASP.NET MVC tries to do the right thing and the duplication of the parameter name as the property name got it confused. So to fix this, I simply needed to rename the parameter like so:
[HttpPost]
public JsonResult SaveImage(ImageModel image)
{
if (image == null)
{
return Json(new { success = false, message = "Model came through as null" });
}
return Json(new { success = true });
}
Sure, a wasted night (and the resulting loss of time documenting it here so that you can prop up my fragile ego), but it helped me understand what was really going on under the covers.
Url: http://wildermuth.com/downloads/dataservicejque...
I'd recently been asked by Chris Sells to help him with a simple WCF Data Services/jQuery example so I thought I'd share it via my blog as well. The basic idea is to use jQuery's AJAX functionality to retrieve JSON instead of the usual OData and consume it on a web page.
The example I decided on using is to expose the XBox database with paging. I am not doing any of the niceties like getting result counts to show a real navigation bar. Instead this is quick and dirty to simply do "next" and "prev" and use WCF Data Service's URI API to retrieve data.
Like most of my XBox examples, I am using the Entity Framework to simply expose three entities types (Games, Genres and Ratings). Then I utilize a WCF Data Service to expose these types for consumption via REST. My HTML is simple:
<h2>
XBox Games</h2>
<div>
<a href="#" id="PrevPage">Prev</a>
<a href="#" id="NextPage">Next</a>
</div>
<div id="gameTable" />
The gameTable will simply be filled with a simple TABLE element for our data. So to the jQuery we go. I am using plain jQuery 1.3.2 (though plugins could be used to simplify some of this code, I choose to just do it raw for simplicity).
First I set up a couple of variables to hold our paging information:
// globals for paging
var page = 0;
var pagesize = 25;
Next I handle the document's ready function to do some work when the initial page load is complete:
// Loads once the document has completed loading
$(document).ready(function () {
// Set up paging buttons
$('#PrevPage').click(function (evt) {
// Stop the navigation from happening
evt.preventDefault();
if (page > 0) {
page--;
loadData();
}
});
$('#NextPage').click(function (evt) {
evt.preventDefault();
page++;
loadData();
});
// Load the initial data
loadData();
});
When setting up the paging buttins, I use the '#PrevPage' and '#NextPage' CSS selectors to find items named PrevPage and NextPage and wire up the event to cause the page changes to happen. The 'evt.preventDefault()' call stops the buttons from trying to navigate since we're using them as buttons. FInally once we change the current page value, we call loadData (or in the initial case, call loadData with the default values).
function loadData() {
var url = "/GameService.svc/Games?$orderby=Name" +
"&$skip=" + (page * pagesize) +
"&$top=" + pagesize;
$.ajax({
type: "GET",
url: url,
contentType: "application/json; charset=utf-8",
dataType: "json",
success: function (msg) {
loadTable(msg.d);
}
});
}
In the loadData function, I first create the URL by using the Data Service/OData URL API to retrieve games by Name while using the global values to retrieve a page of data at a time (see the $skip and $top parameters). Once the URL is defined, jQuery's ajax function executes the URL and returns in the success function in which we call loadTable to create the table for us. Since the returned JSON is contained in a 'd' element for security, we de-reference the 'd' element before we sent it into the loadTable function.
function loadTable(results) {
var table = '<table><thead><tr><th>Name</th>' +
'<th>Publisher</th><th>Box</th></thead><tbody>';
for (var post in results) {
var row = '<tr>';
row += '<td>' + results[post].Name + '</td>';
row += '<td>' + results[post].Publisher + '</a></td>';
row += '<td><img src="' + results[post].ImageUrl +
'" style="width: 100px; height=150px" /></td>';
row += '</tr>';
table += row;
}
table += '</tbody></table>';
$('#gameTable').html(table);
}
Finally in loadTable some simple HTML construction goes on to create a table with our results. The for loop returns a iterator for each row in the collection which we can use to retrieve the individual item (see results[post].Name as an example). Once the table is built, it replaces the contents of the element named gameTable with the new table.
Because WCF Data Services will return JSON as well, you can use it to do AJAX work just as effectively as Silverlight can consume it for rich client work. You can get the code here:
http://wildermuth.com/downloads/DataServiceJQuery.zip