Blazor Scoped服务调用Dispose后再次进入页面未触发构造函数问题
问题原因
Blazor 中注册为Scoped的服务默认生命周期作用域为整个用户会话:Blazor WASM 场景下对应浏览器单个标签页的完整生命周期,Blazor Server 场景下对应单个 SignalR 连接的生命周期,不会随页面导航切换自动销毁重建。
你手动调用Dispose方法仅会执行该服务实例的自定义释放逻辑,并不会将该实例从 DI 容器的 Scoped 作用域缓存中移除。后续再次请求注入ProfileService时,DI 容器仍会返回之前创建的旧实例,自然不会触发构造函数执行。
解决方案
如果需要实现ProfileService跟随ProfileView页面的加载/卸载完成实例的创建/销毁,可以通过以下两种方案实现:
方案1:继承OwningComponentBase<T>基类
Blazor 原生提供了OwningComponentBase<T>组件基类,会自动为当前组件创建独立的 DI 作用域,组件销毁时自动销毁该作用域及作用域内所有服务:
- 修改
ProfileView的父类为OwningComponentBase<ProfileService>,替换原有的ComponentBase - 不要使用
@inject直接注入ProfileService,通过基类提供的Service属性获取服务实例即可 - 页面导航离开触发组件销毁时,独立作用域会自动释放,下次进入页面会创建新的作用域及
ProfileService实例。
方案2:手动管理DI作用域
如果不想修改组件基类,也可以手动控制作用域的创建和销毁:
- 首先给
ProfileView注入IServiceScopeFactory - 在页面初始化时创建独立作用域并获取服务实例:
private IServiceScope _serviceScope; private ProfileService _profileService; protected override async Task OnInitializedAsync() { _serviceScope = _serviceScopeFactory.CreateScope(); _profileService = _serviceScope.ServiceProvider.GetRequiredService<ProfileService>(); // 后续业务逻辑均使用此处获取的_profileService }
- 在组件的释放方法中销毁作用域:
public async ValueTask DisposeAsync() { if (_serviceScope != null) { await _serviceScope.DisposeAsync(); } }
注意:不要手动调用 DI 容器托管的服务的
Dispose方法,对应作用域销毁时容器会自动执行所有服务的释放逻辑,手动调用仅会执行清理逻辑不会更新容器的实例缓存,反而可能导致不可预期的问题。
内容的提问来源于stack exchange,提问作者Lapish
相关产品推荐
相关产品推荐

