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