Configurando Elmah para ASP.NET MVC y ASP.NET Web Api

Hace unos 3 años, cuando quería registrar los errores de mi aplicación, solía hacer uso de Log4Net, librería de Apache para .NET muy popular en aquel entonces. Ahora está más de moda utilizar Elmah para este cometido, debido a una serie de características que podéis revisar en su web 🙂

Cuando trabajamos únicamente con ASP.NET MVC la configuración es bastante sencilla: basta con instalar desde Nuget la librería y de manera automática incluye dentro del web.config los httpModules necesario para registrar los errores:

PM> Install-Package elmah

Sin embargo, si estamos trabajando con ASP.NET Web Api, podemos comprobar que esta configuración no le afecta y es necesario algo más.

ExceptionFilterAttribute

Cuando en ASP.NET MVC ocurre un error, la aplicación lanza un evento que es manejado por Application_Error ubicado en el Global.asax, pero no ocurre lo mismo en el caso de Web Api. Una buena práctica cuando trabajamos con ASP.NET Web Api es la implementación de un filtro para manejar las excepciones no controladas de la aplicación. Para ello, basta con crear una clase que herede de ExceptionFilterAttribute y asignar la misma a la configuración global en App_Start/WebApiConfig. En este caso, nos beneficiaremos de Elmah para registrar los errores:

using System.Web;
using System.Web.Http.Filters;
using Elmah;

namespace ElmahWebApi.Filters
{
    public class ExceptionFilter : ExceptionFilterAttribute
    {
        public override void OnException(HttpActionExecutedContext context)
        {
            ErrorLog.GetDefault(HttpContext.Current).Log(new Error(context.Exception, HttpContext.Current));
        }
    }
}

Sobrescribimos el método OnException y utilizamos Elmah para registrar el error. Acto seguido, asignamos una instancia de esta clase a la configuración global:

using System.Web.Http;
using ElmahWebApi.Filters;

namespace ElmahWebApi
{
    public static class WebApiConfig
    {
        public static void Register(HttpConfiguration config)
        {
            config.Routes.MapHttpRoute(
                name: "DefaultApi",
                routeTemplate: "api/{controller}/{id}",
                defaults: new { id = RouteParameter.Optional }
            );

            // Uncomment the following line of code to enable query support for actions with an IQueryable or IQueryable<T> return type.
            // To avoid processing unexpected or malicious queries, use the validation settings on QueryableAttribute to validate incoming queries.
            // For more information, visit http://go.microsoft.com/fwlink/?LinkId=279712.
            //config.EnableQuerySupport();

            // To disable tracing in your application, please comment out or remove the following line of code
            // For more information, refer to: http://www.asp.net/web-api

            config.EnableSystemDiagnosticsTracing();
            config.Filters.Add(new ExceptionFilter());
        }
    }
}

Para comprobar que funciona correctamente con ambas tecnologías, he modificado el controlador por defecto de ASP.NET Web Api para que lance una excepción:

        // GET api/values
        public IEnumerable<string> Get()
        {
            throw new Exception("Testing Elmah from ASP.NET Web Api!");
            return new string[] { "value1", "value2" };
        }

y he creado una nueva acción en el controlador Home de ASP.NET MVC para que haga lo propio:

        public ActionResult TestingElmah()
        {
            throw new Exception("Testing Elmah from ASP.NET MVC!");
        }

Una vez lanzados ambos errores, para acceder al registro de excepciones de Elmah basta con navegar a /elmah.axd, donde tendremos un resultado similar al siguiente:

Elmah page aspnet mvc and aspnet web api

¡Buen fin de semana!