Erik Zaadi

The tales of a developer with passion for dad jokes

Asp.Net MVC Exception Handling with jQuery

I stumbled upon this excellent post by Sumit : http://2leggedspider.wordpress.com/2009/12/22/handling-exceptions-using-jquery-and-asp-net-mvc/

I thought the idea was great, but the fact that you need to parse it as JSON bothered me.

Since the information needed is only the status code, stack trace and error message, it seemed more appropriate for me to use the existing http response parts that are designed to pass those values.

For the impatient:

Demo | Source

[Update] Altered the code with @Neal, and @Colin’s feedback..

I created a filter that inherits the default [HandleError] Attribute.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
public class HandleErrorWithAjaxFilter : HandleErrorAttribute  
{  

        public bool ShowStackTraceIfNotDebug { get; set; }  

        public override void OnException(ExceptionContext filterContext)  

            {  

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

                        {  

                                var content = ShowStackTraceIfNotDebug ||  

                                                    filterContext.HttpContext.IsDebuggingEnabled ?  

                                                        filterContext.Exception.StackTrace :  

                                                        string.Empty;  

                                filterContext.Result = new ContentResult  

                                    {  

                                            ContentType = "text/plain",//Thanks Colin  
                                                Content = content  

                                                };  

                                filterContext.HttpContext.Response.Status =  

                                        "500 " + filterContext.Exception.Message  

                                        .Replace("\r", " ")  

                                        .Replace("\n", " ");  

                                filterContext.ExceptionHandled = true;  

                                filterContext.HttpContext.Response.TrySkipIisCustomErrors = true;  

                            }  

                    else  

                        {  

                                base.OnException(filterContext);  

                            }  

                }  
}  

Note:

The typical usage would be to decorate the controller with the [HandleErrorWithAjaxFilter] attribute.

However, for the sake of the example, the actions are decorated separately to show the different override usages.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
public class HomeController : Controller  
{  

    public ActionResult Index()  
    {  

        return View();  

    }  


    [ErrorsForAjax.Models.HandleErrorWithAjaxFilter]  
    public ActionResult ThrowError()  

    {  

        throw new Exception("This is the error message");  

    }  


    [ErrorsForAjax.Models.HandleErrorWithAjaxFilter(ShowStackTraceIfNotDebug = true)]  
    public ActionResult ThrowErrorWithStackTrace()  

    {  

            throw new Exception("This is another error message");  

    }  
}  

The filter detects if the request came from Ajax, and if so returns a more slim response, allowing me to capture it in the jQuery ajax method’s error handler:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
$(function() {  

    $("button").click(function() {  

        $.ajax({ error: function(xhr, status, error) {  

                xhr.statusText; //ErrorMessage  
                xhr.responseText; //StackTrace (if debug or overridden)  
                xhr.status; //Numeric status code  
            },  

                url: '/SomeUrlThatMightThrowAnError'  

            });  

        });  

        return false;  

    });  

});  

Demo | Source

Thanks again to Sumit for the great idea, and to Neal and Colin for the feedback.

Erik

Share on: