Blazor WebAssembly中如何初始化加载WebApi配置的共享服务
问题根因说明
- 第一个方案失败:你调用
wasmBuilder.GetRequiredService<T>()时WebAssemblyHost尚未完成构建,builder会临时生成独立的服务提供器解析服务,和后续应用运行时的服务提供器完全隔离,因此拿到的服务实例不一致。 - 第二个方案失败:Blazor WASM运行在浏览器单线程JS互操作环境中,不支持同步阻塞等待异步任务(
.Wait()/.Result均不可用),会直接抛出监视器相关异常。
可行解决方案
方案1:主机构建后在全局Scope初始化(推荐,适合启动时必须完成初始化的场景)
完全对齐你原有思路,仅调整执行时机即可:
- 正常注册所有服务,先完成主机构建
// 注册服务 builder.Services.AddScoped<A>(); builder.Services.AddScoped<B>(); builder.Services.AddScoped<C>(); // 构建主机 var host = builder.Build();
- 从最终运行的主机服务提供器创建Scope,完成服务A的初始化
using var scope = host.Services.CreateScope(); var serviceProvider = scope.ServiceProvider; // 此时解析的服务和后续组件注入的实例完全一致 var serviceA = serviceProvider.GetRequiredService<A>(); var serviceB = serviceProvider.GetRequiredService<B>(); serviceA.MySetupValues = await serviceB.GetSetupValues();
- 最后启动应用
await host.RunAsync();
注意:此方案会阻塞应用启动直到接口返回,若需要加载提示可在
wwwroot/index.html中添加静态加载占位符,Blazor初始化完成后会自动替换。
方案2:懒加载初始化(适合允许启动后首次使用时再初始化的场景)
将初始化逻辑封装到服务A内部,避免阻塞启动流程:
- 改造服务A,内置异步初始化方法
public class A { private readonly B _serviceB; private Task _initTask; public MySetupValues MySetupValues { get; private set; } public A(B serviceB) { _serviceB = serviceB; } public async Task EnsureInitializedAsync() { // 避免重复初始化 if (_initTask == null) { _initTask = InitInternalAsync(); } await _initTask; } private async Task InitInternalAsync() { MySetupValues = await _serviceB.GetSetupValues(); } }
- 统一初始化入口:在根组件
App.razor中触发一次初始化,所有子组件注入时即可直接使用已初始化的实例
@inject A ServiceA @* 原有App.razor的路由等逻辑 *@ <Router AppAssembly="@typeof(App).Assembly"> <!-- 原有路由配置 --> </Router> @code { protected override async Task OnInitializedAsync() { await ServiceA.EnsureInitializedAsync(); } }
如果业务允许,也可以在每个用到服务A的组件的OnInitializedAsync生命周期中自行调用初始化方法,避免根组件阻塞。
内容的提问来源于stack exchange,提问作者Jens Mander
相关产品推荐
相关产品推荐

