Skip to content

[Bug]: Endpoint-Routing MapSwaggerUI CatchAll Breaks #3984

@pinkfloydx33

Description

@pinkfloydx33

Describe the bug

The new Endpoint Routing-based MapSwaggerUI introduced in #3822 uses a catch-all path pattern on the sub application builder, forcing all requests with a specific prefix through the middleware. If the path can not be served by the SwaggerUI Middleware (i.e. "swagger/some-random-path.json") an Internal Server Error will be raised because the request has reached the end of the application builder pipeline without producing a result.

The request reached the end of the pipeline without executing the endpoint: 'swagger/{**path}'. 
Please register the EndpointMiddleware using 'IApplicationBuilder.UseEndpoints(...)' if using routing.

Because a wildcard route was added and it's the only endpoint on the sub-application/pipeline created by MapSwaggerUI, it is expected to produce something. SwaggerUIMiddleware invokes the next RequestDelegate if it internally does not match anything, but there's nothing to execute and thus the pipeline fails.

This doesn't happen with non-endpoint-routing usage of SwaggerUIMiddleware because there's no wildcard match involved; invoking the next delegate will run the rest of "normal" routing which will surface a 404 instead.

Note: I have not verified but I believe this also impacts MapReDoc and ReDocMiddleware

Expected behavior

Accessing a path that does not exist, should return a 404 response and not a 500 Server Error + Exception

Actual behavior

An internal server error is raised because no endpoint was executed

Steps to reproduce

  1. Add the following to an application:
app.UseEndpoints(endpoints =>
{
    endpoints.MapSwaggerUI()
        .AllowAnonymous();
});
  1. Access /swagger/i-dont-exist.json or any other URL that can't be satisfied by the SwaggerUI Middleware.
  2. Fail

Exception(s) (if any)

System.InvalidOperationException: The request reached the end of the pipeline without executing the endpoint: 'swagger/{**path}'. Please register the EndpointMiddleware using 'IApplicationBuilder.UseEndpoints(...)' if using routing.
   at Microsoft.AspNetCore.Builder.ApplicationBuilder.<>c.<Build>b__25_0(HttpContext context)
   at Swashbuckle.AspNetCore.SwaggerUI.SwaggerUIMiddleware.Invoke(HttpContext httpContext)
   at Microsoft.AspNetCore.Routing.EndpointMiddleware.<Invoke>g__AwaitRequestTask|7_0(Endpoint endpoint, Task requestTask, ILogger logger)
   at Microsoft.AspNetCore.Authorization.AuthorizationMiddleware.Invoke(HttpContext context)
   at Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext context)

Swashbuckle.AspNetCore version

10.2.1

.NET Version

10

Anything else?

I can think of at least two ways this can be solved:

  1. Add a flag on SwaggerUIOptions and/or SwaggerUIMiddleware that tells that middleware that it needs terminal behavior and should return a 404 if it cannot serve the request and then plumb that through MapSwaggerUI, etc.
  2. Change the registration of MapSwaggerUI to remove-then-restore the matched endpoint:
var pipeline = endpoints.CreateApplicationBuilder()
    .UseSwaggerUI(options)
    .Build();

return endpoints.Map(GetRoutePattern(options.RoutePrefix), async ctx => 
{
  var orig = ctx.GetEndpoint();
  ctx.SetEndpoint(null);
  await pipeline(ctx);
  ctx.SetEndpoint(orig);
});

This will cause routing to continue if the SwaggerUIMiddleware cannot handle the request. Lack of an endpoint prevents the ApplicationBuilder from throwing; instead it will produce a 404 response

Metadata

Metadata

Labels

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions