You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Blazor Server中NavMenu.razor组件正确使用DbContext的方法及异常解决

问题原因分析

你的问题核心是作用域服务的生命周期与事件触发时机不匹配,具体有两个关键点:

  1. 组件注入的IServiceProvider已被释放
    组件注入的IServiceProvider属于组件所在的Blazor渲染上下文(电路/作用域),当组件所在的作用域因超时、用户断开连接或组件卸载而被销毁时,这个IServiceProvider会被释放。但你的LuahAuthService是单例服务,它的OnChange事件订阅会一直持有组件的引用,当后续事件触发时,调用已释放的ServiceProvider就会抛出ObjectDisposedException。

  2. 直接注入的ScheduleOps作用域过期
    ScheduleOps是Scoped服务,它的生命周期和组件所在的作用域绑定。当作用域过期(比如Blazor Server默认的作用域超时),或者事件触发时原作用域已被销毁,依赖的LuahDbContext也会被释放,从而出现“过期的DbContext”错误。

解决方案

1. 使用IServiceScopeFactory创建独立作用域

替换组件中的IServiceProvider注入为IServiceScopeFactory,它是Singleton服务,可以安全地创建新的独立作用域,避免依赖组件所在的已释放作用域:

首先修改组件注入:

@inject IServiceScopeFactory ScopeFactory
@inject ScheduleOps ScheduleOps
@inject MenuService MenuService
@inject LuahAuthService AuthService
@implements IDisposable

然后修改HandleMenuChangeAsync方法:

private async Task HandleMenuChangeAsync()
{
    var authState = await AuthenticationStateProvider.GetAuthenticationStateAsync();
    if (!authState.User.Identity.IsAuthenticated)
        return;
    var userid = authState.User.FindFirst("userid").Value;

    List<Schedule> lst = null;
    try
    {
        using (var scope = ScopeFactory.CreateScope())
        {
            var scheduleOps = scope.ServiceProvider.GetRequiredService<ScheduleOps>();
            lst = await scheduleOps.CustomerSchedules(userid);
            // 这里可使用lst更新菜单数据
        }
    }
    catch (Exception ex)
    {
        Console.WriteLine(ex.Message);
    }
}

2. 取消事件订阅避免内存泄漏

因为LuahAuthService是单例,组件卸载时必须取消订阅OnChange事件,否则单例会持有组件引用导致内存泄漏,同时也会继续触发已销毁组件的事件处理方法:

public void Dispose()
{
    AuthService.OnChange -= HandleMenuChangeAsync;
}

3. 优化事件订阅逻辑

确保只订阅一次事件,避免重复绑定:

private bool _hasSubscribed;

protected override Task OnAfterRenderAsync(bool firstRender)
{
    if (!_hasSubscribed)
    {
        AuthService.OnChange += HandleMenuChangeAsync;
        _hasSubscribed = true;
    }
    return base.OnAfterRenderAsync(firstRender);
}
原理说明
  • IServiceScopeFactory是Singleton服务,生命周期与应用一致,创建的新作用域完全独立于组件原有作用域,作用域内的Scoped服务(ScheduleOps、LuahDbContext)会在作用域释放时被正确回收,不会受组件生命周期影响。
  • 取消事件订阅可以切断单例服务与已销毁组件的引用关联,避免内存泄漏和无效的事件调用。

内容的提问来源于stack exchange,提问作者Michael EstrinOne

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.16 03:11:14