dotnet / aspnetcore

ASP.NET Core is a cross-platform .NET framework for building modern cloud-based web applications on Windows, Mac, or Linux.
https://asp.net
MIT License
35.25k stars 9.96k forks source link

Breaking routing behavior between net6, net7 and net8. #50773

Open kimbell opened 1 year ago

kimbell commented 1 year ago

This little adventure started some weeks ago as we were updating our applications from .NET6 to .NET7. We have over 150 internal apps running on .NET, so we have an internal framework that handles all the common things: complete control over the middleware pipeline being one of them.

Our framework for .NET6 was still using Startup since we needed to support old .NET Framework applications as well. For .NET7, we removed .NET Framework and moved over to minimal API's setup since that is where all the cool kids are these days. During this update we discovered a routing change that was reported as #50393, but we managed to find a workaround.

With the release on .NET8 RC1, we started updating our framework to support that, and came across the same error we had on .NET7. The core of the problem is that if we use static files, UsePathBase and Razor pages with a match-all filter, then we never get static files. We always get the default Razor page.

I've been trying different things, and it just gets even more confusing. My main branch is running .NET7 and works with the workaround. I created a new branch where we multi-target .NET7 and .NET8; selecting .NET7 as the target framework and the code stops working.

One of the selling points for minimal api's was to move away from the ceremony and magic of MVC. Debugging this new minimal api magic isn't that much easier.

I've updated my repro with some tests that illustrate things: https://github.com/kimbell/RazorStatics

For .NET6, all tests are green For .NET7, static file tests only work with our workaround For .NET8, no static file tests work.

Passed!  - Failed:     0, Passed:     6, Skipped:     0, Total:     6, Duration: 361 ms - RazorStatics.Tests.dll (net6.0)
Failed!  - Failed:     2, Passed:     4, Skipped:     0, Total:     6, Duration: 273 ms - RazorStatics.Tests.dll (net7.0)
Failed!  - Failed:     4, Passed:     2, Skipped:     0, Total:     6, Duration: 320 ms - RazorStatics.Tests.dll (net8.0)
javiercn commented 1 year ago

This seems to be related to the interactions with the implicit registrations and the middleware defined on the pipeline.

For what its worth /{*path} will always match, so it comes down to whether UseStaticFiles gets to see an endpoint in the HttpContext (in which case it doesn't try to match) or not.

If you have a lot of customization in the pipeline, you might want to use the WebHostBuilder directly to exactly configure the pipeline as you need (and avoid all the global implicit middleware that we plug in on the streamlined approach).

kimbell commented 1 year ago

I added an additional test in my repro where I don't set up UsePathBase() at all. Things work fine in .NET6 and .NET7, but fail in .NET8.

Code that used to work without any problems in .NET6 got worse in .NET7 and even more worse in .NET8. If this is intentional, it's a surprising behavior.