ASP.NET Core Web API服务无法构造的依赖注入问题排查
错误信息
System.AggregateException: 'Some services are not able to be constructed (Error while validating the service descriptor 'ServiceType: Middleware.Core.ApplicationService.Services.IProductService Lifetime: Transient ImplementationType: Middleware.Core.ApplicationService.Queries.ProductService': Unable to resolve service for type 'Middleware.Infra.DataAccessLayer.ApplicationDbContextFactory' while attempting to activate 'Middleware.Core.ApplicationService.Queries.ProductService'.)'
错误原因
依赖注入容器无法找到你自定义的ApplicationDbContextFactory的注册项。你调用的AddDbContextFactory方法,注册的是Entity Framework内置的IDbContextFactory<ApplicationDbContext>实现,而非你自己编写的ApplicationDbContextFactory类。
解决方案
方案一:注册自定义工厂类
在依赖注入配置中添加自定义工厂的注册,同时规范DbContext的泛型参数写法:
- 调整
ApplicationDbContext构造函数(使用泛型版本的DbContextOptions,符合EF标准):
public class ApplicationDbContext : DbContext { public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options) : base(options) { } public DbSet<Product> Products { get; set; } }
- 同步修改自定义工厂类的参数:
public class ApplicationDbContextFactory : IDbContextFactory<ApplicationDbContext> { private readonly DbContextOptions<ApplicationDbContext> _options; public ApplicationDbContextFactory(DbContextOptions<ApplicationDbContext> options) { _options = options; } public ApplicationDbContext CreateDbContext() { return new ApplicationDbContext(_options); } }
- 更新依赖注入配置:
var connectionString = builder.Configuration.GetConnectionString("DefaultConnection"); // 注册泛型DbContextOptions builder.Services.AddSingleton<DbContextOptions<ApplicationDbContext>>(sp => new DbContextOptionsBuilder<ApplicationDbContext>() .UseSqlServer(connectionString) .Options); // 注册自定义工厂 builder.Services.AddTransient<ApplicationDbContextFactory>(); // 保留原有服务注册 builder.Services.AddTransient<IProductService, ProductService>();
方案二:使用EF内置的IDbContextFactory
如果不需要自定义工厂逻辑,直接依赖EF原生的IDbContextFactory<ApplicationDbContext>即可,无需自己编写工厂类:
- 修改
ProductService的依赖项:
public class ProductService : IProductService { private readonly IDbContextFactory<ApplicationDbContext> _contextFactory; public ProductService(IDbContextFactory<ApplicationDbContext> contextFactory) { _contextFactory = contextFactory; } public async Task<IEnumerable<Product>> GetAllAsync() { using (ApplicationDbContext context = _contextFactory.CreateDbContext()) { IEnumerable<Product> products = await context.Products.ToListAsync(); return products.Select(p => new Product() { Id = p.Id, ProductName = p.ProductName, Price = p.Price, Qty = p.Qty }); } } }
- 简化依赖注入配置:
var connectionString = builder.Configuration.GetConnectionString("DefaultConnection"); builder.Services.AddDbContextFactory<ApplicationDbContext>(options => options.UseSqlServer(connectionString)); builder.Services.AddTransient<IProductService, ProductService>();
方案三:直接注入ApplicationDbContext(推荐)
如果你的服务是瞬态或范围生命周期,可直接注入ApplicationDbContext,由DI容器自动管理其生命周期:
- 修改
ProductService:
public class ProductService : IProductService { private readonly ApplicationDbContext _context; public ProductService(ApplicationDbContext context) { _context = context; } public async Task<IEnumerable<Product>> GetAllAsync() { IEnumerable<Product> products = await _context.Products.ToListAsync(); return products.Select(p => new Product() { Id = p.Id, ProductName = p.ProductName, Price = p.Price, Qty = p.Qty }); } }
- 依赖注入配置:
var connectionString = builder.Configuration.GetConnectionString("DefaultConnection"); builder.Services.AddDbContext<ApplicationDbContext>(options => options.UseSqlServer(connectionString)); builder.Services.AddTransient<IProductService, ProductService>();
内容的提问来源于stack exchange,提问作者Amir Monfared

