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

注入CurrentUserService到DbContext后控制器中UserId始终为null如何解决

问题根因

你遇到的问题核心是CurrentUserService的UserId赋值时机错误:

  • 你在服务构造函数中直接读取HttpContext.User获取用户ID,但这个属性只有在ASP.NET Core身份认证中间件执行完成后才会被正确填充。
  • DbContext作为Scoped服务,其构造时机远早于控制器的构造时机、也早于身份认证中间件的执行阶段,此时注入的CurrentUserService在构造时读取到的User是空值,导致UserId被永久赋值为null,这和你调整服务生命周期没有关联。

解决方案

第一步:修改CurrentUserService为动态取值

不要在构造函数中提前读取并固定UserId的值,改为每次访问属性时动态从当前HttpContext中读取:

public class CurrentUserService : ICurrentUserService
{
    private readonly IHttpContextAccessor _httpContextAccessor;

    public CurrentUserService(IHttpContextAccessor httpContextAccessor)
    {
        _httpContextAccessor = httpContextAccessor;
    }

    // 动态取值,每次访问时读取最新的用户身份信息
    public string UserId => _httpContextAccessor.HttpContext?.User?.FindFirstValue(ClaimTypes.NameIdentifier);
}

第二步:调整DbContext中UserId的读取时机

不要在AppDbContext的构造函数中访问_currentUserService.UserId,如果有审计字段自动赋值等需求,将逻辑迁移到SaveChanges/SaveChangesAsync方法中,这些方法执行时已经处于请求处理阶段,身份认证已完成,可以拿到正确的用户ID:

public class AppDbContext:IdentityDbContext<AppUser>,IAppDbContext
{
    private readonly ICurrentUserService _currentUserService;
    public AppDbContext(DbContextOptions<AppDbContext> options, ICurrentUserService currentUserService):base(options)
    {
        _currentUserService = currentUserService;
    }

    public override int SaveChanges()
    {
        ProcessAuditFields();
        return base.SaveChanges();
    }

    public override Task<int> SaveChangesAsync(CancellationToken cancellationToken = default)
    {
        ProcessAuditFields();
        return base.SaveChangesAsync(cancellationToken);
    }

    private void ProcessAuditFields()
    {
        // 示例:给所有实现了审计接口的实体自动赋值操作人
        foreach (var entry in ChangeTracker.Entries<IAuditable>())
        {
            var userId = _currentUserService.UserId;
            if (entry.State == EntityState.Added)
            {
                entry.Entity.CreatorId = userId;
                entry.Entity.CreateTime = DateTime.Now;
            }
            else if (entry.State == EntityState.Modified)
            {
                entry.Entity.UpdaterId = userId;
                entry.Entity.UpdateTime = DateTime.Now;
            }
        }
    }
}

额外检查项

  • 确认Program.cs中已经注册了IHttpContextAccessor:
    builder.Services.AddHttpContextAccessor();
    
  • CurrentUserService和AppDbContext都保持Scoped生命周期即可,无需修改为Transient。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.07 09:48:03