-
Notifications
You must be signed in to change notification settings - Fork 10.4k
Description
API propsal:
Background and Motivation
To support middlewares that modify routes in Minimal APIs where UseRouting is called implicitly, we want to allow UseRouting to be called more than once in the app pipeline. E.g.
// visible configuration
app.UseExceptionHandler("/error")
app.MapGet("/error", () => "oh no!");
// functional configuration
app.UseRouting(); // Implicitly added by Minimal API
app.UseExceptionHandler("/error");
app.UseRouting(); // Added by UseExceptionHandler for the error branch only
app.MapGet("/error", () => "oh no!");
To support this, we need to make a change to UseRouting()
since it overrides the EndpointRouteBuilder
in the Properties
bag of the builder: https://github.com/dotnet/aspnetcore/blob/main/src/Http/Routing/src/Builder/EndpointRoutingApplicationBuilderExtensions.cs#L48. Given this would be a breaking behaviour change, we want to add an overload that would use existing EndpointRouteBuilder
if one can be found.
Proposed API
namespace Microsoft.AspNetCore.Builder
{
public static class EndpointRoutingApplicationBuilderExtensions
{
+ public static IApplicationBuilder UseRouting(this IApplicationBuilder builder, bool overrideEndpointRouteBuilder);
}
Usage Examples
The usage pattern we expect is in middleware extensions:
public static IApplicationBuilder UseExceptionHandler(this IApplicationBuilder app, ExceptionHandlerOptions options)
{
...
return app.Use(next =>
{
...
var errorBuilder = app.New();
errorBuilder.UseRouting(overrideEndpointRouteBuilder: false);
errorBuilder.Run(next);
options.ExceptionHandler = errorBuilder.Build();
...
});
}
Alternative Designs
Risks
Is this the best way to allow recalculation of the endpoint?
Original issue:
WebApplicationBuilder
implicitly calls UseRouting()
early on in the pipeline which causes issues for middleware added by the application that re-runs the pipeline after changing the path, including UseExceptionHandler
. We likely need to revisit this behavior and potentially decide whether we also implicitly add middleware like UseDeveloperExceptionPage
and UseExceptionHandler
from WebApplicationBuilder
to resolve this kinds of ordering issues.
Consider the following app:
using System;
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.Hosting;
using Microsoft.AspNetCore.Http;
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
app.UseExceptionHandler("/error");
app.MapGet("/error", () => "oh no!");
app.MapGet("/", () => "Hello World!");
app.MapGet("/throw", IResult () =>
{
throw new Exception("bad bad");
});
app.Run();
Requests for "/" and "/error" directly from the browser work fine, but attempting to request "/throw" results in the following exception and a 500 result being returned:
fail: Microsoft.AspNetCore.Diagnostics.ExceptionHandlerMiddleware[1]
An unhandled exception has occurred while executing the request.
System.Exception: bad bad
at <Program>$.<>c.<<Main>$>b__0_2() in C:\src\local\EmptyWebExceptionHandling\Program.cs:line 20
at lambda_method3(Closure , Object , HttpContext )
at Microsoft.AspNetCore.Http.RequestDelegateFactory.<>c__DisplayClass28_0.<Create>b__0(HttpContext httpContext) in Microsoft.AspNetCore.Http.Extensions.dll:token 0x600013c+0x0
at Microsoft.AspNetCore.Routing.EndpointMiddleware.Invoke(HttpContext httpContext) in Microsoft.AspNetCore.Routing.dll:token 0x60000a8+0x7b
--- End of stack trace from previous location ---
at Microsoft.AspNetCore.Diagnostics.ExceptionHandlerMiddleware.<Invoke>g__Awaited|6_0(ExceptionHandlerMiddleware middleware, HttpContext context, Task task) in Microsoft.AspNetCore.Diagnostics.dll:token 0x60000bf+0x70
fail: Microsoft.AspNetCore.Server.Kestrel[13]
Connection id "0HMA0QQKH5H54", Request id "0HMA0QQKH5H54:00000003": An unhandled exception was thrown by the application.
System.InvalidOperationException: The exception handler configured on ExceptionHandlerOptions produced a 404 status response. This InvalidOperationException containing the original exception was thrown since this is often due to a misconfigured ExceptionHandlingPath. If the exception handler is expected to return 404 status responses then set AllowStatusCode404Response to true.
---> System.Exception: bad bad
at <Program>$.<>c.<<Main>$>b__0_2() in C:\src\local\EmptyWebExceptionHandling\Program.cs:line 20
at lambda_method3(Closure , Object , HttpContext )
at Microsoft.AspNetCore.Http.RequestDelegateFactory.<>c__DisplayClass28_0.<Create>b__0(HttpContext httpContext) in Microsoft.AspNetCore.Http.Extensions.dll:token 0x600013c+0x0
at Microsoft.AspNetCore.Routing.EndpointMiddleware.Invoke(HttpContext httpContext) in Microsoft.AspNetCore.Routing.dll:token 0x60000a8+0x7b
--- End of stack trace from previous location ---
at Microsoft.AspNetCore.Diagnostics.ExceptionHandlerMiddleware.<Invoke>g__Awaited|6_0(ExceptionHandlerMiddleware middleware, HttpContext context, Task task) in Microsoft.AspNetCore.Diagnostics.dll:token 0x60000bf+0x70
--- End of inner exception stack trace ---
at Microsoft.AspNetCore.Diagnostics.ExceptionHandlerMiddleware.HandleException(HttpContext context, ExceptionDispatchInfo edi) in Microsoft.AspNetCore.Diagnostics.dll:token 0x60000bc+0x268
at Microsoft.AspNetCore.Diagnostics.ExceptionHandlerMiddleware.<Invoke>g__Awaited|6_0(ExceptionHandlerMiddleware middleware, HttpContext context, Task task) in Microsoft.AspNetCore.Diagnostics.dll:token 0x60000bf+0xf2
at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.HttpProtocol.ProcessRequests[TContext](IHttpApplication`1 application) in Microsoft.AspNetCore.Server.Kestrel.Core.dll:token 0x6000aa6+0x1b8
Proposal:
We add UseRouting()
in the error branch. This requires a new overload to UseRouting
since the current one replaces the IEndpointRouteBuilder
here:
Current proposal: https://github.com/dotnet/aspnetcore/compare/johluo/diagnostic-option3?expand=1