I want to wire up exception handling in a middleware component, something like this:
public override async Task Invoke(IOwinContext context)
{
try
{
await Next.Invoke(context);
}
catch (Exception ex)
{
// Log error and return 500 response
}
}
However, some of the exceptions I would like to catch are being caught and converted to HttpErrorResponse
s by the Web API pipeline before I can get to them. In the process, I lose a lot of details about the errors, so I can't get useful stack traces when debugging etc (the debugger doesn't even stop when the exception is thrown – I have to manually step through the code and see where it fails…).
I tried adding a custom exception handler with the following implementation:
public Task HandleAsync(ExceptionHandlerContext context, CancellationToken cancellationToken)
{
var owinContext = context.Request.GetOwinContext();
owinContext.Set(Constants.ContextKeys.Exception, context.Exception);
return Task.FromResult(0);
}
registered through config.Services.Replace(typeof(IExceptionHandler), new MyExceptionHandler());
in my startup configuration, but looking at it after executing Next.Invoke(context)
through
context.Get<Exception>(Constants.ContextKeys.Exception);
still doesn't give me all the detail I want, as well as failing to stop at the fault point with the debugger.
Is there a way I can completely turn off all built-in error handling, so that my own middleware can take care of it?
Clarification, since a lot of people seem to misunderstand what I'm after:
- The built-in error handling in Web API catches some (but not all) exceptions and rewrites them into 500 responses.
- I want to catch all exceptions, do some logging, and then emit 500 responses with the information I choose (for most of them, see next bullet).
- There are also some exceptions that signal business logic faults, for which I want to return 40x errors instead.
- I want this to be at the top of the (app) pipeline, i.e. wrapping everything else in the request lifecycle
- I want to handle this using OWIN, to make it portable to a possible future self-hosted scenario (i.e. it's not written in stone that this app will always be hosted on IIS – HTTP modules, Global.asax.cs et al are not relevant here).
Best Answer
Update: I blogged about this. When researching the blog post, I found some potential for improvement; I've updated the relevant parts of this answer. For more detail on why I think this is better than all other suggestions here, or the default behavior, read the entire post :)
I have now gone with the following approach, which seems to work OK, even if not 100 % compliant with what I was looking for:
Create a class
PassthroughExceptionHandler
:Let that class replace the
IExceptionHandler
service of Web API:Create a middleware class which does what I want:
Register that middleware first in the stack:
I will still award the bounty to anyone who comes up with(bounty expired...) I'm still looking for a better solution, which, for example, breaks when an unhandled exception is thrown. (This approach makes VS break when I rethrow the exception in the handler, but the original call stack is lost; I have to set a breakpoint at the faulting line and debug again to be able to intercept the state when an exception is thrown.)