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:
You can customize how Web API handles exceptions by writing an exception filter. An exception filter is executed when a controller method throws any unhandled exception that is not an HttpResponseException exception.
Approach 1: UseExceptionHandler. Switch to the production mode for the app, startup file Configure method tells us: ASP.NET Core handles exception by calling UseExceptionHandler: public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { if (env. IsDevelopment()) { app.
try catch finally 2. Use error events to deal with exceptions within the scope of an object. Page_Error Global_Error Application_Error 3. Use custom error pages to display informational messages for unhandled exceptions within the scope of a Web application.
The "catch" block is used to handle the exception. It must be preceded by try block which means we can't use catch block alone. It can be followed by finally block later. The "finally" block is used to execute the necessary code of the program.
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
:
public class PassthroughExceptionHandler : IExceptionHandler { public Task HandleAsync(ExceptionHandlerContext context, CancellationToken cancellationToken) { // don't just throw the exception; that will ruin the stack trace var info = ExceptionDispatchInfo.Capture(context.Exception); info.Throw(); return Task.CompletedTask; } }
Let that class replace the IExceptionHandler
service of Web API:
config.Services.Replace(typeof(IExceptionHandler), new PassthroughExceptionHandler());
Create a middleware class which does what I want:
public class ExceptionHandlerMiddleware { public override async Task Invoke(IOwinContext context) { try { await Next?.Invoke(context); } catch (Exception ex) { // handle and/or log } } }
Register that middleware first in the stack:
app.Use<ExceptionHandlerMiddleware>() .UseStageMarker(PipelineStage.Authenticate) // other middlewares omitted for brevity .UseStageMarker(PipelineStage.PreHandlerExecute) .UseWebApi(config);
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.)
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