我们正在构建一个与其他系统具有多个集成接触点的应用程序。我们正在有效地使用Unity来满足所有依赖注入需求。整个业务层使用接口驱动方法构建,实际实现在应用程序引导期间注入外部组合根。
我们希望以优雅的方式处理集成层。业务类和存储库依赖于IIntegrationController<A, B>
接口。几个IIntegrationController<A, B>
实现一起表示在后台与一个目标系统的集成 - 形成一个集成层。目前,我们在开始时将组合根中的所有内容连接起来。此界面的消费者也预先在适当的InjectionConstrutor
和ResolvedParameter
注册。大多数类型都使用PerResolveLifetime
运行,而消耗IIntegrationController
的业务类也分别针对每个请求上下文进行解析。
参考下面的代码。
// IIntegrationController Family 1
// Currently the default registration for IIntegrationController types injected into the business classes
container.RegisterType<IIntegrationController<A, B>, Family1-IntegrationController<A, B>>();
container.RegisterType<IIntegrationController<C, D>, Family1-IntegrationController<C, D>>();
// IIntegrationController Family 2 (currently not registered)
// We want to be able to register this, or manage this set of mapping registrations separately from Family 1,
// and be able to hook these up dynamically instead of Family-1 on a per-resolve basis
container.RegisterType<IIntegrationController<A, B>, Family2-IntegrationController<A, B>>();
container.RegisterType<IIntegrationController<C, D>, Family2-IntegrationController<C, D>>();
// Repository/Business Class that consume IIntegrationControllers.
// There is a whole family of IIntegrationController classes being hooked in,
// and there are multiple implementations for the family (as shown above). A typical AbstractFactory scenario.
container.RegisterType(typeof(Repository<Z>), new PerResolveLifetimeManager(),
new InjectionConstructor(
new ResolvedParameter<IIntegrationController<A, B>>(),
new ResolvedParameter<IIntegrationController<C, D>>())
);
问题陈述:
我们希望能够在运行时切换整个IIntegrationController<A, B>
族。在解决业务类时,我们希望根据上下文中可用的请求参数为其注入正确版本的IIntegrationController<A, B>
。
IIntegrationController
的直接消费者也通过Unity解决,因为它会动态地注入到另一个类中。DependencyOverride
和ResolveOverride
课程,但这需要覆盖整套家庭2 IIntegrationController
分辨率,而不仅仅是能够切换整个层。InjectionFactory
? This link提出了一种方法,但我们无法顺利开展工作。答案 0 :(得分:2)
您的设计的好处在于您已经拥有正确的抽象。您使用通用抽象,因此只需在已经SOLID设计之上应用正确的模式即可解决问题。
换句话说,使用代理:
// This class should be considered part of your composition root.
internal class IntegrationControllerDispatcher<TRequest, TResult>
: IIntegrationController<TRequest, TResult>
{
private readonly IUserContext userContext;
private readonly Family1_IntegrationController<A, B> family1Controller;
private readonly Family2_IntegrationController<A, B> family2Controller;
public IntegrationControllerDispatcher(
IUserContext userContext,
Family1_IntegrationController<A, B> family1Controller,
Family2_IntegrationController<A, B> family2Controller) {
this.userContext = userContext;
this.family1Controller = family1Controller;
this.family2Controller = family2Controller;
}
public TResult Handle(TRequest request) {
return this.GetController().Handle(request);
}
private IIntegrationController<TRequest, TResult> GetController() {
return this.userContext.IsInFamily("family1"))
? this.family1Controller
: this.family2Controller;
}
}
使用此类,您可以将整个配置简化为:
container.RegisterType<IUserContext, AspNetUserContext>();
container.RegisterType(
typeof(IIntegrationController<,>),
typeof(IntegrationControllerDispatcher<,>));
container.RegisterType(typeof(Repository<>), typeof(Repository<>));
请注意以下事项:
IntegrationControllerDispatcher
直接取决于他们。这个
class是一个基础结构逻辑,应该放在里面
你的作文根。IUserContext.IsInFamily
之后,在这种情况下,这只是一个例子)。