基于运行时输入的依赖关系注入
本文关键字:依赖 关系 注入 输入 运行时 | 更新日期: 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;
}
}
我是这样看的:
- 您的汽车控制器将ICarRepository作为构造函数参数并与之合作
- 你必须注册自己的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");
如果有任何问题,请告诉我!非常感谢点赞!