Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to configure multiple exception handlers

I am trying to configure my middleware pipeline to use 2 different exception handlers to handle the same exception. For example, I'm trying to have both my custom handler and in-built DeveloperExceptionPageMiddleware as follows:

public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();                
        app.ConfigureCustomExceptionHandler();
    }
    else
    {
        app.UseExceptionHandler("/Home/Error");                               
        app.ConfigureCustomExceptionHandler();            
        app.UseHsts();
    }

    app.UseHttpsRedirection();
    app.UseStaticFiles();
    app.UseCookiePolicy();
    app.UseAuthentication();
    app.UseMvcWithDefaultRoute();
}

My objective is to have the custom handler do its own thing (logging, telemetry, etc), and then pass on (next()) to the other in-built handler which displays a page. My custom handler looks like this:

public static class ExceptionMiddlewareExtensions
{
    public static void ConfigureCustomExceptionHandler(this IApplicationBuilder app)
    {            
        app.UseExceptionHandler(appError =>
        {
            appError.Use(async (context, next) =>
            {                    
                var contextFeature = context.Features.Get<IExceptionHandlerFeature>();
                if (contextFeature != null)
                {
                    //log error / do custom stuff

                    await next();
                }
            });
        });
    }
}

I cannot get CustomExceptionHandler to pass on processing to the next middleware. I get the following page instead:

404 error:

enter image description here

I tried switching around the order, but then the developer exception page takes over and the custom exception handler is not called.

Is what I'm trying to do possible at all?

Update:

The solution was to take Simonare's original suggestion and re-throw the exception in the Invoke method. I also had to remove any type of response-meddling by replacing the following in HandleExceptionAsync method:

context.Response.ContentType = "application/json"; context.Response.StatusCode = (int)code; return context.Response.WriteAsync(result);

with:

return Task.CompletedTask;

like image 242
killswitch Avatar asked Jan 25 '19 09:01

killswitch


People also ask

How do you handle multiple exception handling?

By handling multiple exceptions, a program can respond to different exceptions without terminating it. In Python, try-except blocks can be used to catch and respond to one or multiple exceptions. In cases where a process raises more than one possible exception, they can all be handled using a single except clause.

Can we have multiple @ControllerAdvice?

I have multiple classes annotated with @ControllerAdvice , each with an @ExceptionHandler method in. One handles Exception with the intention that if no more specific handler is found, this should be used.

How can I get multiple exceptions at once?

Starting from Java 7.0, it is possible for a single catch block to catch multiple exceptions by separating each with | (pipe symbol) in the catch block. Catching multiple exceptions in a single catch block reduces code duplication and increases efficiency.

How do you write multiple excepts in Python?

Python Multiple Exception in one Except You can also have one except block handle multiple exceptions. To do this, use parentheses. Without that, the interpreter will return a syntax error.

How do you add multiple exceptions in single catch block?

Java allows you to catch multiple type exceptions in a single catch block. It was introduced in Java 7 and helps to optimize code. You can use vertical bar (|) to separate multiple exceptions in catch block.

How many exception handlers are there?

There are mainly two types of exceptions: checked and unchecked.


1 Answers

Instead of calling two different Exception Handling Middleware, you may consider to add logging under your Home/Error

[AllowAnonymous]
public IActionResult Error()
{
    //log your error here
    return View(new ErrorViewModel 
        { RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier });
}

alternatively, you can use custom Expception Handling Middleware

public class ErrorHandlingMiddleware
{
    private readonly RequestDelegate _next;

    public ErrorHandlingMiddleware(RequestDelegate next)
    {
        _next = next;
    }

    public async Task Invoke(HttpContext context, IHostingEnvironment env)
    {
        try
        {
            await _next(context);
        }
        catch (Exception ex)
        {
            if (!context.Response.HasStarted)
                await HandleExceptionAsync(context, ex, env);
            throw;
        }
    }

    private Task HandleExceptionAsync(HttpContext context, Exception exception, IHostingEnvironment env)
    {
        var code = HttpStatusCode.InternalServerError; // 500 if unexpected
        var message = exception.Message;

        switch (exception)
        {
            case NotImplementedException _:
                code = HttpStatusCode.NotImplemented; 
                break;
            //other custom exception types can be used here
            case CustomApplicationException cae: //example
                code = HttpStatusCode.BadRequest;
                break;
        }

        Log.Write(code == HttpStatusCode.InternalServerError ? LogEventLevel.Error : LogEventLevel.Warning, exception, "Exception Occured. HttpStatusCode={0}", code);


        context.Response.ContentType = "application/json";
        context.Response.StatusCode = (int)code;
        return Task.Completed;
    }
}

and Simply Register it inside IApplicationBuilder Method

  public void Configure(IApplicationBuilder app)
  {
        app.UseMiddleware<ErrorHandlingMiddleware>();
  }
like image 64
Derviş Kayımbaşıoğlu Avatar answered Sep 21 '22 15:09

Derviş Kayımbaşıoğlu