May 03 2014

Web API 2 + ELMAH - Log ALL Unhandled Exceptions

Solution available on GitHub at https://github.com/cornflourblue/elmah-web-api-log-all-exceptions

I got an email from a client today about an error happening in an application that I'd built with ASP.NET Web API 2.1. At first I thought they must be mistaken or doing something wrong on their end because their weren't any errors being reported by ELMAH which I'd configured in my WebApiConfig.cs file using the ElmahHandleErrorApiAttribute filter.

To my surprise and disappointment when I stepped through the code in debug, I found there was in fact an error occurring during the response content serialization (the return Ok(viewModel)) step in my controller and it wasn't being caught by ELMAH. The exception message was "ExceptionMessage":"The 'ObjectContent`1' type failed to serialize the response body for content type 'application/json; charset=utf-8'.".

After some digging around I found that the ElmahHandleErrorApiAttribute filter doesn't catch all exceptions, specifically it misses the following:

  • Exceptions thrown from controller constructors.
  • Exceptions thrown from message handlers.
  • Exceptions thrown during routing.
  • Exceptions thrown during response content serialization.


The way to fix this and get ELMAH to log ALL exceptions is to use the new Global Error Handling feature in ASP.NET Web API 2.1, which is done by adding an exception logger that logs all unhandled exceptions to ELMAH. Conveniently there is one ready to go called ElmahExceptionLogger that comes with the NuGet package Elmah.Contrib.WebApi.

So the steps to set it up are:

  1. Install the package elmah using NuGet
  2. Install the package Elmah.Contrib.WebApi using NuGet
  3. Update your WebApiConfig.cs file with the following:
public static class WebApiConfig
{
    public static void Register(HttpConfiguration config)
    {
        // enable elmah
        config.Services.Add(typeof(IExceptionLogger), new ElmahExceptionLogger());

        ...
    }
}


Here's a couple of links if you're interested in reading up more about the new features in ASP.NET Web API 2.1 or Web API Global Error Handling:

 

UPDATE 6 Nov 2015:

Logging 404 errors to ELMAH from Web API

It turns out that 404 errors are treated a bit differently in Web API, they bypass the usual request pipeline and are sent directly to the browser before ELMAH knows anything about them.

So in order to log 404 errors with ELMAH you need to add a 'catch all' route as the last route in your WebApiConfig to log the errors manually.

Here's the catch all route from the example solution, it maps to the NotFound action method of the ErrorController:

// catch all route mapped to ErrorController so 404 errors
// can be logged in elmah
config.Routes.MapHttpRoute(
    name: "NotFound",
    routeTemplate: "{*path}",
    defaults: new { controller = "Error", action = "NotFound" }
);

 

This is the ErrorController that logs the 404 error to ELMAH and returns a 404 NotFound response to the browser:

public class ErrorController : ApiController
{
    [HttpGet, HttpPost, HttpPut, HttpDelete, HttpHead, HttpOptions]
    public IHttpActionResult NotFound(string path)
    {
        // log error to ELMAH
        Elmah.ErrorSignal.FromCurrentContext().Raise(new HttpException(404, "404 Not Found: /" + path));

        // return 404
        return NotFound();
    }
}

 

The full solution is available on GitHub at https://github.com/cornflourblue/elmah-web-api-log-all-exceptions


Sponsored by