Support for multiple Blazor Web apps per server project
- Dominant language
- C#
- Stars
- 38.4k
- Forks
- 10.9k
- Avg merge
- 2d 5h
- Merged PRs (30d)
- 276
Description
### Is there an existing issue for this?
- [X] 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()
.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()
.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(ctx => ctx.Request.Host.Port == 7282)
app.MapRazorComponents(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_
Contributor guide
Assessment
This issue has not been assessed yet.