如何用工厂模式与Microsoft.Extensions.DependencyInjection注册多接口实现并解决报错
错误原因
你当前的注册逻辑仅将ProdDeployApplicationService、NonProdDeployApplicationService作为IDeployApplicationService接口的实现注册到了DI容器,容器中不存在这两个实现类自身的服务注册,因此工厂中调用GetRequiredService<ProdDeployApplicationService>()直接获取实现类实例时,会抛出服务未注册异常。
解决方案
以下两种常用方案均可解决问题,可根据实际场景选择:
方案1:注册实现类自身到DI容器
修改Program.cs的注册逻辑,额外注册两个实现类本身,不需要修改工厂代码:
public static IHostBuilder CreateHostBuilder(string[] args) => Host.ConfigureServices((hostContext, services) => { //[...] services.AddScoped<IDeployApplicationServiceFactory, DeployApplicationServiceFactory>(); // 新增:注册两个实现类自身的服务 services.AddScoped<ProdDeployApplicationService>(); services.AddScoped<NonProdDeployApplicationService>(); // 若其他业务逻辑需要直接注入IDeployApplicationService,可保留下面两行,不需要可删除 services.AddScoped<IDeployApplicationService, ProdDeployApplicationService>(sp => sp.GetRequiredService<ProdDeployApplicationService>()); services.AddScoped<IDeployApplicationService, NonProdDeployApplicationService>(sp => sp.GetRequiredService<NonProdDeployApplicationService>()); //[...] });
该方案性能最优,工厂获取实例的逻辑不需要做任何调整即可正常运行。
方案2:调整工厂逻辑,从接口实现集合中匹配实例
如果不想额外注册实现类,可直接修改工厂代码,从已注册的IDeployApplicationService接口实现集合中匹配对应实例,不需要修改注册逻辑:
public IDeployApplicationService GetService(string environment) { // 获取所有已注册的IDeployApplicationService实现 var allImplementations = serviceProvider.GetServices<IDeployApplicationService>(); if (environment.ToLower() == "prod") { return allImplementations.First(x => x is ProdDeployApplicationService); } else { return allImplementations.First(x => x is NonProdDeployApplicationService); } }
该方案适合实现类数量极少的场景,无需调整DI注册代码,缺点是每次调用都需要遍历实现集合,性能略低于方案1。
可选简化方案(仅适合实现类无DI依赖的场景)
如果ProdDeployApplicationService和NonProdDeployApplicationService没有其他需要从DI容器注入的依赖,可直接在工厂中new对应的实例,不需要在DI容器中注册这两个实现类,进一步简化注册代码。
内容的提问来源于stack exchange,提问作者surprised_ferret
相关产品推荐
相关产品推荐

