In ASP.NET MVC (versions 1 to 3) we have the [HandleError] attribute, that will allow us to handle errors in a very easy way.
Just by decorating an action (or controller if we want to extend HandleError behaviour to all actions on that controller) with the HandleError attribute and enabling “CustomErrors” in web.config, we get a nice redirection to a friendly view in case an unhandled error raises.
Internally, we could have a look at the implementation of OnException method inside HandleError using Reflector to see how it works:
As we can see, the unhandled exception will be handled if it hasn't been already marked as "handled" and if custom error handling is enabled .
Web.config customErrors section
The CustomErrors section allow us to define automatic error handling behaviour. If it doesn't exists, it must be created inside system.web section. as shown here:
Posible values for mode are "Off | On | RemoteOnly". This will allow us to easy define behaviour for development and production scenarios :
· On: custom error handling enabled
· Off: custom error handling disabled. If an error is raised, we will see the yellow screen of death of ASP.NET
· RemoteOnly: if we launch the application in the local server (targeting http://localhost ), we won't see custom errors. If we access the application from other machine, we will see custom erros. This option is used by developers to debug applications. If there is an error, you can always (among other things) RD to your server and launch the application in a local browser so you see the exception in a first seat.
Behaviour:
· If we use the HandleError attribute and CustomErrors is enabled, when an unhandled error raises, the MVC runtimewill look for a “Errors.aspx” view in the context of the HttpRequest being processed (current view folder associated to controller or shared view folder), and will render it. In this case the "defaultredirect" and "redirect" CustomErrors attributes are ignored
· If we don't use the HandleError attribute and CustomErrors is enabled , we will get an HTTP redirection to the url defined on the "redirect" and "defaultredirect" attributes, within the CustomErrors section in web.config (in our case, /Error/General
Important: ASP.NET MVC3, registers the HandleError attribute globally (for all controllers) !! (see image). Take that into account so you don't think your MVC3 controlleris not using the HandleError attribute (by default it is). In previous versions of ASP.NET MVC, where we didn't have global filters, the HandleError attribute had to be defined manually for each action or controller.
Also important: If you have enabled CustomErrors=On , also added the [HandleError ] and still get a yellow screen of death please make sure the Error.aspx has no errors (check master page and the errors.aspx code) , it may have an error (this is pretty common scenario and difficult to debug).You can check if this is happening simple by temporaly removing all Error.aspx code and replacing by a text (más información).
To avoid showing ASP.NET yellow screen of death if your Error.aspx has errors, use "redirect" CustomErrros attribute to show a static html page.
Controller OnException
Alternatively to HandleError, we can also override the OnException method of a controller (or all of them if we use a base controller class).
An example of exception handling, logging and redirection to friendly message would be:
Note: the OnException event is executed independly of the use of HandleError in the controler.
Using Elmah to intercept, log and notify of unhandled errors
Elmah is a fantastic library that help us to intercept, register (in the desired format: database, text file, xml, etc) and optionally deliverunhandled errors ocurred in our application, so we keep everything in control at all times. It also provieds a web interface so you can access the error records remotely, and a RSS feed so you can subscribe with your favorite RSS reader.
With NuGet , a library package manager, available with ASP.NET MVC3, install Elmah is a pretty straightforward process. First step is launching NuGet:
Then, we search for "Elmah":
and proceed to install it. NuGet will handle for us the necessary steps required to install and configure it (in previous versions of ASP.NET MVC we had to do it manuall). NuGet does for us:
· downloads the last version from the oficial repository
· adds the assembly reference to our project
· modifies the web.config to add the proper configuration parameters
In our case, Elmah needs some parameters and configuration sections (httpModules,httpHandlers, etc) in order to work del web.config :
If we want Elmah to record errors or events in XML files inside a certain directory , we have to indicate it::
And that's it.. When an unhandled error is raised, Elmah will be able to intercept it and record it, and also send an email to the administrator.
Registering with Elmah custom events and errors
Elmah offers an API so we can record or own events or exceptions . We can use that funcionality to log exceptions that we have already handled with our code. Example:
Elmah and HandleError
Elmah works perfectly with unhandled exceptions (yellow screen of death), but won't be able to intercept exceptions that are being handled by the [HandleError] attribute.
To fix this, we need to create a custom HandleError attribute and add a custom behaviour to the new attribute.
More details and source code here: http://stackoverflow.com/questions/766610/how-to-get-elmah-to-work-with-asp-net-mvc-handleerror-attribute
Filtering unwanted events in Elmah
If Elmah is logging too many stuff, (ex: 404 errors looking for favicon.ico), I have the posibility of applying custom filters to those unwanted events .
First, we must add the Elmah ErrorFilter module to web.config:
Once registered, we implement the following events on Global.asax.cs, defining the filtering rules I want to apply:
Final notes
In my particular experience, I found the best practice to use the custom HandleError as shown in the last part of this article (having the HandleError applied globaly) with CustomErrors enabled, helped by Elmah to handle, register and send unhandled exceptions . When necessary, I use the Elmah signal capabilities for those handled exceptions I want to log.