EBarr
EBarr

Reputation: 12026

Exception handling beyond Exception Filters?

Using Asp.net WebApi (RC), how can I catch errors that are not caught by Exception Filters or Application_Error() in global.asax?

With both of these in place it seems that there is a class of exceptions still not covered. For example: ApiControllerActionSelector_AmbiguousMatch error (Multiple actions were found that match the request: {0}).

I'm not specifically concerned about the above error, this error just pointed out that there is a class of errors that aren't being caught by either my Exception Filter or Application_Error method.

So how can I cover all my bases?

Upvotes: 1

Views: 1055

Answers (2)

Sixto Saez
Sixto Saez

Reputation: 12680

You're right, there are several classes of exception not trapped by either Application_Error or ExceptionFilter. The Web API request pipeline is processed separately from the ASP.NET MVC pipeline (at least through MVC 4) so the MVC Application_Error doesn't kick-in. Also, if your application throws HttpResponseException type exceptions, they will not be caught by an ExceptionFilter by design (see the ExceptionFilter paragraph). To access all exceptions thrown by your code, you'll need to create a DelegatingHandler along the lines of this code:

public class ResponseExceptionTrapper : DelegatingHandler
{
    protected override Task<HttpResponseMessage> SendAsync(
        HttpRequestMessage request,
        CancellationToken cancellationToken)
    {
        return base
            .SendAsync(request, cancellationToken)
            .ContinueWith(response =>
                 {
                     var result = response.Result;
                     if (!result.IsSuccessStatusCode)
                     {
                          var exceptionResult = string.Format(
                               "Response exception: Path({0}) Status({1}) ",
                               request.RequestUri,
                               result.StatusCode);

                          if (result.Content != null)
                          {
                               var exceptionReadTask =
                                      result.Content.ReadAsStringAsync();

                               exceptionReadTask.Wait();
                               exceptionResult += "Message:\n\r" +
                                                 exceptionReadTask.Result;
                           }

                           // Do something appropriate with exceptionResult
                      }

                      return result;
                 }, cancellationToken);
    }
}

You can wire up the handler with this line in your global config logic:

GlobalConfiguration.Configuration.MessageHandlers.Add(
     new ResponseExceptionTrapper());

Upvotes: 3

Chris
Chris

Reputation: 772

I believe that Exception Filters only get called once the action is invoked (in which case there is a try/catch around it). The Ambiguous match error would pop up before that in the pipeline and there could be other errors that pop up after that (e.g. a formatter error) as you mention.

I'm not sure you can have one solution to address all of the aspects (since the hosting implementation can vary), but you could try overriding the HttpControllerDispatcher. This class is one of the "root" classes used in the pipeline. Specifically, you could override SendAsync to do your try/catch and handle accordingly.

Upvotes: 2

Related Questions