具有多个 WebAPI 项目的简单注入器

Simple Injector with multiple WebAPI projects

我有一个包含多个 WebAPI 项目的 C# 解决方案。其中一个项目,我们称之为项目 A,已经成功地使用了 SimpleInjector。我正在尝试将 SimpleInjector 添加到这些 WebAPI 项目中的另一个项目 B,但我遇到了问题。

我正在尝试像在项目 A 中那样在项目 B 中创建第二个容器,但是当我这样做并尝试构建解决方案时,在项目 A 中存在异常,它是在项目 B 之后构建的, 在 container.Verify() 方法处。它告诉我位于项目 B (IUserService) 的接口未在项目 A 中正确注册,但项目 A 不使用此接口。

在 Global.asax.cs 的项目 B 中,我有这样的配置:

/* Dependency Injection */
var container = new Container();
container.Options.DefaultScopedLifestyle = new AsyncScopedLifestyle();


container.Register<IUserService>(() => { return new UserService(); }, Lifestyle.Scoped);
container.RegisterWebApiControllers(GlobalConfiguration.Configuration);

container.Verify();

GlobalConfiguration.Configuration.DependencyResolver = new SimpleInjectorWebApiDependencyResolver(container);

在项目A中,我有这样的配置:

/* Dependency Injection */
var container = new Container();
container.Options.DefaultScopedLifestyle = new AsyncScopedLifestyle();

container.Register<ILog>(() => { return LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); }, Lifestyle.Scoped);
container.Register<IFundRepository>(() => { return new IporangaFundRepository(dbConnectorMiddle); }, Lifestyle.Scoped);
container.Register<ITradeRepository>(() => { return new IporangaTradeRepository(dbConnectorMiddle, middleReadClient); }, Lifestyle.Scoped);
container.Register<ITradeManager, TradeManager>(Lifestyle.Scoped);

container.Register<ITradeService>(() => new TradeService(container.GetInstance<ITradeManager>()),Lifestyle.Scoped);
container.Register<ISimulationService>(() => new SimulationService(container.GetInstance<ITradeService>()), Lifestyle.Scoped);
container.Register<IBookerService>(() => new BookerService(container.GetInstance<ITradeService>(), container.GetInstance<ISimulationService>()), Lifestyle.Scoped);
container.RegisterWebApiControllers(GlobalConfiguration.Configuration);

container.Verify();

GlobalConfiguration.Configuration.DependencyResolver = new SimpleInjectorWebApiDependencyResolver(container);

错误信息:

System.InvalidOperationException: 'The configuration is invalid. Creating the instance for type UserController failed. The constructor of type UserController contains the parameter with name 'userService' and type IUserService that is not registered. Please ensure IUserService is registered, or change the constructor of UserController.'

RegisterWebApiControllers 在幕后使用反射来搜索 ApiController 的实现。

我猜,根据您得到的错误,项目 B 被项目 A 引用,并且在项目 A 中对 container.RegisterWebApiControllers 的调用也找到并注册了项目 B 的控制器。

现在,当调用 .Verify() 时,它将扫描项目 B 中 ApiControllers 的构造函数,找到对 IUserService 的依赖并中断,因为项目 A 中实际上缺少此注册.

集成包包含 RegisterWebApiControllers 的另一个重载,它采用必须扫描的程序集数组 ApiControllers,而不是扫描所有引用的程序集。

假设项目 A 的程序集包含所有需要注册的 ApiControllers 此重载可以在项目 A 中使用,例如:

container.RegisterWebApiControllers(GlobalConfiguration.Configuration,
         new[] {typeof(MyApiControllerInProjectA).Assembly});

以下不是对您问题的回答,而是关于如何改进和简化项目 A 注册的建议。

我建议使用以下代码连接项目 A 的 Container 实例,而不是使用发布的代码:

var container = new Container();
container.Options.DefaultScopedLifestyle = new AsyncScopedLifestyle();

// For Log4NetAdapter<T>, please see: 
container.RegisterConditional(typeof(ILog),
    c => typeof(Log4NetAdapter<>).MakeGenericType(c.Consumer.ImplementationType),
    Lifestyle.Singleton,
    c => true);

container.RegisterInstance(dbConnectorMiddle);
container.RegisterInstance(middleReadClient);

container.Register<IFundRepository, IporangaFundRepository>(Lifestyle.Scoped);
container.Register<ITradeRepository, IporangaTradeRepository(Lifestyle.Scoped);
container.Register<ITradeManager, TradeManager>(Lifestyle.Scoped);

container.Register<ITradeService, TradeService>(Lifestyle.Scoped);
container.Register<ISimulationService, SimulationService>(Lifestyle.Scoped);
container.Register<IBookerService, BookerService(Lifestyle.Scoped);

container.RegisterWebApiControllers(GlobalConfiguration.Configuration);

container.Verify();

GlobalConfiguration.Configuration.DependencyResolver =
    new SimpleInjectorWebApiDependencyResolver(container);

这样更好,因为:

  • 注册被简化是因为它们只指定抽象(例如ITradeService)和实现(例如TradeService)之间的映射,同时让简单注入器Auto-Wire 通过检查构造函数的依赖关系来确定类型。
  • 不仅简化了注册,而且现在 Simple Injector 了解完整依赖关系图的结构,因此可以有效地代表您进行验证。例如,这将允许 Simple Injector 找到任何 Lifestyle Mismatches.
  • 条件注册用于 ILog 抽象。这允许简单注入器注入特定于消费类型的 ILog 实现。这允许您的日志库记录有关原始 class 的信息。这在您的注册中不起作用,它总是会注入一个包含您的注册类型的记录器。