Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Move Blazor WASM to subdirectory (base directory static files)

I want to make an app where I need static pages on the base domain and my Blazor app on a subdirectory.

Example:

https://example.com is where my static pages should be (like '/features' or '/pricing' or '/faq')

https://example.com/app should be where my blazor website lives.

I've seen that I can pass in a PathString to app.UseBlazorFrameworkFiles but that does not work (app.UseBlazorFrameworkFiles(new PathString("/app")). My Blazor app is hosted on a .NET 5 WebApi project with gRPC.

Can someone point me to the right direction how to achieve this?

Thanks in advance!

like image 436
Coupz Avatar asked Nov 17 '20 11:11

Coupz


2 Answers

The subdirectory name needs to appear in four places.

In the Startup.cs of your WebAPI project you need:

app.UseBlazorFrameworkFiles(new PathString("/app"));

and in endpoint config:

endpoints.MapFallbackToFile("/app/{*path:nonfile}", "app/index.html");

In the wwwroot/index.html file of the Wasm app:

<base href="/app/" />

In the CSProj file of the Wasm app:

<StaticWebAssetBasePath>app</StaticWebAssetBasePath>

Docs: https://docs.microsoft.com/en-us/aspnet/core/blazor/host-and-deploy/webassembly?view=aspnetcore-5.0#hosted-deployment-with-multiple-blazor-webassembly-apps

There's an example implementation here: https://github.com/javiercn/BlazorMultipleApps

If you have used the default Wasm template with Identity you'll find your client doesn't load properly because the static assets bundled inside microsoft.aspnetcore.components.webassembly.authentication aren't served up. To work around this change the src in index.html to an absolute path:

<script src="/_content/Microsoft.AspNetCore.Components.WebAssembly.Authentication/AuthenticationService.js"></script>

Other changes required for Identity to function:

  • In AppSettings, change the IdentityServer client profile from "IdentityServerSPA" to "SPA"
  • Specify "RedirectUri" and "LogoutUri" to include the new subdirectory
      "Clients": {
        "BlazorApp.Client": {
          "Profile": "SPA",
          "RedirectUri": "https://localhost:44357/app/authentication/login-callback",
          "LogoutUri": "https://localhost:44357/app/authentication/logout-callback"
        }
      }
like image 111
Daz Avatar answered Oct 07 '22 00:10

Daz


I've looked at the answer from Daz, which does fix the problem when debugging/running a standalone product. My production environment is Kubernetes based however, and my ingress controller wouldn't route the request to the correct location e.g:

In my example, I have changed the usual 4 settings:

  • set the <base href> in the index file to <base href="/app/" />
  • set app.UseBlazorFrameworkFiles(new PathString("/app")) in the servers ConfigureServices function
  • set endpoints.MapFallbackToFile("/app/{*path:nonfile}", "app/index.html") in the servers Configure function, UseEndpoints option
  • added <StaticWebAssetBasePath>app into the client's <PropertyGroup> section of the csproj file.

Everything was working barring the single file "Microsoft.AspNetCore.Components.WebAssembly.Authentication/AuthenticationService.js" which is an embedded file.

Since the file needs to come from the server, adjusting the file path in the client won't work, because it wouldn't be correctly routed by my ingress configuration. For my application, I dropped in a very simple middleware as follows:

        // "/{app}/_content/{embedded-library-files}/{file}" requests need to be presented at root
        app.Use(async (context, next) =>
        {
            HttpRequest request = context.Request;
            var path = request.Path;
            if (path.StartsWithSegments(new PathString("/app/_content")))
            {
                if (new string[] {
                    "/Microsoft.AspNetCore.Components.WebAssembly.Authentication/AuthenticationService.js"
                }.Any(s => path.Value.EndsWith(s)))
                {
                    request.Path = path.Value.Substring("/app".Length);
                }
            }

            await next.Invoke();
        });

You'd need an if clause for each folder, and an entry in the list for each file. Obviously this can be simplified if you know that the whole folder should be redirected.

Since rewriting the path in the server is invisible to the client application, this simple update fixes the problem.

Mark

like image 28
Mark Rabjohn Avatar answered Oct 07 '22 02:10

Mark Rabjohn