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.51k stars 10.04k forks source link

Attempts to map multiple blazor entry points with MapBlazorHub causes Ambiguous Route Error. This worked with net7. #52156

Open ViperElectric opened 1 year ago

ViperElectric commented 1 year ago

Is there an existing issue for this?

Describe the bug

It looks like attempts to use MapBlazorHub more than once in an Iappicationbuilder now cause an ambiguous route error.

app.UseDeveloperExceptionPage();
app.UseMiddleware<CheckPathMiddleware>();
app.UseStaticFiles();
app.UseInvariantCulture();
app.UseRouting();
app.UseEndpoints(x =>
{
    x.MapControllers();
    x.MapRazorPages();
    x.MapBlazorHub("/Instrument/_blazor");
    x.MapBlazorHub("/App/_blazor");
    x.MapFallbackToPage("/Web");
});

This is my code where I call MapBlazorHub, this worked in .net6 and .net7 but now when I run my code with this I get an AmbiguousMatchException Error that mentions "Blazor static files"

From my digging it seems like the MapBlazorHub now maps an enpoint for _framework/blazor.server.js but because I'm calling MapBlazorHub twice it's mapping a duplicate enpoint which breaks the application.

This is an application that runs on a piece of hardware with a display and we are using the /Instrument endpoint for the display output on the hardware and the App endpoint for a webpage that can be reached via USB.

Expected Behavior

I would expect that if MapBlazorHub is called more than once the _framework/blazor.server.js endpoint would not be mapped twice to prevent this duplicate route issue.

Steps To Reproduce

Call MapBlazorHub on two different entry points after updating to .net8

Exceptions (if any)

Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware: Error: An unhandled exception has occurred while executing the request.

Microsoft.AspNetCore.Routing.Matching.AmbiguousMatchException: The request matched multiple endpoints. Matches:

Blazor static files Blazor static files at Microsoft.AspNetCore.Routing.Matching.DefaultEndpointSelector.ReportAmbiguity(Span1 candidateState) at Microsoft.AspNetCore.Routing.Matching.DefaultEndpointSelector.ProcessFinalCandidates(HttpContext httpContext, Span1 candidateState) at Microsoft.AspNetCore.Routing.Matching.DefaultEndpointSelector.Select(HttpContext httpContext, Span`1 candidateState) at Microsoft.AspNetCore.Routing.Matching.DefaultEndpointSelector.SelectAsync(HttpContext httpContext, CandidateSet candidateSet) at Microsoft.AspNetCore.Routing.Matching.DfaMatcher.SelectEndpointWithPoliciesAsync(HttpContext httpContext, IEndpointSelectorPolicy[] policies, CandidateSet candidateSet) at Microsoft.AspNetCore.Routing.EndpointRoutingMiddleware.g__AwaitMatch|10_1(EndpointRoutingMiddleware middleware, HttpContext httpContext, Task matchTask) at Microsoft.AspNetCore.Localization.RequestLocalizationMiddleware.Invoke(HttpContext context) at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddlewareImpl.Invoke(HttpContext context)

.NET Version

8.0.100

Anything else?

dotnet --info .NET SDK: Version: 8.0.100 Commit: 57efcf1350 Workload version: 8.0.100-manifests.8d38d0cc

Runtime Environment: OS Name: Windows OS Version: 10.0.22621 OS Platform: Windows RID: win-x64 Base Path: C:\Program Files\dotnet\sdk\8.0.100\

.NET workloads installed: Workload version: 8.0.100-manifests.8d38d0cc [maui] Installation Source: SDK 8.0.100 Manifest Version: 8.0.3/8.0.100 Manifest Path: C:\Program Files\dotnet\sdk-manifests\8.0.100\microsoft.net.sdk.maui\8.0.3\WorkloadManifest.json Install Type: Msi

[android] Installation Source: VS 17.8.34309.116 Manifest Version: 34.0.43/8.0.100 Manifest Path: C:\Program Files\dotnet\sdk-manifests\8.0.100\microsoft.net.sdk.android\34.0.43\WorkloadManifest.json Install Type: Msi

[maui-windows] Installation Source: VS 17.8.34309.116 Manifest Version: 8.0.3/8.0.100 Manifest Path: C:\Program Files\dotnet\sdk-manifests\8.0.100\microsoft.net.sdk.maui\8.0.3\WorkloadManifest.json Install Type: Msi

[wasm-tools-net6] Installation Source: VS 17.8.34309.116 Manifest Version: 8.0.0/8.0.100 Manifest Path: C:\Program Files\dotnet\sdk-manifests\8.0.100\microsoft.net.workload.mono.toolchain.net6\8.0.0\WorkloadManifest.json Install Type: Msi

[maccatalyst] Installation Source: VS 17.8.34309.116 Manifest Version: 17.0.8478/8.0.100 Manifest Path: C:\Program Files\dotnet\sdk-manifests\8.0.100\microsoft.net.sdk.maccatalyst\17.0.8478\WorkloadManifest.json Install Type: Msi

[ios] Installation Source: VS 17.8.34309.116 Manifest Version: 17.0.8478/8.0.100 Manifest Path: C:\Program Files\dotnet\sdk-manifests\8.0.100\microsoft.net.sdk.ios\17.0.8478\WorkloadManifest.json Install Type: Msi

Host: Version: 8.0.0 Architecture: x64 Commit: 5535e31a71

.NET SDKs installed: 6.0.414 [C:\Program Files\dotnet\sdk] 8.0.100 [C:\Program Files\dotnet\sdk]

.NET runtimes installed: Microsoft.AspNetCore.App 6.0.22 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App] Microsoft.AspNetCore.App 6.0.25 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App] Microsoft.AspNetCore.App 7.0.14 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App] Microsoft.AspNetCore.App 8.0.0 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App] Microsoft.NETCore.App 6.0.22 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App] Microsoft.NETCore.App 6.0.25 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App] Microsoft.NETCore.App 7.0.14 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App] Microsoft.NETCore.App 8.0.0 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App] Microsoft.WindowsDesktop.App 6.0.22 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App] Microsoft.WindowsDesktop.App 6.0.25 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App] Microsoft.WindowsDesktop.App 7.0.14 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App] Microsoft.WindowsDesktop.App 8.0.0 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]

Other architectures found: x86 [C:\Program Files (x86)\dotnet] registered at [HKLM\SOFTWARE\dotnet\Setup\InstalledVersions\x86\InstallLocation]

Environment variables: Not set

global.json file: Not found

ralfbalzer commented 1 year ago

I am having the same issue. My current BlazorHubs are configured as follows:

_app.MapBlazorHub("/bookingengine/_blazor"); _app.MapBlazorHub("/propertymanagement/_blazor"); _app.MapFallbackToPage("~/bookingengine/{*clientroutes:nonfile}", "/_HostBe"); _app.MapFallbackToPage("~/propertymanagement/{*clientroutes:nonfile}", "/_HostHv");

After upgrading to Version 8, I am getting "multiple endpoints match" error.

softwaretirol commented 11 months ago

We have the same problem

ralfbalzer commented 11 months ago

I am having the same issue. My current BlazorHubs are configured as follows:

_app.MapBlazorHub("/bookingengine/_blazor"); _app.MapBlazorHub("/propertymanagement/_blazor"); _app.MapFallbackToPage("~/bookingengine/{*clientroutes:nonfile}", "/_HostBe"); _app.MapFallbackToPage("~/propertymanagement/{*clientroutes:nonfile}", "/_HostHv");

After upgrading to Version 8, I am getting "multiple endpoints match" error.

I actually managed to work aournd this. The main reason why I had two Blazor Apps in Version 7 was, that there was no way to apply a different layout (at least I couldn't find one). As I needed a different layout for each of the apps, I created two.

The changes made in Version 8 have made it now possible, to create a page for each of my Apps and use the @layout directive, to apply the layout I need.

ElliottBrand commented 11 months ago

I'm also having this issue. My setup looks similar to this:

endpoints.MapBlazorHub();
endpoints.MapBlazorHub("/admin/_blazor");
endpoints.MapFallbackToPage("/_Host");
endpoints.MapFallbackToAreaPage("/admin/{*clientroutes:nonfile}", "/_AdminHost", "Admin");
ElliottBrand commented 11 months ago

This is what ended up working for me. I removed both the extra MapFallbackToAreaPage (or MapFallbackToPage for some cases) and the extra MapBlazorHub from the app.UseEndpoints() section, then added the following just above the app.UseEndpoints() section:

app.Map("/admin", builder =>
{
    // This helped with my static files not being referenced at the correct path.
    builder.Use(next => context =>
    {
        // Set endpoint to null so the static files middleware will handle the request.
        context.SetEndpoint(null);

        return next(context);
    });

    builder.UsePathBase("/admin/");
    builder.UseRouting();
    builder.UseEndpoints(endpoints =>
    {
        endpoints.MapBlazorHub();
        endpoints.MapFallbackToAreaPage("/_AdminHost", "Admin");
    });
});

Reference:

halter73 commented 8 months ago

There have been several workarounds mentioned earlier in the thread. If you can rearchitect your app to use a single hub with multiple root components with different layouts, that's great.

The simpler fix, since the endpoint that is ambiguous is the identical _framework/blazor.server.js endpoint, is preferring one set of endpoints over the other. The lower Order has a higher precedence, so the following basically says where there are conflicting endpoints, prefer the one defined by MapBlazorHub("/App/_blazor").

app.MapBlazorHub("/Instrument/_blazor");
app.MapBlazorHub("/App/_blazor").WithOrder(-1);

See https://github.com/dotnet/aspnetcore/issues/51698 for more info.

While it would be nice to detect if there was an endpoint conflict and not re-add an endpoint, I'm not sure how reliably we can determine if the endpoints are truly identical. And if they're not, which endpoint to prefer. Someone might configure auth on one endpoint and not the other. And while not requiring auth would probably be the least breaking in this case, it would also be the most risky.

Although there has been the suggestion of adding [AllowAnonymous] to the _framework/blazor.server.js endpoint by default or at least making it opt-in in https://github.com/dotnet/aspnetcore/issues/39321. None of this will be done in a patch though, so I'm moving this to .NET 9 planning.

ViperElectric commented 8 months ago

Rearchitecting the app unfortunately is not an option at the moment, however we will give setting the order a try and see if we can make that work. Thanks for the information.

jvelezc commented 4 months ago

I have no idea why this worked... app.MapBlazorHub("APP"); I just gave it random name and now it doesn't conflict.