Using Json.NET as default JSON serializer in MVC

JSON
Returning JSON from an MVC action method is very easy. Just look at this simple example:

public JsonResult GetItemData(int itemId)
{
  // ...things to do...
  var response = new { result = "ok" };
  return Json(response);
}

Serialization of the object into JSON is taken care of by ASP.NET in the background and you can just focus on what your method should be doing.

MVC uses JavaScriptSerializer as the default JSON serializer. But what if you’re not happy with that? In Web.API the default JSON serializer is Json.NET (created by James Newton-King) and why shouldn’t we be able to use this one in MVC as well? As Microsoft themselves put it:

Json.NET provides the flexibility and performance required for a modern web framework.

What we basically need to do is to extend the JsonResult class and create new functionality for the ExecuteResult method. We then get the opportunity to select ourselves how we want to serialize the Json data and can thus use the JsonSerializer from Json.NET instead.

public class JsonNetResult : JsonResult
{
  public JsonNetResult()
  {
    Settings = new JsonSerializerSettings
    {
      ReferenceLoopHandling = ReferenceLoopHandling.Error
    };
  }

  public JsonSerializerSettings Settings { get; private set; }

  public override void ExecuteResult(ControllerContext context)
  {
    if (context == null)
      throw new ArgumentNullException("context");

    HttpResponseBase response = context.HttpContext.Response;

    if (this.ContentEncoding != null)
      response.ContentEncoding = this.ContentEncoding;
    if (this.Data == null)
      return;

    response.ContentType = string.IsNullOrEmpty(this.ContentType) ? "application/json" : this.ContentType;

    var scriptSerializer = JsonSerializer.Create(this.Settings);
    // Serialize the data to the Output stream of the response
    scriptSerializer.Serialize(response.Output, this.Data);
  }
}

After this is done we need to make sure our new version of JsonResult is being used. The easiest way to do this is to create an action filter that executes after the action method is done. In this action method we filter out all calls that have a result of type JsonResult and change that to a result of type JsonNetResult. Since JsonNetResult extends JsonResult it works really simple.

public class JsonNetActionFilter : ActionFilterAttribute
{
  public override void OnActionExecuted(ActionExecutedContext filterContext)
  {
    if (filterContext.Result.GetType() == typeof(JsonResult))
    {
      // Get the standard result object with unserialized data
      JsonResult result = filterContext.Result as JsonResult;

      // Replace it with our new result object and transfer settings
      filterContext.Result = new JsonNetResult
      {
        ContentEncoding = result.ContentEncoding,
        ContentType = result.ContentType,
        Data = result.Data,
        JsonRequestBehavior = result.JsonRequestBehavior
      };

      // Later on when ExecuteResult will be called it will be the
      // function in JsonNetResult instead of in JsonResult
  }
    base.OnActionExecuted(filterContext);
  }
}

The final thing we need to do is to register our new ActionFilter in App_Start/FilterConfig.cs so it’ll be activated for all action methods automatically.

public class FilterConfig
{
  public static void RegisterGlobalFilters(GlobalFilterCollection filters)
  {
    filters.Add(new HandleErrorAttribute());
    filters.Add(new JsonNetActionFilter());
  }
}

Now, everytime you execute an action method according to the first initial example above, Json.NET serializer will be used instead of the standard JavaScriptSerializer.

Note, however, that it’s only outgoing responses that are encoded using Json.NET. If you want to encode incoming JSON data as well you have to implement your own ValueProviderFactory. I might cover that in a later post, but not here and now.