I have code in the global.asax
file's Application_Error
event which executes when an error occurs and emails details of the error to myself.
void Application_Error(object sender, EventArgs e)
{
var error = Server.GetLastError();
if (error.Message != "Not Found")
{
// Send email here...
}
}
This works fine when I'm running it in Visual Studio, however when I publish to our live server the Application_Error
event does not fire.
After some testing I can get the Application_Error
firing when I set customErrors="Off"
, however setting it back to customErrors="On"
stops the event from firing again.
Can anyone suggest why Application_Error
would not be firing when customErrors
are enabled in the web.config
?
I was having the same problem where
Application_Error()
wasn't getting hit. I tried everything, until finally I stepped through what was happening. I had some custom code in an ELMAH event that was adding JSON to the email it sends, and there was a null error in there!Fixing the internal error allowed the code to continue on to the
Application_Error()
event as expected.UPDATE
Since this answer does provide a solution, I will not edit it, but I have found a much cleaner way of solving this problem. See my other answer for details...
Original Answer:
I figured out why the
Application_Error()
method is not being invoked...Global.asax.cs
By default (when a new project is generated), an MVC application has some logic in the
Global.asax.cs
file. This logic is used for mapping routes and registering filters. By default, it only registers one filter: aHandleErrorAttribute
filter. When customErrors are on (or through remote requests when it is set to RemoteOnly), the HandleErrorAttribute tells MVC to look for an Error view and it never calls theApplication_Error()
method. I couldn't find documentation of this but it is explained in this answer on programmers.stackexchange.com.To get the ApplicationError() method called for every unhandled exception, simple remove the line which registers the HandleErrorAttribute filter.
Now the problem is: How to configure the customErrors to get what you want...
The customErrors section defaults to
redirectMode="ResponseRedirect"
. You can specify the defaultRedirect attribute to be a MVC route too. I created an ErrorController which was very simple and changed my web.config to look like this...web.config
The problem with this solution is that it does a 302 redirect to your error URLs and then those pages respond with a 200 status code. This leads to Google indexing the error pages which is bad. It also isn't very conformant to the HTTP spec. What I wanted to do was not redirect, and overrite the original response with my custom error views.
I tried to change
redirectMode="ResponseRewrite"
. Unfortunately, this option does not support MVC routes, only static HTML pages or ASPX. I tried to use an static HTML page at first but the response code was still 200 but, at least it didn't redirect. I then got an idea from this answer...I decided to give up on MVC for error handling. I created an
Error.aspx
and aPageNotFound.aspx
. These pages were very simple but they had one piece of magic...This block tells the page to be served with the correct status code. Of coarse, on the PageNotFound.aspx page, I used
HttpStatusCode.NotFound
instead. I changed my web.config to look like this...It all worked perfectly!
Summary:
filters.Add(new HandleErrorAttribute());
Application_Error()
method to log exceptionsThere are a couple downsides I have noticed with this solution.
There are work-arounds for these problems but I wasn't concerned enough by them to do any extra work.
I hope this helps everyone!
As far as I know, you are passing control over to the Page specified in the url parameter and your event notification would sit in here, rather than Application_Error
A lot of information can be found here: http://support.microsoft.com/kb/306355
I solved this by creating an ExceptionFilter and logging the error there instead of Application_Error. All you need to do is add a call to in in RegisterGlobalFilters
log4netExceptionFilter.cs
Global.asax.cs
To get around this I ended up leaving customerrors disabled and handling all errors from the Application_Error event in global.asax. It's slightly tricky with MVC as I didn't want to return a 301 redirect, I wanted to return suitable error codes. More details can be viewed on my blog at http://www.wduffy.co.uk/blog/using-application_error-in-asp-net-mvcs-global-asax-to-handle-errors/ but the final code is listed below...
And here is the controller
I like Mark's answer with the ExceptionFilter, but another option, if you have all your controllers derive from the same base controller, is to simply override OnException in your base controller. You can do your logging and emailing there. This has the advantage of being able to use whatever dependencies you've already got injected into your base controller with your IoC container.
You can still use your IoC with an IExceptionFilter, but it's a bit more tricky to configure your bindings.