4

Code to demonstrate the problem:

  • Assume Test Thing is an real implementation, such as DB invocation.
  • The documentation for Web API states that unhanded exceptions will be caught in a global handler allowing you to process them.
  • If I replace MyErrorHandler with an ExceptionFilter this does indeed work, except the code base I'm working with uses handlers because the error logic is a cross cutting concern and will be the same regardless of where the error came from.
  • If the type of exception thrown is not a TaskCancelledException this invokes the handler as expected.
  • I've tried the latest version of Web API too (5.2.3).
  • The only work around is to add a try/catch block around everywhere that can throw this type of exception, needless to say this is painful and something I wish to avoid hence the use of the handler.

I hate to call this a bug given this is not my code, but after hours of attempts it's starting to feel that way.

using System;
using System.Net;
using System.Threading;
using System.Threading.Tasks;
using System.Web.Http;
using System.Web.Http.ExceptionHandling;

namespace WebApplication3.Controllers
{
    public class TestController : ApiController
    {
        public async Task<string> Get()
        {
            var cancellationTokenSource = new CancellationTokenSource(TimeSpan.FromSeconds(1));
            return await new TestThing().ExecuteAsync(cancellationTokenSource.Token);
        }
    }

    public class MyErrorHandler : ExceptionHandler
    {
        public override Task HandleAsync(ExceptionHandlerContext context, CancellationToken cancellationToken)
        {
            throw new HttpResponseException(HttpStatusCode.InternalServerError);
        }
    }


    public class TestThing
    {
        public async Task<string> ExecuteAsync(CancellationToken cancellationToken)
        {
            // Remove this to see the problem, I don't want to add these
            // try/catch statements all over the codebase.
            try
            {
                await Task.Delay(TimeSpan.FromMinutes(1), cancellationToken);
            }
            catch (Exception ex)
            {
                throw new Exception("Failure...");
            }

            return await Task.FromResult("Testing...");
        }
    }
}
Finglas
  • 15,518
  • 10
  • 56
  • 89
  • Does this help? [WebApi v2 ExceptionHandler not called](http://stackoverflow.com/questions/22169889/webapi-v2-exceptionhandler-not-called) – Absolom Sep 14 '15 at 16:36

2 Answers2

2

Given the lack of suggestions or answers I went with a custom message handler.

    public class AsyncFixHandler : DelegatingHandler
    {
        protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
        {
            try
            {
                return await base.SendAsync(request, cancellationToken);
            }
            catch (TaskCanceledException)
            {
                // TODO: Log the issue here
                return new HttpResponseMessage(HttpStatusCode.InternalServerError);
            }
        }
    }

This isn't ideal, but the try/catch is in one place. I'm using this successfully as the solution until something better comes along.

Finglas
  • 15,518
  • 10
  • 56
  • 89
  • Thanks for this workaround. For others who, like me, want their global exception handler and logger to be engaged, simply throw a new replacement exception instead of returning an HttpResponseMessage – BCA Jul 02 '16 at 15:18
1

It seems like it's and old bug, and there are some people reporting issues still. I suggest you to create an issue in ASP.NET Github repo and use your workaround or another one for the moment.

Community
  • 1
  • 1
Hernan Guzman
  • 1,235
  • 8
  • 14
  • 1
    Thanks for the link to the bug report, I never found that in my many attempts to solve/research this. I can confirm this is still a problem in 5.2.3 though :( – Finglas Sep 17 '15 at 06:39