Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Disable *all* exception handling in ASP.NET Web API 2 (to make room for my own)?

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 HttpErrorResponses 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).
like image 1000
Tomas Aschan Avatar asked Dec 10 '15 12:12

Tomas Aschan


People also ask

How do you handle exceptions in Web API?

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.

How do I handle exceptions in asp net core Web API?

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.

What are the 3 approaches to handling exceptions in a web application?

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.

What are the 3 blocks used to handle exception?

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.


1 Answers

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.)

like image 82
Tomas Aschan Avatar answered Sep 21 '22 06:09

Tomas Aschan