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:
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
