ASP.NET MVC – Create easy REST API with JSON and XML

Mar 27th, 2009

So I just hopped on the ASP.NET MVC bandwagon. As my first task, I undertook custom Action Filters for returning either JSON or XML as determined by the HTTP Request. Fortunately Omar AL Zabir did most of the work for creating a RESTful API with ASP.NET MVC.

JSON and XML Action Filter Code

The following is a filter which makes the whole thing much cleaner. The filter looks for Content-Type headers in the HTTP request. If it matches text/xml then Plain Old XML (POX) is returned and if it matches application/json the output is JSON. This eliminates the need to write separate actions for JSON/XML and Views.

using System;
using System.Web;
using System.Web.Mvc;
using System.IO;
using System.Xml;
using System.Text;
using System.Xml.Serialization;
namespace AleemBawany.ActionFilters
{
  public class JsonPox : ActionFilterAttribute
  {
    private static UTF8Encoding UTF8 = new UTF8Encoding(false);
    public override void OnActionExecuted(ActionExecutedContext filterContext)
    {
      // setup the request, view and data
      HttpRequestBase request = filterContext.RequestContext.HttpContext.Request;
      ViewResult view = (ViewResult)(filterContext.Result);
      var data = view.ViewData.Model;
      String contentType = request.ContentType ?? string.Empty;
      // JSON
      if (contentType.Contains("application/json"))
      {
        filterContext.Result = new JsonResult
        {
          Data = data
        };
      }
      // POX
      else if (contentType.Contains("text/xml"))
      {
        // MemoryStream to encapsulate as UTF-8 (default UTF-16)
        // http://stackoverflow.com/questions/427725/
        using (MemoryStream stream = new MemoryStream(500))
        {
          using (var xmlWriter =
            XmlTextWriter.Create(stream,
              new XmlWriterSettings()
              {
                // Plain Old XML (no XML headers)
                OmitXmlDeclaration = true,
                Encoding = UTF8,
                Indent = true
              }))
          {
            new XmlSerializer(data.GetType()).Serialize(xmlWriter, data);
          }
          filterContext.Result = new ContentResult
          {
            ContentType = "text/xml",
            Content = UTF8.GetString(stream.ToArray()),
            ContentEncoding = UTF8
          };
        }
      }
    }
  }
}

I suggest you get the code directly through JsonPoxFilter.cs in my SVN repository. It will be updated if I make any improvements.

Usage Example

To use this code in your Controller Action, you simply need to decorate it with the [JsonPox] attribute:

// Depending on HTTP Content-Type header
// this returns JSON, XML or the default View

[JsonPox]
public ActionResult Index()
{
        ArrayList stuff = new ArrayList();
        stuff.Add("Hello World");
        stuff.Add(999);
        stuff.Add(1.0001);
        ViewData.Model = stuff;
        return View();
}

Sample Output

If Content-Type: text/xml HTTP header is present the output is:

<ArrayOfAnyType xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <anyType xsi:type="xsd:string">Hello World</anyType>
  <anyType xsi:type="xsd:int">999</anyType>
  <anyType xsi:type="xsd:double">1.0001</anyType>
</ArrayOfAnyType>

For the HTTP header Content-Type: application/json the output is:

["Hello World",999,1.0001]

And if neither of those headers are present, the default View is returned.

Once again, if you intend to use it, get the latest bits for JsonPoxFilter.cs here instead of copying the above code.

12 Responses

Respond