我正在开发一个webapi项目并使用Unity作为我们的IOC容器。我有一组分层依赖项,如下所示:
unityContainer.RegisterType<BaseProvider, CaseProvider>(new HierarchicalLifetimeManager());
unityContainer.RegisterType<IRulesEngine, RulesEngine>();
unityContainer.RegisterType<IQuestionController, QuestionController>();
unityContainer.RegisterType<IAPIThing, WebAPIThing>();
现在,BaseProvider的构造函数接受一个int作为参数,它是Case标识符。 WebAPIThing在其构造函数中使用BaseProvider。通常在非Web场景中,我会使用类似的东西注入case id:
public static IAPIThing GetIAPIThing(int caseId)
{
return CreateUnityContainer().Resolve<IAPIThing >(new ParameterOverride("caseId", caseId).OnType<CaseProvider>());
}
但这只有在我明确调用该方法时才有效。在Web API场景中,我使用的是
config.DependencyResolver = new UnityDependencyResolver(unityContainer);
解析我的api控制器。
我猜我仍然需要影响DependencyResolver在运行时如何解析该BaseProvider对象。
任何人都必须做类似的事情吗?
编辑1
我尝试过使用以下似乎有效的方法:
unityContainer.RegisterType<BaseProvider>(
new HierarchicalLifetimeManager()
, new InjectionFactory(x =>
new CaseProvider(SessionManager.GetCaseID())));
答案 0 :(得分:5)
您正在尝试将运行时值(case id)注入对象图中,这意味着您使对象图的配置,构建和验证变得复杂。
你应该做的是将原始价值提升到自己的抽象。这听起来可能很愚蠢,但这种抽象在描述其功能方面会做得更好。例如,在您的情况下,抽象应该命名为ICaseContext
:
public interface ICaseContext
{
int CurrentCaseId { get; }
}
通过有效地隐藏int
这个抽象背后:
int
的角色。 int
类型值的冗余。int
,直到构建对象图形为止。您可以在应用程序的核心层中定义此ICaseContext
,并且每个人都可以依赖它。在Web API项目中,您可以定义此ICaseContext
抽象的特定于Web API的实现。例如:
public class WebApiCaseContext : ICaseContext
{
public int CurrentCaseId
{
get { return (int)HttpContext.Current.Session["CaseId"];
}
}
此实现可以注册如下:
unityContainer.RegisterType<ICaseContext, WebApiCaseContext>();
更新
请注意,您自己的new CaseProvider(SessionManager.GetCaseID())
配置并不能解决所有问题,因为这意味着在验证对象图时必须有一个会话,在应用程序启动期间和单元内部都不会出现这种情况。整合测试。