Blazor Server中EF Core DbContext已释放问题(依赖注入场景)
Blazor Server中DbContext被释放导致ObjectDisposedException的解决方法
核心原因
Blazor Server中Scoped服务的生命周期与组件所在的SignalR电路绑定,当父组件销毁(如路由跳转),Scoped的DbContext和仓库会被DI容器释放,若子组件仍持有引用并执行数据操作,就会抛出该异常。Transient注册无法解决本质问题,因为异步操作延迟执行时,实例仍可能被提前释放。
解决方案
1. 使用DbContextFactory替代直接注册DbContext
EF Core专门针对Blazor场景提供了IDbContextFactory,通过工厂创建DbContext实例,能精准控制实例生命周期,避免共享实例导致的释放问题。
注册方式修改为:
builder.Services.AddDbContextFactory<ApplicationContext>(options => options.UseSqlServer(builder.Configuration.GetConnectionString("Sms")));
仓库中注入工厂而非直接注入DbContext:
public class GetwayRepository { private readonly IDbContextFactory<ApplicationContext> _contextFactory; public GetwayRepository(IDbContextFactory<ApplicationContext> contextFactory) { _contextFactory = contextFactory; } public async Task<List<Gateway>> GetAllGatewaysAsync() { // 每次操作创建新实例,using自动释放 using var context = _contextFactory.CreateDbContext(); return await context.Gateways.ToListAsync(); } // 其他数据操作方法同理,都用using包裹DbContext实例 }
2. 禁止在组件间传递仓库实例
不要将父组件注入的仓库实例通过参数传递给子组件,父组件销毁时会连带释放仓库和DbContext,导致子组件引用失效。让子组件自行通过DI注入仓库:
子组件正确写法:
@inject GetwayRepository Repository // 组件逻辑
避免错误写法:
// 父组件中传递 <AddGateway Repository="@_repository" /> // 子组件接收参数 [Parameter] public GetwayRepository Repository { get; set; }
3. 确保数据操作在Blazor同步上下文执行
不要用Task.Run等方式脱离Blazor同步上下文执行EF Core操作,这会导致DbContext在操作完成前被容器释放。直接在组件生命周期方法或事件回调中执行异步操作:
正确示例:
protected override async Task OnInitializedAsync() { _gateways = await Repository.GetAllGatewaysAsync(); }
错误示例:
// 禁止这种写法 Task.Run(async () => { _gateways = await Repository.GetAllGatewaysAsync(); StateHasChanged(); });
4. 不要手动管理DbContext的释放
DbContext的释放由using语句或DI容器自动处理,无需给仓库或组件手动实现IDispose接口,否则可能导致重复释放或释放时机错误。
内容的提问来源于stack exchange,提问作者madiyyarrrr
相关产品推荐
相关产品推荐

