Thoughts on developing resilient Ajax code (Part 2 – ASP.net MVC)

In my last post we looked at different methods to indicate a call to a service that would return JSON was unsuccessful.

The conclusion was that we really want to be setting the HTTP status code of the response to indicate a request was unsuccessful.

In this post we will look at some possibilities for wrapping this logic up in ASP.net MVC controller methods (and there are many).

We want a way of:

  • Setting the status code of the response
  • Including in the response our errors formatted as JSON
  • Something that’s easy to reuse and maintain

The most obvious (and least reusable) option is probably something like:

Response.StatusCode = (int) HttpStatusCode.InternalServerError;
return Json(new { data = "bad error" });

We could also use the HttpStatusCodeResult class however this only allows us to set the description of the error status code rather than the body of the response:

return new HttpStatusCodeResult(HttpStatusCode.InternalServerError, "bad error");

We could remedy this with something like this:

Response.Write("bad error");
return new HttpStatusCodeResult(HttpStatusCode.InternalServerError, "bad error");

But we also want to format our response as JSON and set the return content-type to application/json so would then have to do something like this:

var errors = new List<string>() {"Bad error", "Another bad error"};
var serializer = new JavaScriptSerializer();
Response.ContentType = "application/json";
Response.Write(serializer.Serialize(errors));
return new HttpStatusCodeResult(HttpStatusCode.InternalServerError, "bad error");

Yuck!

This is getting a bit messy & we want something easy to use, maintain & test.

ASP.net MVC is very flexible and we have a number of different ways to do this but I reckon inheriting from JsonResult works pretty well for our purposes:

public class JsonErrorResult : JsonResult
{

private readonly HttpStatusCode _statusCode;

public JsonErrorResult(HttpStatusCode statusCode)
{

_statusCode = statusCode;

}

public override void ExecuteResult(ControllerContext context)
{
context.HttpContext.Response.StatusCode = (int)_statusCode;
base.ExecuteResult(context);
}

}

With this new type of ActionResult we get all the functionality of JsonResult and can also set the status code of the response easily:

var errors = new List<string>() {"Bad error", "Another bad error"};
return new JsonErrorResult(HttpStatusCode.InternalServerError) {Data = errors};

If we use browser tools we can see the Http status code was set correctly to 500, the content type is application/json and the response body contains our json encoded messages for later display:

1-12-2012 1-53-19 PM

Another option is to create a custom Action filter (this can be shortened by returning a JsonErrorResult as above):

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, Inherited = true, AllowMultiple = false)]
public class HandleErrorAsJsonResponseAttribute : ActionFilterAttribute, IExceptionFilter
{

public void OnException(ExceptionContext filterContext)
{

if (filterContext.HttpContext.Request.IsAjaxRequest())
{

filterContext.HttpContext.Response.StatusCode = (int) HttpStatusCode.InternalServerError;
filterContext.ExceptionHandled = true;
filterContext.Result = new JsonResult
{
Data = new { errorMessage = filterContext.Exception.Message}
};

}

}
}

This is very easy to apply (and can be done so at method, controller and even application level):

[HandleErrorAsJsonResponse]
public ActionResult ThrowError()
{
throw new Exception("bad exception");
}

I think these serve my purposes pretty well but if anyone’s got better ways of doing this I would love to hear them 🙂

Next up what’s jQuery actually doing in $.ajax

Advertisements