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

Blazor Server中如何向单例DbContextFactory注入作用域服务?

Blazor Server中EF Core DbContext获取当前用户信息的问题解决

背景

在Blazor Server中使用EF Core时,需通过DbContextFactory而非直接AddDbContext来注册上下文服务,注册代码如下:

builder.Services.AddDbContextFactory<AppDbContext>(options =>
{
    options.UseSqlServer(builder.Configuration.GetConnectionString("Connection"));
});

该默认注册的DbContextFactory为单例生命周期。

业务需求是在DbContext的SaveChangesAsync方法中自动填充实体的创建/修改日期及用户信息,用户信息由Scoped服务UserState维护,其注册代码:

builder.Services.AddScoped<UserState>();

尝试的方案及问题

最初参考资料尝试通过IServiceScopeFactory向单例的DbContext注入Scoped服务,实现代码如下:

private readonly IServiceScopeFactory _serviceScopeFactory;

public AppDbContext(DbContextOptions<AppDbContext> options, IServiceScopeFactory serviceScopeFactory) : base(options)
{
     _serviceScopeFactory = serviceScopeFactory;
}

public override Task<int> SaveChangesAsync(CancellationToken cancellationToken = new CancellationToken())
{
    using IServiceScope scope = _serviceScopeFactory.CreateAsyncScope();
    var _userState = scope.ServiceProvider.GetRequiredService<UserState>();

    foreach (var entry in ChangeTracker.Entries<EntityBase>())
    {
      switch (entry.State)
      {
            case EntityState.Added:
                entry.Entity.CreatedAt = DateTime.Now;
                   if (_userState.UserName is not null)
                        entry.Entity.CreatedBy = _userState.UserName;
                   break;
             case EntityState.Modified:
                   entry.Entity.EditedAt = DateTime.Now;
                   if (_userState.UserName is not null)
                        entry.Entity.EditedBy = _userState.UserName;
                   break;
       }
     }

    return base.SaveChangesAsync(cancellationToken);
}

但实际运行时,通过新创建的作用域获取到的UserState是一个空数据的新实例——原因是手动创建的作用域与当前用户的Scoped作用域完全独立,无法共享已填充的用户状态。

解决方法

将DbContextFactory的生命周期改为Scoped,这样它就能和UserState处于同一作用域中,直接注入即可获取正确的用户信息。

1. 修改DbContextFactory注册代码

builder.Services.AddDbContextFactory<AppDbContext>(options =>
{
    options.UseSqlServer(builder.Configuration.GetConnectionString("Connection"));
}, ServiceLifetime.Scoped);

2. 调整DbContext构造函数与SaveChangesAsync实现

直接注入UserState,无需再手动创建作用域:

private readonly UserState _userState;

public AppDbContext(DbContextOptions<AppDbContext> options, UserState userState) : base(options)
{
     _userState = userState;
}

public override Task<int> SaveChangesAsync(CancellationToken cancellationToken = new CancellationToken())
{
    foreach (var entry in ChangeTracker.Entries<EntityBase>())
    {
      switch (entry.State)
      {
            case EntityState.Added:
                entry.Entity.CreatedAt = DateTime.Now;
                   if (_userState.UserName is not null)
                        entry.Entity.CreatedBy = _userState.UserName;
                   break;
             case EntityState.Modified:
                   entry.Entity.EditedAt = DateTime.Now;
                   if (_userState.UserName is not null)
                        entry.Entity.EditedBy = _userState.UserName;
                   break;
       }
     }

    return base.SaveChangesAsync(cancellationToken);
}

此方案下,每次通过Scoped的DbContextFactory创建的DbContext,都能直接获取到当前用户的UserState实例,自动填充实体的用户信息。


内容的提问来源于stack exchange,提问作者Luis Zenteno

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.16 18:41:01