Skip to content

Add an option on the ExceptionHandlerOptions to select status codes based on exceptions #56616

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged

Conversation

latonz
Copy link
Contributor

@latonz latonz commented Jul 3, 2024

Add an option on the ExceptionHandlerOptions to select status codes based on exceptions

Adds Func<Exception, int>? StatusCodeSelector to the ExceptionHandlerOptions which allows users to easily map an exception to a status code. The ExceptionHandlerMiddlewareImpl uses that new status code selector whenever the default status code of 500 was used and only falls back to 500 if no status code selector is set on the options.
If a status code selector is set, 404 status codes are allowed (AllowStatusCode404Response is ignored).

Fixes #44156

@latonz latonz requested a review from BrennanConroy as a code owner July 3, 2024 22:42
@ghost ghost added the area-middleware Includes: URL rewrite, redirect, response cache/compression, session, and other general middlewares label Jul 3, 2024
@dotnet-policy-service dotnet-policy-service bot added the community-contribution Indicates that the PR has been added by a community member label Jul 3, 2024
@latonz
Copy link
Contributor Author

latonz commented Jul 3, 2024

@dotnet-policy-service agree

@dotnet-policy-service dotnet-policy-service bot added the pending-ci-rerun When assigned to a PR indicates that the CI checks should be rerun label Jul 12, 2024
@adityamandaleeka
Copy link
Member

@latonz Thanks for the contribution! We'll review this soon.

}

[Fact]
public async Task ExceptionHandler_SelectsStatusCode404_When404ThrowedAndNotNotAllowed()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This test name should be changed for clarity (and for the typo 😄)... maybe just StatusCodeSelector_CanSelect404?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Renamed the test as you suggested 👍

@@ -34,4 +35,21 @@ public async Task ExceptionHandlerPage_ProducesProblemDetails()
Assert.NotNull(body);
Assert.Equal(500, body.Status);
}

[Fact]
public async Task StatusCodeSelector_ProducesProblemDetailsWith403()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
public async Task StatusCodeSelector_ProducesProblemDetailsWith403()
public async Task StatusCodeSelector_ProducesProblemDetailsWithCustomStatusCode()

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Renamed the test as requested.

@@ -17,12 +17,22 @@ public void ConfigureServices(IServiceCollection services)
public void Configure(IApplicationBuilder app)
{
// Configure the error handler to produces a ProblemDetails.
app.UseExceptionHandler();
app.UseExceptionHandler(new ExceptionHandlerOptions
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Technically this makes the other test in ExceptionHandlderTest.cs not test the default behavior. Could we change it to something like

app.Map("/throw", throwApp =>
{
    throwApp.UseExceptionHandler();
    throwApp.Map("/conflict", throwConflictApp =>
    {
        throwConflictApp.Run(_ => throw new Exception("Conflict Exception"));
    });
    throwApp.Run(_ => throw new Exception("Application Exception"));
});

app.Map("/throw2", throwApp =>
{
    throwApp.UseExceptionHandler(new ExceptionHandlerOptions
    {
        StatusCodeSelector = ex => ex is ConflictException
            ? StatusCodes.Status409Conflict
            : StatusCodes.Status500InternalServerError,
    });
    throwApp.Map("/conflict", throwConflictApp =>
    {
        throwConflictApp.Run(_ => throw new Exception("Conflict Exception"));
    });
});

So the tests can use different usages of UseExceptionHandler?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for pointing out, improved the isolation of the test as suggested.

@latonz latonz force-pushed the 44156-exception-handler-status-code-selector branch from 7f94943 to 247a948 Compare July 19, 2024 01:00
@BrennanConroy BrennanConroy removed the pending-ci-rerun When assigned to a PR indicates that the CI checks should be rerun label Jul 19, 2024
@BrennanConroy
Copy link
Member

/azp run

Copy link

Azure Pipelines successfully started running 3 pipeline(s).

@BrennanConroy BrennanConroy merged commit 137d04d into dotnet:main Jul 22, 2024
25 checks passed
@BrennanConroy
Copy link
Member

Thanks @latonz !

@dotnet-policy-service dotnet-policy-service bot added this to the 9.0-preview7 milestone Jul 22, 2024
@latonz latonz deleted the 44156-exception-handler-status-code-selector branch July 22, 2024 18:26
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area-middleware Includes: URL rewrite, redirect, response cache/compression, session, and other general middlewares community-contribution Indicates that the PR has been added by a community member
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Mapping Exception x StatusCode in ExceptionHandlerMiddleware
3 participants