如何解决无法解析Microsoft.EntityFrameworkCore.IDbContextFactory服务的错误?
IDbContextFactory<C4PDbContext>无法解析的依赖注入问题 运行ASP.NET Core项目时触发Unable to resolve service for type 'Microsoft.EntityFrameworkCore.IDbContextFactory<C4PDbContext>'错误,已尝试注册DI容器组件但问题未解决,怀疑ManageUserDocuments中的DbContext配置存在遗漏。以下为项目相关代码、错误信息及解决方案:
项目代码文件
UserService.cs
using Cosmos.UnitsOfWork; using GraphQlProject.Interfaces; using GraphQlProject.Models; using User = Cosmos.Entities.User; namespace GraphQlProject.Services; public class UserService : IUser { private readonly IManageUserDocuments _documents; public UserService(IManageUserDocuments documents) { _documents = documents; } public async Task<Models.User> GetUserById(string id) { { try { var user = await _documents.UserRepository.GetUserByIdAsync(id); var convertedUser = new Models.User { // DO SOMETHING }; return convertedUser; } catch (Exception e) { Console.WriteLine(e); throw; } } } }
ManageUserDocuments.cs(IDbContextFactory实现)
using System; using System.Threading.Tasks; using Cosmos.EntityFramework; using Cosmos.Repositories; using Microsoft.EntityFrameworkCore; namespace Cosmos.UnitsOfWork; public interface IManageUserDocuments : IUnitOfWork { public IUserRepository UserRepository { get; } } public class ManageUserDocuments : IManageUserDocuments { private IUserRepository? _userRepository; private readonly C4PDbContext _c4pDbContext; /// <summary> /// /// </summary> /// <param name="dbContextFactory">Instance of a class that implements IDbContextFactory</param> /// <exception cref="ArgumentNullException"></exception> public ManageUserDocuments(IDbContextFactory<C4PDbContext> dbContextFactory) { _c4pDbContext = dbContextFactory.CreateDbContextAsync().GetAwaiter().GetResult() ?? throw new ArgumentNullException(nameof(C4PDbContext)); } private void Dispose(bool disposing) { if (disposing) { _c4pDbContext.Dispose(); } } public void Dispose() { Dispose(true); } public Task<int> SaveChangesAsync() { return _c4pDbContext.SaveChangesAsync(); } public IUserRepository UserRepository { get { return _userRepository ??= new UserRepository(_c4pDbContext); } } }
UserRepository.cs
using System; using System.Collections.Generic; using System.Text.Json; using System.Threading.Tasks; using Cosmos.EntityFramework; using Microsoft.Azure.Cosmos; using Microsoft.EntityFrameworkCore; using User = Cosmos.Entities.User; namespace Cosmos.Repositories; public interface IUserRepository { public Task<User> GetUserByIdAsync(string id); } public class UserRepository : IUserRepository { private readonly C4PDbContext _c4pDbContext; public UserRepository(C4PDbContext c4pDbContext) { _c4pDbContext = c4pDbContext; } public async Task<User> GetUserByIdAsync(string id) { var partLine = await _c4pDbContext.Database.GetCosmosClient() .GetContainer("c4p", nameof(User).ToLower()) .ReadItemStreamAsync(id, new PartitionKey(id)); return partLine.IsSuccessStatusCode ? await JsonSerializer.DeserializeAsync<User>(partLine.Content) : default; } }
C4PDbContext.cs
using Cosmos.Entities; using Microsoft.EntityFrameworkCore; namespace Cosmos.EntityFramework; public class C4PDbContext : DbContext { /// <summary> /// Overloaded constructor /// </summary> /// <param name="options">Instance of a DbContextOptions</param> public C4PDbContext(DbContextOptions<C4PDbContext> options) : base(options) { } protected override void OnModelCreating(ModelBuilder modelBuilder) { #region User modelBuilder .Entity<User>() .ToContainer(nameof(User).ToLower()) .HasNoDiscriminator() .HasPartitionKey(x => x.id); #endregion base.OnModelCreating(modelBuilder); } }
Program.cs
using System.Runtime.CompilerServices; using Cosmos.EntityFramework; using Cosmos.Repositories; using Cosmos.UnitsOfWork; using GraphiQl; using GraphQL.Server; using GraphQL.Types; using GraphQlProject.Interfaces; using GraphQlProject.Mutations; using GraphQlProject.Query; using GraphQlProject.Schema; using GraphQlProject.Services; using GraphQlProject.Type; using Microsoft.Azure.Cosmos; using Microsoft.EntityFrameworkCore.Internal; var builder = WebApplication.CreateBuilder(args); // Add services to the container. builder.Services.AddControllers(); // Scoped Services builder.Services.AddTransient<IProduct, ProductService>(); builder.Services.AddTransient<IUser, UserService>(); // Repositories builder.Services.AddTransient<IUserRepository, UserRepository>(); // DB Context builder.Services.AddDbContext<C4PDbContext>(); // Register GraphQL type, query and schema builder.Services.AddSingleton<ProductType>(); builder.Services.AddSingleton<UserType>(); builder.Services.AddSingleton<ProductQuery>(); builder.Services.AddSingleton<UserQuery>(); builder.Services.AddSingleton<ProductMutation>(); builder.Services.AddSingleton<ISchema, ProductSchema>(); builder.Services.AddSingleton<ISchema, UserSchema>(); builder.Services.AddGraphQL(x => x.EnableMetrics = false).AddSystemTextJson(); // Cosmos // builder.Services.AddSingleton(_ => new CosmosClient("")); // Units Of Work builder.Services.AddScoped<IManageUserDocuments, ManageUserDocuments>(); // builder.Services.AddTransient<IManageUserDocuments, ManageUserDocuments>(); // Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle builder.Services.AddEndpointsApiExplorer(); builder.Services.AddSwaggerGen(); var app = builder.Build(); // Configure the HTTP request pipeline. if (app.Environment.IsDevelopment()) { app.UseSwagger(); app.UseSwaggerUI(); } app.UseGraphiQl("/graphql"); app.UseGraphQL<ISchema>(); app.Run();
错误信息
System.AggregateException:部分服务无法构造(验证服务描述符时出错,无法解析
Microsoft.EntityFrameworkCore.IDbContextFactory<C4PDbContext>服务以激活ManageUserDocuments)---> (内部异常 #1) System.InvalidOperationException:验证服务描述符时出错,无法解析
Microsoft.EntityFrameworkCore.IDbContextFactory<C4PDbContext>服务以激活ManageUserDocuments---> (内部异常 #2) System.InvalidOperationException:验证服务描述符时出错,无法解析
Microsoft.EntityFrameworkCore.IDbContextFactory<C4PDbContext>服务以激活ManageUserDocuments
解决方案
1. 替换DbContext注册方式为工厂模式
原Program.cs中使用AddDbContext<C4PDbContext>()仅注册了DbContext实例,未注册IDbContextFactory<C4PDbContext>,而ManageUserDocuments的构造函数依赖该工厂。需将DbContext注册代码替换为AddDbContextFactory,并配置Cosmos连接:
// 从配置文件读取Cosmos连接字符串 var cosmosConnectionString = builder.Configuration.GetConnectionString("CosmosDb"); // 注册DbContext工厂 builder.Services.AddDbContextFactory<C4PDbContext>(options => { options.UseCosmos(cosmosConnectionString, databaseName: "c4p"); });
同时确保appsettings.json中添加对应连接字符串配置:
{ "ConnectionStrings": { "CosmosDb": "你的Cosmos DB连接字符串" } }
2. 修复ManageUserDocuments中的同步阻塞异步问题
原代码中使用dbContextFactory.CreateDbContextAsync().GetAwaiter().GetResult()同步阻塞异步方法,易导致死锁。建议延迟初始化DbContext,调整后的代码如下:
public class ManageUserDocuments : IManageUserDocuments { private IUserRepository? _userRepository; private readonly IDbContextFactory<C4PDbContext> _dbContextFactory; private C4PDbContext? _c4pDbContext; public ManageUserDocuments(IDbContextFactory<C4PDbContext> dbContextFactory) { _dbContextFactory = dbContextFactory ?? throw new ArgumentNullException(nameof(dbContextFactory)); } // 延迟初始化DbContext,避免构造函数中阻塞异步调用 private C4PDbContext C4pDbContext => _c4pDbContext ??= _dbContextFactory.CreateDbContext(); private void Dispose(bool disposing) { if (disposing) { _c4pDbContext?.Dispose(); } } public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } public Task<int> SaveChangesAsync() { return C4pDbContext.SaveChangesAsync(); } public IUserRepository UserRepository { get { return _userRepository ??= new UserRepository(C4pDbContext); } } }
3. 移除冗余的DbContext注册
替换为AddDbContextFactory后,需删除原有的builder.Services.AddDbContext<C4PDbContext>()代码,避免DI容器出现冲突注册。
内容的提问来源于stack exchange,提问作者GThree

