Injecting runtime value into Unity dependency resolver

Sec*_*per 3 c# dependency-injection unity-container asp.net-web-api

I am working on a webapi project and using Unity as our IOC container. I have a set of layered dependencies something like the following:

unityContainer.RegisterType<BaseProvider, CaseProvider>(new HierarchicalLifetimeManager());
unityContainer.RegisterType<IRulesEngine, RulesEngine>();
unityContainer.RegisterType<IQuestionController, QuestionController>();
unityContainer.RegisterType<IAPIThing, WebAPIThing>();
Run Code Online (Sandbox Code Playgroud)

Now the constructor for BaseProvider accepts an int as a parameter which is the Case identifier. WebAPIThing takes a BaseProvider in its constructor. Normally in a non web scenario I would inject the case id using something like:

public static IAPIThing GetIAPIThing(int caseId)
{
  return CreateUnityContainer().Resolve<IAPIThing >(new ParameterOverride("caseId", caseId).OnType<CaseProvider>());
}
Run Code Online (Sandbox Code Playgroud)

But that only works when I explicitly call that method. In a Web API scenario I am using a config.DependencyResolver = new UnityDependencyResolver(unityContainer); to resolve my api controllers.

I would guess I will still need to influence how the DependencyResolver resolves that BaseProvider object at runtime.

Anyone had to do something similar?

EDIT 1
I have tried using the following which appears to work:

unityContainer.RegisterType<BaseProvider>(
        new HierarchicalLifetimeManager()
        , new InjectionFactory(x => 
                    new CaseProvider(SessionManager.GetCaseID())));
Run Code Online (Sandbox Code Playgroud)

Ste*_*ven 5

您试图将运行时值(case id)注入对象图,这意味着您使对象图的配置,构建和验证变得复杂.

你应该做的是将原始价值提升到自己的抽象.这听起来可能很愚蠢,但这种抽象在描述其功能方面会做得更好.例如,在您的情况下,抽象应该命名为ICaseContext:

public interface ICaseContext
{
    int CurrentCaseId { get; }
}
Run Code Online (Sandbox Code Playgroud)

通过int有效地隐藏这个抽象背后:

  • 使这个角色int非常明确.
  • 使用int您的应用程序可能需要的任何其他类型的值删除任何冗余.
  • int在构建对象图之后,延迟解析此问题.

您可以ICaseContext在应用程序的核心层中定义它,每个人都可以依赖它.在Web API项目中,您可以定义此ICaseContext抽象的Web API特定实现.例如:

public class WebApiCaseContext : ICaseContext
{
    public int CurrentCaseId
    {
        get { return (int)HttpContext.Current.Session["CaseId"];
    }
}
Run Code Online (Sandbox Code Playgroud)

此实现可以注册如下:

unityContainer.RegisterType<ICaseContext, WebApiCaseContext>();
Run Code Online (Sandbox Code Playgroud)

UPDATE

请注意,您自己的new CaseProvider(SessionManager.GetCaseID())配置并不能解决所有问题,因为这意味着在验证对象图时必须有一个会话,在应用程序启动期间和单元/集成测试中都不会出现这种情况.