C# – the best strategy to handle unhandled Exceptions (error 500 responses) in Asp.Net MVC actions for Ajax requests

asp.net-mvccexception handlingjson

I am confused as to how to handle this situation.

Usually when an unhandled ASP.Net exception occurs, the server sends back an HTML message of some sort, either the default Asp.Net error handler or a custom error handler. In either case though, HTML is being sent back (and usually it's a good idea to make the page user friendly).

However, I am having an issue where the unhandled exceptions are occurring in Asp.net MVC controller actions that are expected to return JSON for Ajax calls. When the javascript reads the returned page (which is HTML instead of intended JSON) it crashes due to not being able to convert the response into JSON (right now I'm using ExtJS). I want Json to be returned upon an exception so that the user can be notified that an error has occurred.

The only solution I can think of is to do the following in every action that returns Json:

try { .... }
catch (Exception ex)
{
   return Json(new { success = false, msg = ex.Message });
}

I don't like that method because it requires me catch all exceptions (which is bad for obvious reasons) and it requires me to pepper every JsonResult action with that same exception handling code (which makes it hard to change later).

Is there a better method to return a more appropriate error result only on action methods that return Json, but still keep regular error pages user friendly for non-Ajax web requests?

Best Answer

Here's how I solved this problem:

public class HandleJsonError : HandleErrorAttribute
{
    public override void OnException(ExceptionContext exceptionContext)
    {
        if (!exceptionContext.HttpContext.Request.IsAjaxRequest() || exceptionContext.Exception == null) return;

        exceptionContext.HttpContext.Response.StatusCode = (int) HttpStatusCode.InternalServerError;
        exceptionContext.Result = new JsonResult
                                   {
                                       Data = new
                                                  {
                                                      exceptionContext.Exception.Message,
                                                      exceptionContext.Exception.StackTrace
                                                  }
                                   };

        exceptionContext.ExceptionHandled = true;
    }
}