aspnetcore icon indicating copy to clipboard operation
aspnetcore copied to clipboard

Blazor webassembly subpath doesn't work

Open suntsu42 opened this issue 2 years ago • 9 comments

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 image

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. image

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) image

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

suntsu42 avatar Nov 08 '23 07:11 suntsu42

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(); and app.UseStaticFiles(); with the relative path, not add additional calls to those methods. Only app.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.

guardrex avatar Nov 08 '23 12:11 guardrex

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).

mkArtakMSFT avatar Nov 08 '23 17:11 mkArtakMSFT

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.

ghost avatar Nov 08 '23 17:11 ghost

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.

guardrex avatar Nov 08 '23 17:11 guardrex

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.

suntsu42 avatar Nov 09 '23 08:11 suntsu42

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");).
  • 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.

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

guardrex avatar Nov 09 '23 12:11 guardrex

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 avatar Jan 30 '24 12:01 PatrickBateman91

@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 🤞🍀.

guardrex avatar Jan 30 '24 13:01 guardrex

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

audacity76 avatar Feb 22 '24 10:02 audacity76

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();

NikLuy avatar May 13 '24 17:05 NikLuy