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

HotChocolate 15中EF Core注入作用域服务失败:无法从根容器解析

问题分析与解决方案

HotChocolate 15.x 对DI作用域和EF Core集成逻辑做了调整:默认情况下,GraphQL执行流程会使用根服务提供者来解析依赖,而你的IRequestIdentity是Scoped服务,根容器无法直接解析Scoped依赖,这就是你遇到两种错误的核心原因。以下是保留原有功能的具体解决方案:

核心思路

放弃在DbContext构造函数中直接注入IRequestIdentity,改为通过IHttpContextAccessor在请求作用域内延迟获取身份信息;同时配置HotChocolate在请求作用域内创建DbContext,确保能拿到当前请求的上下文数据。

步骤1:调整IRequestIdentity的注册与实现

确保身份服务从当前请求的HttpContext中解析JWT信息,注册为Scoped:

public interface IRequestIdentity
{
    string UserId { get; }
    string TenantId { get; }
}

public class RequestIdentity : IRequestIdentity
{
    public string UserId { get; }
    public string TenantId { get; }

    public RequestIdentity(IHttpContextAccessor httpContextAccessor)
    {
        var context = httpContextAccessor.HttpContext;
        UserId = context?.User.FindFirst(ClaimTypes.NameIdentifier)?.Value ?? string.Empty;
        TenantId = context?.User.FindFirst("TenantId")?.Value ?? string.Empty;
    }
}

// DI注册
services.AddScoped<IRequestIdentity>();
services.AddHttpContextAccessor();

步骤2:修改DbContext实现,延迟获取身份信息

移除构造函数中的IRequestIdentity注入,改为通过IHttpContextAccessor在需要时获取:

public class DataContext : DbContext
{
    private readonly IHttpContextAccessor _httpContextAccessor;
    private IRequestIdentity _identity;

    public DataContext(DbContextOptions<DataContext> options, IHttpContextAccessor httpContextAccessor)
        : base(options)
    {
        _httpContextAccessor = httpContextAccessor;
    }

    // 延迟加载当前请求的身份信息
    private IRequestIdentity CurrentIdentity => 
        _identity ??= _httpContextAccessor.HttpContext?.RequestServices.GetRequiredService<IRequestIdentity>();

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        // 全局查询过滤:仅返回当前租户的数据
        modelBuilder.Entity<YourEntity>().HasQueryFilter(e => e.TenantId == CurrentIdentity.TenantId);
    }

    public override int SaveChanges(bool acceptAllChangesOnSuccess)
    {
        // 自动填充修改人信息
        foreach (var entry in ChangeTracker.Entries<IAuditable>())
        {
            if (entry.State == EntityState.Added)
            {
                entry.Entity.CreatedBy = CurrentIdentity.UserId;
            }
            else if (entry.State == EntityState.Modified)
            {
                entry.Entity.UpdatedBy = CurrentIdentity.UserId;
            }
        }
        return base.SaveChanges(acceptAllChangesOnSuccess);
    }
}

步骤3:配置HotChocolate使用Scoped的DbContext

在GraphQL服务注册时,明确指定DbContext的作用域为Scoped,确保每个请求都能拿到正确的上下文:

builder.Services.AddGraphQLServer()
    .AddQueryType<Query>()
    .AddMutationType<Mutation>()
    // 关键:告诉HotChocolate在请求作用域内创建DbContext
    .AddDbContext<DataContext>(DbContextKind.Scoped);

// 注册DbContext(无需使用DbContextFactory)
builder.Services.AddDbContext<DataContext>(options =>
{
    options.UseSqlServer(builder.Configuration.GetConnectionString("DefaultConnection"));
});

为什么之前的方案失效?

  • 直接在DbContext构造函数注入IRequestIdentity:HotChocolate 15默认用根容器解析DbContext,根容器无法获取Scoped的IRequestIdentity,导致执行错误。
  • 使用DbContextFactory:DbContextFactory默认是Singleton服务,它创建DbContext时使用的是根服务提供者,同样无法解析Scoped的IRequestIdentity,因此抛出"Cannot resolve scoped service"错误。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.14 05:36:07