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
相关产品推荐
相关产品推荐

