Blazor webassembly subpath doesn't work
Is there an existing issue for this?
- [X] I have searched the existing issues
Describe the bug
I want to host a blazor webassembly under a subpath (http://foo.com/bar instead of http://foo.com) I've tried to set it up using the official documentation https://learn.microsoft.com/en-us/aspnet/core/blazor/host-and-deploy/?view=aspnetcore-7.0&tabs=visual-studio#app-base-path
The project is hosted via asp.net core
In the webapplication project, i can set the subpath by using usePathBase, UseStaticFiles and UseBlazorFrameworkFiles
var app = builder.Build();
app.UseBlazorFrameworkFiles("/bar");
app.UseStaticFiles("/bar");
app.UsePathBase("/bar");
In the wwwroot/index.html, i've set the base to:
<base href="/bar/" />
With those changes, some parts of the webassembly are available under the subpath, but blazor.webassembly.js is not. This file is loaded via the subpath, but cannot be provided.
I think what is missing is the StaticWebAssetBasePath (https://learn.microsoft.com/en-us/aspnet/core/blazor/fundamentals/static-files?view=aspnetcore-7.0#static-web-asset-base-path) I've set this in the webassembly csproj file:
// I've tried with and without trailing slash
<StaticWebAssetBasePath>bar</StaticWebAssetBasePath>
<StaticWebAssetBasePath>bar/</StaticWebAssetBasePath>
As soon as i add the StaticWebAssetBasePath, blazro webassembly is not retrieved anymore. (Be it using bar/ or bar/index.html)
The complete example is available on github: https://github.com/suntsu42/BlazorSubPathSample
Question: What do i need to configure to host a blazor webassembly project under a subpath?
Expected Behavior
No response
Steps To Reproduce
No response
Exceptions (if any)
No response
.NET Version
net7.0
Anything else?
No response
Notes for triage:
- There's at least a doc regression, since it was tested a few releases back and worked at that time.
- Your repro sample doesn't exactly follow the guidance. The guidance is to modify the existing
app.UseBlazorFrameworkFiles();andapp.UseStaticFiles();with the relative path, not add additional calls to those methods. Onlyapp.UsePathBase("/bar");would be at the top of the processing pipeline (cross-ref). However, it made no difference here when I just tested it ... I get the same broken app result that you're reporting.
I'd play with it a bit more myself, but I'm 🏃♂️😅 at the moment to get more .NET 8 coverage ready for release. I'm 👂 for the engineers to suggest the fix. I'll get the update into the docs ASAP.
Thanks for raising this, @suntsu42 and thanks for helping out with this, @guardrex. @suntsu42 can you try @guardrex 's suggestion above and see if that works (bullet point 2).
Hi @suntsu42. We have added the "Needs: Author Feedback" label to this issue, which indicates that we have an open question for you before we can take further action. This issue will be closed automatically in 7 days if we do not hear back from you by then - please feel free to re-open it if you come back to this issue after that time.
Unfortunately, @mkArtakMSFT, I did try that here, and I'm able to reproduce the problem that @suntsu42 is reporting. I think there is a regression in the docs. I'm not sure what the problem is. AFAIK, our guidance used to work ... a few releases ago at this point.
I'd work further on it, but I can't at the moment due to the 8.0 docs work. I'm buried in work for the next couple of weeks.
I did test with only app.UsePathBase("/bar"); and the behavior is the same. I also tested different other combinations with the same behavior. Hosting under a subpath never worked.
Same here ... I took a few minutes to try a few different things before I had to get back to .NET 8 doc work, and I failed to get it working 😢.
There is a regression somewhere. I think it's on the documentation side, but I'm not sure.
When this is reached for investigation, the guidance is ...
Hosted Blazor WebAssembly
If the app is a hosted Blazor WebAssembly app:
- In the in the Server project (
Program.cs):- Adjust the path of
UseBlazorFrameworkFiles(for example,app.UseBlazorFrameworkFiles("/base/path");). - Configure calls to
UseStaticFiles(for example,app.UseStaticFiles("/base/path");).
- Adjust the path of
- In the Client project:
- Configure
<StaticWebAssetBasePath>in the project file to match the path for serving static web assets (for example,<StaticWebAssetBasePath>base/path</StaticWebAssetBasePath>). - Configure the
<base>tag, per the guidance in the Configure the app base path section.
- Configure
The Configure the app base path piece is ...
Hosted Blazor WebAssembly (Client project, wwwroot/index.html):
<base href="/CoolApp/">
The trailing slash is required.
In the Server project, call UsePathBase first in the app's request processing pipeline (Program.cs) immediately after the WebApplicationBuilder is built (builder.Build()) to configure the base path for any following middleware that interacts with the request path:
app.UsePathBase("/CoolApp");
Cross-ref: https://learn.microsoft.com/en-us/aspnet/core/blazor/host-and-deploy/?view=aspnetcore-7.0&tabs=visual-studio#hosted-blazor-webassembly
How would one use base path in hosted WASM without hardcoding it in index.html? I'd like my base href to come from appSettings, and I am finding it difficult to get it working with the hosted model. App.UsePathBase just gets ignored in the server's Program.cs, even when put on top of the execution?
@PatrickBateman91 ... I added guidance on that just three weeks ago at ...
https://learn.microsoft.com/en-us/aspnet/core/blazor/host-and-deploy/?view=aspnetcore-8.0&tabs=visual-studio#obtain-the-app-base-path-from-configuration
Basically, you'll be supplying the app base path via a HeadContent component in the App component. Be sure to remove the <base> tag from the index.html page, or (IIRC) it won't work. Even then, I was only able to perform limited testing at the time due to the large backlog of 8.0 doc work, and I'm accepting feedback on the approach.
WRT this issue, it applies to the old hosted WASM template-based apps. I'm not even sure that it will be worked because hosted WASM, although supported, is no longer a project template. I feel good about all of the App base path section guidance working in standalone WASM apps and BWAs. I haven't received any reports on bad guidance for BWAs or for Blazor Server apps of the <8.0 era. I'm cautiously optimistic that for >=8.0 that the guidance is good 🤞🍀.
Hi! This behavior is not WebAssembly only. I have a .NET 8 WebApp with a blue/green deployment. With .NET 7 we did the following in our program.cs:
app.UseWhen(ctx => ctx.Request.Path.StartsWithSegments("/blue"), app =>
{
app.UsePathBase("/blue");
});
app.UseWhen(ctx => ctx.Request.Path.StartsWithSegments("/green"), app =>
{
app.UsePathBase("/green");
});
app.UseRouting();
When using a <base href="/" /> in the app.razor this is ignored. When <base /> is missing in the app.razor the blue/green routes work BUT the path to static files don't work anymore.
Full code to reproduce:
program.cs
using BlazorWebApp8.Components;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddRazorComponents()
.AddInteractiveServerComponents();
var app = builder.Build();
app.UseWhen(ctx => ctx.Request.Path.StartsWithSegments("/blue"), app =>
{
app.UsePathBase("/blue");
});
app.UseWhen(ctx => ctx.Request.Path.StartsWithSegments("/green"), app =>
{
app.UsePathBase("/green");
});
app.UseRouting();
app.UseStaticFiles();
app.UseAntiforgery();
app.MapRazorComponents<App>()
.AddInteractiveServerRenderMode();
app.Run();
App.razor
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
@* <base href="/"> *@
</head>
<body>
<Routes @rendermode="InteractiveServer" />
<script src="_framework/blazor.web.js"></script>
</body>
</html>
Home.razor
@page "/sub/Home"
<h1>Hello, world!</h1>
MainLayout.razor
@inherits LayoutComponentBase
@Body
Routes.razor
<Router AppAssembly="typeof(Program).Assembly">
<Found Context="routeData">
<RouteView RouteData="routeData" DefaultLayout="typeof(Layout.MainLayout)" />
</Found>
</Router>
Import part is, that Home.razor is on a sub page /sub/home
I had to Add
location / {
proxy_pass http://localhost:5000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection keep-alive;
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
and
builder.Services.Configure<ForwardedHeadersOptions>(options =>
{
options.ForwardedHeaders = ForwardedHeaders.XForwardedProto;
options.RequireHeaderSymmetry = false;
options.KnownNetworks.Clear();
options.KnownProxies.Clear();
});
app.UseForwardedHeaders();