Last Wednesday, I took a whopping 15 minutes out of my day and added ELMAH (Error Logging Modules and Handlers) to my ASP.NET MVC application. If you haven’t heard the news (I hadn’t until recently), ELMAH does a killer job of logging and reporting nearly all unhandled exceptions. As for handled exceptions, I’ve been using NLog but since I was already playing with the ELMAH bits I thought I’d see if I couldn’t replace it.
Atif Aziz provided a quick solution in his answer to a Stack Overflow question. I’ll let you consult his answer to see how one can subclass the HandleErrorAttribute and override the OnException method in order to get the bits working. I pretty much took rolled the recommended logic into my application and it worked like a charm.
Along the way, I did uncover a few HandleError fact to which I wasn’t already privy. Most of my learning came from Steven Sanderson’s book, Pro ASP.NET MVC Framework. I’ve flipped through a bunch of the book and spent time on specific sections. It’s a really good read if you’re looking to pick up an ASP.NET MVC reference.
Anyway, my notes are found a comments in the following code snippet. I hope my notes clarify a few things for you too.
public class LogAndHandleErrorAttribute : HandleErrorAttribute
{
public override void OnException(ExceptionContext context)
{
// A word from our sponsors:
// http://stackoverflow.com/questions/766610/how-to-get-elmah-to-work-with-asp-net-mvc-handleerror-attribute
// and Pro ASP.NET MVC Framework by Steven Sanderson
//
// Invoke the base implementation first. This should mark context.ExceptionHandled = true
// which stops ASP.NET from producing a "yellow screen of death." This also sets the
// Http StatusCode to 500 (internal server error.)
//
// Assuming Custom Errors aren't off, the base implementation will trigger the application
// to ultimately render the "Error" view from one of the following locations:
//
// 1. ~/Views/Controller/Error.aspx
// 2. ~/Views/Controller/Error.ascx
// 3. ~/Views/Shared/Error.aspx
// 4. ~/Views/Shared/Error.ascx
//
// "Error" is the default view, however, a specific view may be provided as an Attribute property.
// A notable point is the Custom Errors defaultRedirect is not considered in the redirection plan.
base.OnException(context);
var e = context.Exception;
// If the exception is unhandled, simply return and let Elmah handle the unhandled exception.
// Otherwise, try to use error signaling which involves the fully configured pipeline like logging,
// mailing, filtering and what have you). Failing that, see if the error should be filtered.
// If not, the error simply logged the exception.
if (!context.ExceptionHandled
|| RaiseErrorSignal(e)
|| IsFiltered(context))
return;
LogException(e); // FYI. Simple Elmah logging doesn't handle mail notifications.
}