aspnetcore icon indicating copy to clipboard operation
aspnetcore copied to clipboard

Mapping Exception x StatusCode in ExceptionHandlerMiddleware

Open brunolins16 opened this issue 2 years ago • 14 comments

Background and Motivation

In .NET 7 the ExceptionHandlerMiddleware was updated to generate a Problem Details when the IProblemDetailsService is registered.

While this change allows a consistent ProblemDetails for the application the default handler for ExceptionHandlerMiddleware always sets the response status code to 500 and changing to produce a different Status Code requires a custom implementation (as mentioned here #43831).

Proposed API

The community ProblemDetails middleware (https://github.com/khellang/Middleware) has a capability to map an Exception to Status Code when producing the payload. Since the ExceptionHandlerMiddleware is the built-in feature to handle exception, my suggestion is to add a similar feature to allow mapping exception type X status code every time an exception is handled.

namespace Microsoft.AspNetCore.Builder;

public class ExceptionHandlerOptions
{
+    public void Map<TException>(int statusCode) where TException : Exception {}
+    public bool TryGetMap(Exception exception, out int statusCode) {}
}

Usage Examples

Configuring the ExceptionHandlerOptions

var builder = WebApplication.CreateBuilder(args);

// Add services to the container.
builder.Services.AddExceptionHandler(o => 
{
    o.Map<InvalidOperationException>(400);
});

var app = builder.Build();

app.UseExceptionHandler();

app.MapGet("/", () =>
{
    throw new InvalidOperationException();
});

app.Run();

Setting ExceptionHandlerOptions directly to the middleware

var app = WebApplication.Create(args);

var options = new ExceptionHandlerOptions();
options.Map<InvalidOperationException>(400);

app.UseExceptionHandler(options);

app.MapGet("/", () =>
{
    throw new InvalidOperationException();
});

app.Run();

Alternative Designs

Alternative names

public void AddMap<TException>(int statusCode) where TException : Exception {} public void MapStatusCode<TException>(int statusCode) where TException : Exception {} public void MapToStatusCode<TException>(int statusCode) where TException : Exception {}

Using a property instead

namespace Microsoft.AspNetCore.Builder;

public class ExceptionHandlerOptions
{
+    public IDictionary<Type, int> StatusCodeMapping { get; } = new Dictionary<Type, int>();
}

The disadvantage of this design is the Dictionary potentially accepts any type, not necessarily an Exception type.

cc @khellang

brunolins16 avatar Sep 24 '22 00:09 brunolins16