My exception logger implementing [IExceptionLogger][1]
is called twice when an exception is thrown from a controller action.
context.RequestContext.Configuration.Services.GetServices(typeof(IExceptionLogger))
this returns a single entry so I'm sure only one instance of the logger is registered. I don't want my unhandled exceptions to be logged twice and I don't think that's expected default behavior. How do I troubleshoot what causes it?
If I set a breakpoint in LogAsync()
method the callstack shows [External Code]
on both calls.
[RoutePrefix("test")]
public class MyController : ApiController
{
[HttpGet, AllowAnonymous]
[Route("test")]
public string GetTest()
{
throw new InvalidOperationException("Shit happens");
}
}
The logger is injected like this:
config.Services.Add(typeof(IExceptionLogger), new WebApiExceptionLogger());
public class WebApiExceptionLogger : IExceptionLogger
{
private readonly ILoggingService loggingService;
public WebApiExceptionLogger()
{
this.loggingService = ServiceContainer.Factory.Resolve<ILoggingService>();
}
public Task LogAsync(ExceptionLoggerContext context, CancellationToken cancellationToken)
{
this.loggingService.Log(LogLevel.Error, this.GetType().Name, context.Exception, "Ship has just happened");
return Task.FromResult(true);
}
}
Try change WebApiExceptionLogger so that it is inheriting from ExceptionLogger instead. ExceptionLogger implements a custom method called "ShouldLog" which suppresses duplicate calls. (you should NOT override this method unless you can provide similar logic). This solved the issue for me.
I think this behavior is because WebApi2 calls Log/LogAsync twice for each request when an Exception has occurred from different locations in the pipeline. Unless you have logic to handle this you will end up with duplicate log calls.
A side note about when you'd like to resolve your global exception handlers with autofac here is what you could do:
1) Make sure autofac types registration method is called first. There you typically do something like this:
builder.RegisterType<AppExceptionLogger>().AsSelf().AsImplementedInterfaces();
builder.RegisterType<AppExceptionHandler>().AsSelf().AsImplementedInterfaces();
2) Add the following to your WebApiConfig.Register(HttpConfiguration config) or the similar call you have:
// Inject our exception logger and handler (get one from DR/Autofac)
config.Services.Replace(typeof(IExceptionHandler), config.DependencyResolver.GetService(typeof(AppExceptionHandler)));
config.Services.Replace(typeof(IExceptionLogger), config.DependencyResolver.GetService(typeof(AppExceptionLogger)));
This works without OWIN but it should be fine there as well.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With