Support for multiple Blazor Web apps per server project · Issue #52216 · dotnet/aspnetcore (original) (raw)
Is there an existing issue for this?
- I have searched the existing issues
Is your feature request related to a problem? Please describe the problem.
Quite often an application consists of several frontend apps which all need to access the same backend API. The new Blazor 8 template in VS assumes only one client app and distributes the razor files involved into 2 projects (the prerendering part is in the server project, the rest is in the client project).
So if I have 3 different frontend apps in Blazor 8, I'd need to have 3x2 = 6 projects, and each server project would essentially duplicate a lot of the shared logic, like authentication etc. Of course I could deploy a 7th project hosting only the common concerns like authentication, but for smaller projects this is overkill and poses new obstacles.
In ASP.NET Core 7 this problem was already solved:
https://learn.microsoft.com/en-us/aspnet/core/blazor/host-and-deploy/multiple-hosted-webassembly?view=aspnetcore-7.0&pivots=port-domain
I tried applying the same principle to Blazor 8, but it always results in an AmbiguousMatchException because both client apps register identical routes using the @page
directive (like "/" etc.)
Describe the solution you'd like
The following code should work without any issues since I'm isolating the two clients using a request filter, as proposed in the ASP.NET 7 tutorial.
app.UseHttpsRedirection();
app.UseRouting();
app.UseStaticFiles();
app.UseAntiforgery();
app.MapWhen(ctx => ctx.Request.Host.Port == 7282, client1 =>
{
client1.Use((ctx, nxt) =>
{
if (!ctx.Request.Path.Value!.Contains("blazor.web.js"))
{
ctx.Request.Path = "/Client1" + ctx.Request.Path;
}
return nxt();
});
client1.UseStaticFiles();
client1.UseStaticFiles("/Client1");
//client1.UseRouting(); //<--- needed???
client1.UseEndpoints(endpoints =>
{
endpoints.MapRazorComponents<AppClient1>()
.AddInteractiveServerRenderMode()
.AddInteractiveWebAssemblyRenderMode()
.AddAdditionalAssemblies(typeof(Client.Pages.Counter).Assembly);
});
});
app.MapWhen(ctx => ctx.Request.Host.Port == 7283, client2 =>
{
client2.Use((ctx, nxt) =>
{
if (!ctx.Request.Path.Value!.Contains("blazor.web.js"))
{
ctx.Request.Path = "/Client2" + ctx.Request.Path;
}
return nxt();
});
client2.UseStaticFiles();
client2.UseStaticFiles("/Client2");
//client2.UseRouting(); //<--- needed???
client2.UseEndpoints(endpoints =>
{
endpoints.MapRazorComponents<AppClient2>()
.AddInteractiveServerRenderMode()
.AddInteractiveWebAssemblyRenderMode()
.AddAdditionalAssemblies(typeof(MultiClientTest.SecondClient.Pages.Counter).Assembly);
});
});
app.Run();
Alternatively you could offer an optional builtin feature for isolating multiple client apps, like so:
app.MapRazorComponents<AppClient1>(ctx => ctx.Request.Host.Port == 7282)
app.MapRazorComponents<AppClient2>(ctx => ctx.Request.Host.Port == 7283)
I'm aware that this could still lead to ambiguous route mappings if the request filters aren't mutually exclusive; but then the framework would just throw an exception as it already does today.
Additional context
No response