blazorblazor-webassemblyhosted-blazor-webassembly

Create a multiple WebAssembly projects in a single solution


Please, see this question for context and the answer by MrC aka Shaun Curtis

This question is about something I've tried to solve in the past without great success. Are you familiar with this sample I've once downloaded and run it. It did not work. I then realized that I must add the base url to the url in the browser's address bar in order to run the first project, for instance: https://localhost: 44302/FirstApp That is, the Client project. And for the SecondClient it should be https://localhost: 44302/SecondApp. This is exactly how the sample app by MrC aka Shaun Curtis works, though he added a Razor Pages app to provide a menu for redirection to the four projects.

What I tried to do without much success is to make the first WebAssemby front end project, which is hosted, to be the default; that is when I run the app, or type in the address bar https://localhost: 44302. And if I type https://localhost: 44302/FirstApp I see the first stand alone WebAssembly project I added to the solution. And a second project, and a third project, and so on, all are WebAssembly projects. I could not do that: When I ran the default project everything is fine... I can navigate within the bounds of the project, route to the Counter page, FetchData page, etc.

But when I add the segment /FirstApp to the url in the address bar and hit enter, the Router displays the message "Sorry, there's nothing at this address." instead of navigating to the project represented by the base url /FirstApp/

Does anyone here have any idea how to achieve the requested feature I am looking for ?


Solution

  • This is a summary of the Repo that demonstrates how to do this.

    The sub-folder Web Assembly projects have project files like this. The important bit is setting the <StaticWebAssetBasePath>

    <Project Sdk="Microsoft.NET.Sdk.BlazorWebAssembly">
    
        <PropertyGroup>
            <TargetFramework>net6.0</TargetFramework>
            <Nullable>enable</Nullable>
            <ImplicitUsings>enable</ImplicitUsings>
            <StaticWebAssetBasePath>grey</StaticWebAssetBasePath>
        </PropertyGroup>
    ....
    

    and Index.html like this. We've updated the paths on the base, css and the framework js file.

    <!DOCTYPE html>
    <html lang="en">
    
    <head>
        <meta charset="utf-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
        <title>Blazr.Medusa.Grey</title>
        <base href="/grey/" />
        <link href="/grey/css/bootstrap/bootstrap.min.css" rel="stylesheet" />
        <link href="/grey/css/app.css" rel="stylesheet" />
        <link href="Blazr.Medusa.Grey.styles.css" rel="stylesheet" />
    </head>
    
    <body>
        <div id="app">Loading...</div>
    
        <div id="blazor-error-ui">
            An unhandled error has occurred.
            <a href="" class="reload">Reload</a>
            <a class="dismiss">🗙</a>
        </div>
        <script src="/grey/_framework/blazor.webassembly.js"></script>
    </body>
    
    </html>
    

    The Web Project has dependencies on all the Web Assembly projects, so they can all be mapped to wwwwroot.

    The Web Project Program looks like this with specific end points for each Web Assembly SPA. The default maps to the base Web Assembly project - Blazr.Medusa.WASM.

    var builder = WebApplication.CreateBuilder(args);
    
    // Add services to the container.
    builder.Services.AddRazorPages();
    
    var app = builder.Build();
    
    // Configure the HTTP request pipeline.
    if (!app.Environment.IsDevelopment())
    {
        app.UseExceptionHandler("/Error");
        // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
        app.UseHsts();
    }
    
    app.UseHttpsRedirection();
    app.UseStaticFiles();
    
    app.MapWhen(ctx => ctx.Request.Path.StartsWithSegments("/grey"), app1 =>
    {
        app1.UseBlazorFrameworkFiles("/grey");
        app1.UseRouting();
        app1.UseEndpoints(endpoints =>
        {
            endpoints.MapFallbackToFile("/grey/{*path:nonfile}", "/grey/index.html");
        });
    });
    
    app.MapWhen(ctx => ctx.Request.Path.StartsWithSegments("/green"), app1 =>
    {
        app1.UseBlazorFrameworkFiles("/green");
        app1.UseRouting();
        app1.UseEndpoints(endpoints =>
        {
            endpoints.MapFallbackToFile("/green/{*path:nonfile}", "/green/index.html");
        });
    });
    
    app.MapWhen(ctx => ctx.Request.Path.StartsWithSegments("/purple"), app1 =>
    {
        app1.UseBlazorFrameworkFiles("/purple");
        app1.UseRouting();
        app1.UseEndpoints(endpoints =>
        {
            endpoints.MapFallbackToFile("/purple/{*path:nonfile}", "/purple/index.html");
        });
    });
    
    app.UseBlazorFrameworkFiles("");
    
    app.UseRouting();
    
    app.UseAuthorization();
    
    app.MapRazorPages();
    
    
    app.MapFallbackToFile("/index.html");
    
    app.Run();
    

    The Site Links component in the MainLayout of each site provides navigation between the SPA's

    <div class="p-2 m-2 text-end">
        <button class="btn btn-sm btn-primary me-1" @onclick='() => Go("")'>Go Base</button>
        <button class="btn btn-sm btn-secondary me-1" @onclick='() => Go("grey")'>Go Grey</button>
        <button class="btn btn-sm btn-success me-1" @onclick='() => Go("green")'>Go Green</button>
        <button class="btn btn-sm btn-dark me-1" @onclick='() => Go("purple")'>Go Purple</button>
    </div>
    
    @code {
    
        [Inject] private NavigationManager? NavManager { get; set; }
        
        private void Go(string colour)
            => this.NavManager?.NavigateTo($"/{colour}", true);
    }
    

    The Repo that contains the full solution is here

    The site looks like this:

    Green Site