aspnet mvc has the HandleError filter that will return a view if an error occurs, but if an error occurs when calling a JsonResult Action how can I return a JSON object that represents an error?
I don't want to wrap the code in each action method that returns a JsonResult in a try/catch to accomplish it, I'd rather do it by adding a 'HandleJsonError' attribute or using the existing HandleError attribute to the required action methods.
In short, the way to go can be to extend the HandleErrorAttribute, like this:
public class OncHandleErrorAttribute : HandleErrorAttribute
{
    public override void OnException(ExceptionContext context)
    {
        // Elmah-Log only handled exceptions
        if (context.ExceptionHandled)
            ErrorSignal.FromCurrentContext().Raise(context.Exception);
        if (context.HttpContext.Request.IsAjaxRequest())
        {
            // if request was an Ajax request, respond with json with Error field
            var jsonResult = new ErrorController { ControllerContext = context }.GetJsonError(context.Exception);
            jsonResult.ExecuteResult(context);
            context.ExceptionHandled = true;
        }
        else
        {
            // if not an ajax request, continue with logic implemented by MVC -> html error page
            base.OnException(context);
        }
    }
}
Remove Elmah logging code line if you don't need it. I use one of my controllers to return a json based on an error and context. Here is the sample:
    public class ErrorController : Controller
{
    public ActionResult GetJsonError(Exception ex)
    {
        var ticketId = Guid.NewGuid(); // Lets issue a ticket to show the user and have in the log
        Request.ServerVariables["TTicketID"] = ticketId.ToString(); // Elmah will show this in a nice table
        ErrorSignal.FromCurrentContext().Raise(ex); //ELMAH Signaling
        ex.Data.Add("TTicketID", ticketId.ToString()); // Trying to see where this one gets in Elmah
        return Json(new { Error = String.Format("Support ticket: {0}\r\n Error: {1}", ticketId, ex.ToString()) }, JsonRequestBehavior.AllowGet);
    }
I add some ticket info above, you can ignore this. Due to the way the filter is implemented (extends the default HandleErrorAttributes) we can remove then HandleErrorAttribute from the global filters:
    public class MvcApplication : System.Web.HttpApplication
{
    public static void RegisterGlobalFilters(GlobalFilterCollection filters)
    {
        filters.Add(new GlobalAuthorise());
        filters.Add(new OncHandleErrorAttribute());
        //filters.Add(new HandleErrorAttribute());
    }
This is basically it. You can read my blog entry for more detailed info, but for the idea, above should suffice.
Take a look at the MVC implementation of HandleErrorAttribute. It returns a ViewResult. You could write your own version (HandleJsonErrorAttribute) that returns a JsonResult.
Maybe you could create your own Attribute and have a constructor value that takes an enum value of View or Json. Below is what Im using for a custom Authorization Attribute to demonstrate what I mean. This way when authentication fails on a json request it responds with a json error and the same with if it returns a View.
   public enum ActionResultTypes
   {
       View,
       Json
   }
    public sealed class AuthorizationRequiredAttribute : ActionFilterAttribute, IAuthorizationFilter
    {
        public ActionResultTypes ActionResultType { get; set; }
        public AuthorizationRequiredAttribute(ActionResultTypes actionResultType)
        {
            this.ActionResultType = ActionResultType;
        }
    }
    //And used like
    [AuthorizationRequired(ActionResultTypes.View)]
    public ActionResult About()
    {
    }
                        If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With