Search code examples
c#blazorblazor-webassembly

Blazor webassembly hosted in sub folder


I have a quite complicated existing asp.net core site with an SPA. This SPA uses # for routing, so all of the existing razor pages and API endpoints just work.

I first tried to host just using app.UseBlazorFrameworkFiles(), but all sorts of things break with this.

Then I tried to put it in a sub folder: app.UseBlazorFrameworkFiles("/UI"), updated the main Index.cshtml to redirect to /UI/ and serve the appropriate HTML there in /Areas/UI/Pages/Index.cshtml and added <StaticWebAssetBasePath>UI</StaticWebAssetBasePath> and hacked the AddHttpClient to use baseaddress of the whole site.

This works... Except when it doesn't, in particularly when using a url to a subpage in blazor or a from blazor navigating to a route that doesn't exists. This will end up visiting the hosted site and serve my 404 instead.

I then tried various variations of

app.MapWhen(ctx => ctx.Request.Path.StartsWithSegments("/UI/"), blazor => {
   blazor.UseEndpoints(endpoints => {
      endpoints.MapFallbackToAreaPage("/UI/{*path:nonfile}", "/", "UI");
   });
});

Result: InvalidOperationException: Cannot find the fallback endpoint specified by route values: { page: /, area: UI }.

app.MapFallbackToAreaPage("/", "UI");

Result: InvalidOperationException: Cannot find the fallback endpoint specified by route values: { page: /, area: UI }.

app.MapFallbackToAreaPage("/Index", "UI");

Result: AmbiguousMatchException: The request matched multiple endpoints. Matches: /Index /Index

or any other sorts of variations I could come up with, all with the result of either a) blows up the existing configuration or b) blows up at startup or c) blows up when visting a page that doesn't exist.

Help please. How do I make this blazor hosted on my site?


Solution

  • TLDR; Fix it at the start of pipeline, not at the end (with mapfallback)

    I was able to find a solution simply by hacking the pipeline and rewriting the request.

    app.UseHttpsRedirection(); //after this
    
    //host blazor in this folder
    app.UseBlazorFrameworkFiles("/UI");
    app.Use((ctx, next) => {
       if (ctx.Request.Path.StartsWithSegments("/UI", out var rest) && !rest.StartsWithSegments("/"))
       {
          //detected paths that needs to be routed by Blazor and not server
          ctx.Request.Path = new PathString("/UI/");
          return next();
       }
       return next();
    
    });
    

    If this is placed after UseHttpsRedirection and before everything else (can be after UseStaticFiles also if the new path is a non-file, like a razor page), it will rewrite EVERYTHING like /UI/* into /UI/.