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:
[Update] Altered the code with @Neal, and @Colin's feedback..
I created a filter that inherits the default [HandleError] Attribute.
{
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.
{
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:
$("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;
});
});
Thanks again to Sumit for the great idea, and to Neal and Colin for the feedback.
Erik
Trackback on 12/22/2009 9:40:07 AM - CST
QuoteReply
Twitter / Erik Zaadi: Blogged : Asp.Net MVC Exce ...
Trackback on 12/22/2009 9:51:12 AM - CST
QuoteReply
Twitter / Slobodan Pavkov: Excellent: RT @erikzaadi: ...
Trackback on 12/22/2009 10:16:01 AM - CST
QuoteReply
Twitter / Kazi Manzur Rashid: RT @erikzaadi: Blogged : A ...
Trackback on 12/22/2009 11:37:20 AM - CST
QuoteReply
Twitter Trackbacks for Asp.Net MVC Exception Handling with jQuery [erikzaadi.com] on Topsy.com
Trackback on 12/22/2009 11:42:16 AM - CST
QuoteReply
Twitter / srkirkland: Interesting idea to use Re ...
Posted by Neal Blomfield on 12/22/2009 12:14:54 PM - CST
QuoteReply
Repeating the comment I made on 2 Legged Spider because it concerns me that you don't address this particularly well.
If you are returning the stacktrace to the user you are doing it wrong. This is a classic example of something @bellware likes to describe as "geek autism". By all means catch the error, then log it somewhere and return a clean error message to the user indicating the action failed.
Posted by erikzaadi on 12/22/2009 1:02:18 PM - CST
QuoteReply
@Neal, Excellent point regarding the stacktrace, no need to transfer it to the client site unless it's in debug mode.
However, I have to emphasize that this is just a small helper for the debugging developer, the final UI shouldn't display the actual error message, just act upon the error itself. I'll update the sample, changing the default behavior to not show the stacktrace unless it's in debug mode, with some overloads. Thanks for the input. Erik
Trackback on 12/29/2009 3:09:00 AM - CST
QuoteReply
Twitter / Sumit Thomas: Asp.Net MVC Exception Hand ...
Trackback on 12/29/2009 3:24:10 AM - CST
QuoteReply
Twitter / Michael Davis: RT @2leggedspider: Asp.Net ...
Trackback on 12/29/2009 9:21:49 AM - CST
QuoteReply
Twitter / Elijah Manor: "ASP.NET MVC Exception Han ...
Trackback on 12/29/2009 12:27:53 PM - CST
QuoteReply
Twitter / Jose Basilio: RT @elijahmanor: "ASP.NET ...
Trackback on 12/31/2009 8:20:19 AM - CST
QuoteReply
Twitter / Craig Taylor: RT @bik: Asp.Net MVC Excep ...
Trackback on 1/1/2010 7:29:47 PM - CST
QuoteReply
Twitter / Abhinav Singh: "ASP.NET MVC Exception Han ...
Posted by Colin Bowern on 1/7/2010 10:33:23 AM - CST
QuoteReply
Shouldn't your content type be "text/plain"? Use System.Net.Mime.MediaTypeNames.Text.Plain to get the right one in place.
Posted by erikzaadi on 1/7/2010 12:55:00 PM - CST
QuoteReply
Thanks Colin, you're right, I'll update the snippet...
Erik
Posted by Kris-I on 1/15/2010 2:50:22 PM - CST
QuoteReply
Thanks for this article ! I need more :). In the controller methode you have a try/catch(MyPersonnalException ex), in the try, the normal way, return a View. In the catch, I'd like return a View too but an "ErrorView" to display the result in a div. How can I do this ?
FYI : tried to log with OpenId but I receive an error
Posted by erikzaadi on 1/17/2010 7:14:39 AM - CST
QuoteReply
@Kris-I I'm not sure I get what you want to do, this does not seem related to an ajax request.. Could you elaborate?
Posted by Kris-I on 1/17/2010 12:01:31 PM - CST
QuoteReply
Hello. Below a link for ASP.NET MVC controller code, an another link to the code to call the controller. I'd like using ajax to call controller, this controller return a view but this view is different is the operation is a success or generate exception.
Controller : http://pastebin.com/f5024e015 UI/Ajax : http://pastebin.com/f58990221 Question still open on stackoverflow : http://bit.ly/7c4lD9
Posted by erikzaadi on 1/20/2010 11:06:29 AM - CST
QuoteReply
Hey Kris,
If you use the [HandleErrorWithAjaxFilter] as shown in this post, you won't need to do anything. just throw the MyPersonalException. If it's a ajax request, then you'll get the correct data (and not the entire html) in the jQuery error function.
Posted by Birzhan on 4/30/2010 2:31:21 AM - CST
QuoteReply
Hello, Eric!
Thank you for such a great post, but I got one problem. I tried to embed your code into my application, and on the browser side error message was always "Internal Server Error", after it I downloaded your source and tried to launch it, and the result was the same. Error Message : Internal Server Error (instead of my exception's message). Since I don't have IIS installed on my computer due to corporate policy, I'm using ASP.NET Development Server. Could it be the cause of the problem?
Posted by erikzaadi on 4/30/2010 5:58:50 AM - CST
QuoteReply
Hey Birzhan,
I'm afraid the development server ignores the header we set in the code.. Much similar to the differences in CustomError pages etc.. You are welcome to try it out at the demo page :)
Posted by Fatih YASAR on 6/8/2010 4:13:34 AM - CST
QuoteReply
Hey,
Nice article, it would be nice if you use (int)System.Net.HttpStatusCode.InternalServerError; instead of "500".