web api中的依赖注入
Posted
技术标签:
【中文标题】web api中的依赖注入【英文标题】:Dependency injection in web api 【发布时间】:2019-04-05 00:15:57 【问题描述】:我有一个关于构建依赖关系的正确方法的问题。
假设你有一个 web api 控制器,它有一个带有两个参数的方法:id 和 bar。 控制器需要根据 'id' 值读取特定配置,并向应用了该配置的不同服务发出请求。
public class FooController : ApiController
private readonly IConfigurationProvider _configurationProvider;
private readonly IService _service;
public FooController(IConfigurationProvider configurationProvider, IService service)
_configurationProvider = configurationProvider;
_service = service;
public IHttpActionResult Bar(int id, int bar)
var configuration = _configurationProvider.GetConfiguration(id);
_service.Configure(configuration);
var barResult = _service.Bar(bar);
return Ok(barResult);
我不太确定我在依赖注入方面做得对:
服务在构造函数中初始化,但配置 在执行请求之前不知道。服务的客户 可能不会调用配置,它可能会导致问题(会某种 Builder 模式在这里工作?)。 服务本身是否应该负责其配置加载?从依赖注入的角度来看,这个例子还有其他问题吗?
谢谢。
【问题讨论】:
您的依赖结构似乎有误。控制器依赖于 IConfigurationProvider,但实际上不做任何事情,只是将检索到的配置传递给它也依赖的服务。此外,依赖项不应该是基础设施代码,IConfigurationProvider 看起来就像基础设施代码渗入您的控制器。所以真正应该发生的是,这些基础设施问题应该在您的组件注册代码中处理。 了解您正在使用的 IoC 容器也很好。 【参考方案1】:您可以尝试使用工厂类(构建器类可能是错误的)
public class ServiceFactory : IServiceFactory
private readonly Dictionary<int, IService> _services = new Dictionary<int, IService>();
private readonly IConfigurationProvider _configurationProvider;
public ServiceFactory(IConfigurationProvider configurationProvider)
_configurationProvider = configurationProvider;
public IService GetService(int id)
if (!_services.ContainsKey(id))
var config = _configurationProvider.GetConfiguration(id);
var service = new Service(config);
_services.Add(id, service);
return _services[id];
这将创建一个服务实例,并在工厂类的生命周期内保持对它的引用,因此它只需要创建一次。然后注册 ServiceFactory 并将其注入到你的控制器中。
public class FooController : ApiController
private readonly IServiceFactory _serviceFactory;
public FooController(IServiceFactory serviceFactory)
_serviceFactory = serviceFactory;
public IHttpActionResult Bar(int id, int bar)
var service = _serviceFactory.GetService(id);
var barResult = service.Bar(bar);
return Ok(barResult);
现在你的控制器仍然是可测试的,你不必担心 Configure() 被调用,因为 'id' 是对服务构造函数的依赖。
附:不尊重@Ahmed Sherien,但不要使用 Unity,它又旧又慢!!! ;-)
【讨论】:
【参考方案2】:在这些情况下,我会使用键控解析...如果您使用统一,则类似这样:
IUnityContainer container = new UnityContainer();
container.RegisterType<IConfiguration, ConfigurationType1>("Type1");
container.RegisterType<IConfiguration, ConfigurationType2>("Type2");
IConfiguration cfg1 = container.Resolve<IConfiguration>("Type1"); // return ConfigurationType1 object
IConfiguration cfg2 = container.Resolve<IConfiguration>("Type2"); // return ConfigurationType2 object
在您的情况下,实现将如下所示:
public class FooController : ApiController
private readonly IService _service;
public FooController(IService service)
_service = service;
public IHttpActionResult Bar(int id, int bar)
var configuration = container.Resolve<IConfiguration>(id.ToString());
_service.Configure(configuration);
var barResult = _service.Bar(bar);
return Ok(barResult);
【讨论】:
直接在控制器内部使用容器可能是个坏主意,首先现在你的控制器是不可测试的(如果你想测试你的控制器)它实际上让我想起了服务定位器模式太可怕了,其次,您的代码现在可以与您选择的 IoC 容器紧密耦合。在您的代码示例中,“容器”变量来自哪里? @matt_lethargic 我会在全局变量中定义它,但显然这也是个坏主意...... 是的,全局变量仍然很糟糕,仍然使您的控制器无法测试以上是关于web api中的依赖注入的主要内容,如果未能解决你的问题,请参考以下文章
.NET Core Web API使用依赖注入(DI)进行服务配置一
web API .net - .net core 对比学习-依赖注入
Simple Injector 无法在 Web API 控制器中注入依赖项