基于运行时输入的依赖关系注入

本文关键字:依赖 关系 注入 输入 运行时 | 更新日期: 2023-09-27 18:30:59

CCI 正在编写一个外观,以从不同来源获取数据、规范化和格式化数据。我是使用 asp.net 5 并尝试依赖注入的新手,但我遇到了问题。 我想知道如何根据运行时输入解决依赖项。根据路由,我想实例化正确的存储库。例如,如果我通过了丰田,我想实例化一个丰田存储库,如果我通过了福特,我想实例化一个福特存储库。这些存储库还具有每个存储库唯一的依赖项。所有存储库共享相同的 ICarRepository 接口,并依赖于相同的接口但不同的具体实现。我想过使用工厂来创建存储库,但随后必须将每个存储库的依赖项注入工厂,这感觉不对。随着存储库数量的增加,需要注入的依赖项数量也会增加。目前,我只是在工厂中更新存储库及其依赖项,这也感觉不对,不是很可靠。也许我的架构有问题?

[Route("api/v1/[controller]")]
public class CarsController : Controller
{
    private IDataFormatter<Product> _formatter;
    private ILogger _logger;
    private ICarRepositoryFactory _repositoryFactory;
    public CarssController(ILogger<CarsController> logger, IProductRepositoryFactory repositoryFactory, IDataFormatter<Car> formatter)
    {
        _logger     = logger;
        _repositoryFactory = repositoryFactory;
        _formatter  = formatter;
    }
    [HttpGet("{carType}")]
    public async Task<IEnumerable<Car>> GetCars(string carType)
    {
        var repository = _repositoryFactory.Create(carType);
        var cars = await repository.GetAll();
        foreach(var car in cars)
        {
            _formatter.Format(car);
        }
        return cars;
    }
}
public class CarRepositoryFacotry : ICarRepositoryFactory
{
    private Dictionary<string, Func<ICarRepository>> _carRepositories = new Dictionary<string, Func<ICarRepository>>();
    private ILogger<ICarRepository> _logger;
    private IOptions<WebOptions> _webOptions;
    private IOptions<DisplayInfoOptions> _displayOptions;
    public CarRepositoryFacotry(ILogger<ICarRepository> logger, IOptions<WebOptions> webOptions, IOptions<DisplayInfoOptions> displayInfoOptions)
    {
        _logger = logger;
        _webOptions = webOptions;
        _displayInfoOptions = displayInfoOptions;
        _carRepositories.Add("toyota", () => new ToyotaRepository(_logger, new DisplayInfoRepository(_displayInfoOptions), new ToyotaMapper(), _options));
        _carRepositories.Add("ford", () => new FordRepository(_logger, new DisplayInfoRepository(_displayInfoOptions), new FordMapper(), _options));
    }
    public ICarRepository Create(string carType)
    {
        Func<ICarRepository> repo;
        _carRepositories.TryGetValue(carType, out repo);
        return repo.Invoke();
    }
}

我目前正在使用 asp.net 5 中的内置依赖项框架,但如果它使事情变得更容易,我愿意使用 autofac。任何帮助或评论都将是一个很大的帮助。

基于运行时输入的依赖关系注入

使用注入所有存储库的工厂是可行的方法(并且比临时的"新"依赖项要好得多)

public interface IVehicleRepository
{
    bool CanHandle(string vendor); // example how to deal with choosing appropriate repository
    IEnumerable<Vehicle> GetAll();
}
public class VehicleFactory
{
    private readonly IVehicleRepository[] repositories;
    public VehicleFactory(IVehicleRepository[] repositories)
    {
        this.repositories = repositories;
    }
    public IVehicleRepository Create(string vendor) {
        return repositories.Single(r => r.CanHandle(vendor));
    }
}

用法:

[Route("api/v1/[controller]")]
public class CarController : Controller
{
    private readonly VehicleFactory factory;
    public CarController(VehicleFactory factory)
    {
        this.factory = factory;
    }
    [HttpGet("{vehicleType}")]
    public IEnumerable<Vehicle> GetVehicles(string vehicleType)
    {
        var repository = factory.Create(vehicleType);
        var vehicles = repository.GetAll();
        foreach (var vehicle in vehicles)
        {
            // Process(vehicle)
        }
        return vehicles;
    }
}

我是这样看的:

  1. 您的汽车控制器将ICarRepository作为构造函数参数并与之合作
  2. 你必须注册自己的IControllerFactory,它将分析路由参数并创建具有具体存储库的控制器的具体实例

谷歌的第一个链接。可能不是最好的,但很好。

http://www.codeproject.com/Articles/560798/ASP-NET-MVC-Controller-Dependency-Injection-for-Be

我的团队使用Castle Windsor,这是一个IoC容器,可以轻松解决我们所有的依赖关系。(应该类似于Autofac,但我在企业应用程序中更频繁地看到温莎城堡)

在您的情况下,您可以

1. 像这样注册FordRepository

public class RepositoriesInstaller : IWindsorInstaller
{
    public void Install(IWindsorContainer container, IConfigurationStore store)
    {
        container.Register(
            Classes.FromThisAssembly(),
            Component.For<DisplayInfoRepository>().ImplementedBy<DisplayInfoRepository>
              .DependsOn(Dependency.OnValue("_displayInfoOptions", displayInfoOptionsObject)),
                                           // whatever property name you have in DisplayInfoRepository
            Component.For<ICarRepository>().ImplementedBy<FordRepository>().Named("Ford")
              .DependsOn(Dependency.OnComponent(typeof(Logger), nameof("Logger")))
              .DependsOn(Dependency.OnComponent(typeof(DisplayInfoRepository), nameof(DisplayInfoRepository)))
              .DependsOn(Dependency.OnComponent(typeof(FordMapper), nameof(FordMapper)))
              .DependsOn(Dependency.OnValue("_option", optionObject)),
                                        // what ever property name you have in FordRepository
        );
    }
}

2. 启动容器:

// application starts...
var container = new WindsorContainer();
container.Install(FromAssembly.This());
// clean up, application exits
container.Dispose();

3. 根据这样的字符串获取您的汽车存储库

var carRepo = container.Resolve<ICarRepository>("Ford");

如果有任何问题,请告诉我!非常感谢点赞!