aspnetcore: Multiple calls to UseRouting breaks endpoint routing

If you have multiple calls to UseRouting, you won’t be able to pull the resolved endpoint between the two calls:

image

This is because the latter overrides the DefaultEndpointRouteBuilder set by the former call:

https://github.com/aspnet/AspNetCore/blob/33055d9a3c3a2a296dcd0152ccfe0df04b6d2109/src/Http/Routing/src/Builder/EndpointRoutingApplicationBuilderExtensions.cs#L44-L45

I think the UseRouting method should check whether the EndpointRouteBuilder key already exists and noop if it does, possibly also log a warning. The EndpointRoutingMiddleware already short-circuits in the case of multiple instances in the pipeline, so subsequent instances are effectively noops already:

https://github.com/aspnet/AspNetCore/blob/33055d9a3c3a2a296dcd0152ccfe0df04b6d2109/src/Http/Routing/src/EndpointRoutingMiddleware.cs#L49-L55

// @rynowak @khalidabuhakmeh

About this issue

  • Original URL
  • State: closed
  • Created 5 years ago
  • Reactions: 5
  • Comments: 19 (13 by maintainers)

Most upvoted comments

So, builder.Properties[EndpointRouteBuilder] getting assigned the same endpointRouteBuilder-instance that gets passed to EndpointRoutingMiddleware is critical in this case?

Yes, the first middleware gets one builder instance, which gets overwritten (thrown away) immediately. The second middleware gets a new builder instance, which is the one being picked up by UseEndpoints and filled with endpoints.

Because we’ve been discussing?

Libraries that want to provide routable functionality should plug into UseEndpoints(…) rather than trying to wrap routing.

After reading through this thread, I’m here ^^^^ - our docs include as well. I strongly discourage anyone from writing libraries that try to hide the use of routing from the user as an implementation detail.

Do you think that’s there’s still something to do here? We haven’t seen more reports of this problem, or requests for clarification, more guardrails, etc.

The problem arose when we had a shared package that does common bootstrapping tasks for our ASP.NET Core applications. That shared package was calling UseRouting while the application utilizing the package was also calling UseRouting. This lead to two calls to UseRouting which silently broke our middleware pipeline

Thanks for sharing your feedback. I’m relieved that this was just a bump in the road for you to figure out and not something more difficult to reason about.


My general thoughts on routing + libraries in case it’s useful to you…

I’d really strongly recommend not trying to hide the middleware pipeline in a library unless you’re hiding all of it. The team spent a lot of time prior to 3.0 trying to make UseRouting() OR UseEndpoints() not required - we probably evaluated 5-6 different designs. They all had problems, or caused confusion.

The challenge is that you will hit scenarios where you want to put middleware:

  • Before UseRouting
  • Between UseRouting and UseEndpoints.

Libraries that want to provide routable functionality should plug into UseEndpoints(...) rather than trying to wrap routing.