Blazor模块化UI应用服务容器托管时的路由配置问题
问题:Blazor作为HostedService跨进程运行时的回退路由映射问题
我正在尝试创建Blazor应用,计划将宿主与布局定义在单个Razor Class Library(RCL)或应用中,供其他RCL模块复用。但遇到路由问题,始终无法实现预期效果。具体来说,当Blazor应用自身作为HostedService在另一个进程中运行时,不知道如何将回退路由正确映射到宿主页面。
示例场景
我用标准“Blazor Server Application”模板创建应用,把应用构建逻辑移到了UiHostService中,代码如下:
using Alpha.ReferenceApp.Data; namespace Alpha.ReferenceApp.Services { public class UiHostService : IHostedService { WebApplication? _app; public Task StartAsync(CancellationToken cancellationToken) { var builder = WebApplication.CreateBuilder(Environment.GetCommandLineArgs()); // Add services to the container. builder.Services.AddRazorPages(); builder.Services.AddServerSideBlazor(); builder.Services.AddSingleton<WeatherForecastService>(); _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. _app.UseHsts(); } _app.UseHttpsRedirection(); _app.UseStaticFiles(); _app.UseRouting(); _app.MapBlazorHub(); _app.MapFallbackToPage("/_Host"); return _app.StartAsync(cancellationToken); } public Task StopAsync(CancellationToken cancellationToken) => _app?.StopAsync(cancellationToken) ?? Task.CompletedTask; }
原应用的Program.cs代码如下:
public static async Task Main() => await Host.CreateDefaultBuilder() .ConfigureServices(svc => svc .AddHostedService<UiHostService>() ) .Build() .RunAsync();
该方案在原应用中运行可行,且能加载来自RCL的区域/页面。但将其加载到独立应用Alpha.HostProcess的服务容器中时(代码如下),无法将路由映射回回退页面“_Host”。
using Alpha.ReferenceApp.Services; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; await Host.CreateDefaultBuilder().ConfigureServices(svc => svc .AddHostedService<UiHostService>() ) .Build() .RunAsync();
问题原因
- 内容根路径不匹配:独立宿主进程运行时,
WebApplication默认内容根路径是宿主进程的执行目录,而非原Blazor应用的目录,导致找不到_Host.cshtml页面文件。 - 资源访问权限缺失:独立进程无法访问原Blazor应用中的Razor页面、静态资源等文件,因为这些文件未被正确嵌入或复制到宿主进程环境中。
正确配置方式
方式一:将Blazor应用转为RCL并嵌入资源
- 转换项目类型并配置嵌入资源:
将原Blazor项目改为Razor Class Library(RCL),把_Host.cshtml、布局文件、静态资源等文件的生成操作设置为嵌入的资源(在文件属性中修改)。 - 指定内容根路径:
创建WebApplicationBuilder时,指定内容根路径为RCL程序集所在目录:using System.Reflection; var builder = WebApplication.CreateBuilder(new WebApplicationOptions { Args = Environment.GetCommandLineArgs(), ContentRootPath = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location) }); - 注册嵌入式Razor Pages:
添加Razor Pages服务时,指定加载当前程序集的页面资源:builder.Services.AddRazorPages() .AddApplicationPart(typeof(UiHostService).Assembly);
方式二:调整宿主进程的内容根路径
若不想转为RCL,可直接修改独立宿主进程的内容根路径,使其指向原Blazor应用的发布目录:
await Host.CreateDefaultBuilder(new[] { "--contentRoot", @"C:\Path\To\Alpha.ReferenceApp\Publish" }) .ConfigureServices(svc => svc.AddHostedService<UiHostService>()) .Build() .RunAsync();
确保原Blazor应用已发布到指定路径,且宿主进程有权限访问该目录下的所有文件。
路由配置补充注意事项
- 确认
MapFallbackToPage("/_Host")中的路径正确,_Host.cshtml需位于Razor Pages的根目录(或配置的RootDirectory下)。 - 若使用区域,需在路由中指定区域,例如:
MapFallbackToPage("/_Host", "/Areas/MyArea")。
内容的提问来源于stack exchange,提问作者Mik3c
相关产品推荐
相关产品推荐

