Web API中的依赖注入

时间:2018-10-31 18:36:43

标签: asp.net-web-api dependency-injection dependencies

我对构建依赖项的正确方法有疑问。

想象一下,您有一个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);
        }
}

我不太确定我在依赖注入方面是否做对了:

  • 服务在构造函数中初始化,但配置 在执行请求之前未知。服务的客户 可能不会调用Configure,并且可能会导致问题( 生成器模式的作品在这里?)。
  • 服务本身应该负责配置的加载吗?

从依赖注入的角度来看,此示例中还有其他问题吗?

谢谢。

2 个答案:

答案 0 :(得分: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'是对服务构造函数的依赖。

P.S。不尊重@Ahmed Sherien,但不要使用Unity,它又旧又慢!!! ;-)

答案 1 :(得分:0)

在这种情况下,我将使用键控解决方案...如果您使用的是团结,则类似这样:

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);
    }
}