Blazor Server behind reverse-proxy is case sensitive when app base path is changed
See original GitHub issueIs there an existing issue for this?
- I have searched the existing issues
Describe the bug
I’m trying to host a Blazor Server behind Azure Front Door and noticed issues around case sensitivity for the app base path. Basically I set the base path for ANC using app.UsePathBase("/foo")
in Program.cs
and then have a routing rule matching /foo/*
and /foo/
in Azure Front Door which will forward to the Blazor server app (hosted on Azure App Services).
Every thing works fine when I navigate to https://example.com/foo/
. But when I navigate to https://example.com/FoO/
Blazor will fail to initialize the circuit, and in developer tools I can see the following logs. No exceptions or anything on the server though.
[2022-01-12T18:49:30.095Z] Error: The circuit failed to initialize. blazor.server.js:1:115531
[2022-01-12T18:49:30.096Z] Information: Connection disconnected. blazor.server.js:1:36859
Uncaught (in promise) Error: Invocation canceled due to the underlying connection being closed.
After adjusting log level on the server side I saw the following log which caught my eye:
Received hub invocation: InvocationMessage {
InvocationId: "0",
Target: "StartCircuit",
Arguments: [
https://example.com/foo/,
https://example.com/FoO/,
[{"type":"server","sequence":0,"descriptor":"..."},{"type":"server","sequence":1,"descriptor":"..."}],
], StreamIds: [ ]
}.
I think that the case mismatch in baseUri
(https://example.com/foo/
) and uri
(https://example.com/FoO/
) is because Azure Front Door will forward according to the matching rules (which are case-insensitive). So because the matching rule is /foo
the forwarded path will be /foo
. The uri
I believe is just location.href
in Blazor JS side.
After following the code I noticed that the case mismatch above will lead to an exception in NavigationManager
.
The URI 'https://example.com/FoO/' is not contained by the base URI 'https://example/foo/'.
https://github.com/dotnet/aspnetcore/blob/v6.0.0/src/Components/Server/src/ComponentHub.cs#L133 https://github.com/dotnet/aspnetcore/blob/v6.0.0/src/Components/Server/src/Circuits/CircuitFactory.cs#L63 https://github.com/dotnet/aspnetcore/blob/v6.0.0/src/Components/Components/src/NavigationManager.cs#L161 https://github.com/dotnet/aspnetcore/blob/v6.0.0/src/Components/Components/src/NavigationManager.cs#L82 https://github.com/dotnet/aspnetcore/blob/v6.0.0/src/Components/Components/src/NavigationManager.cs#L305
The case mismatch will NOT happen if i navigate directly to the Azure App Service. StartCircuit
is invoked with arguments https://example.com/FoO/, https://example.com/FoO/, [....]
Expected Behavior
Path should be case-insensitive when hosted behind a reverse-proxy.
Steps To Reproduce
EDIT: Added local repro code using YARP. See https://github.com/bjorkstromm/aspnetcore-blazor-repro-issue-39469
- Create new Blazor Server App
- Add Azure SignalR (needed when using behind Azure Front Door)
a) Install NuGet package
Microsoft.Azure.SignalR
b) Addbuilder.Services.AddSignalR().AddAzureSignalR();
toProgram.cs
- Adjust base path
a)
app.UsePathBase("/foo");
toProgram.cs
- Publish to Azure App Service
- Create Azure Front Door and configure
a) Add backend pool, point to Azure App Service
b) Add routing rule with match patterns
/foo/
and/foo/*
which forwards to backend pool created in previous step.
If above steps are not enough, I could either try creating a minimal repro with Bicep templates, or if possible try to reproduce everything locally using YARP instead of Azure Front Door. Let me know if you need more info.
The root cause however is simple to reproduce (NavigationManager throwing exception):
var foo = new FooNavigatioManager();
foo.Init("https://example.com/foo/", "https://example.com/FoO/");
class FooNavigatioManager : NavigationManager
{
public void Init(string baseUri, string uri) => Initialize(baseUri, uri);
}
Exceptions (if any)
The URI 'https://example.com/FoO/' is not contained by the base URI 'https://example/foo/'.
But it’s actually swallowed here: https://github.com/dotnet/aspnetcore/blob/v6.0.0/src/Components/Server/src/ComponentHub.cs#L158
.NET Version
6.0.100
Anything else?
Related https://github.com/dotnet/aspnetcore/issues/23107 https://github.com/dotnet/aspnetcore/issues/6818
Issue Analytics
- State:
- Created 2 years ago
- Reactions:1
- Comments:5 (2 by maintainers)
Top GitHub Comments
We’ve moved this issue to the Backlog milestone. This means that it is not going to be worked on for the coming release. We will reassess the backlog following the current release and consider this item at that time. To learn more about our issue management process and to have better expectation regarding different types of issues you can read our Triage Process.
E.g. if AFD is configured to match pattern
/foo-bar/*
on a route, and incoming HTTP request has/Foo-Bar/BaZ
, then AFD will match route, and forward/foo-bar/BaZ
to backend. This somehow messes up Blazor Server, since client side script sees path/Foo-Bar
while server-side got request on/foo-bar
.This isn’t a problem when using YARP, since it will NOT change casing when forwarding request.