3

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>();

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>());
}

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())));
SecretDeveloper
  • 3,140
  • 2
  • 31
  • 36
  • 1
    Where is that `caseId` coming from? How is that `caseId` constructed by the caller of `GetIAPIThing`? Does this value come from a session, request param, cookie? – Steven Apr 29 '14 at 10:53
  • @Steven CaseId will be stored and provided from the session. – SecretDeveloper Apr 29 '14 at 10:56

1 Answers1

5

You are trying to inject a runtime value (the case id) into the object graph, which means you are complicating configuration, building, and verification of the object graph.

What you should do is promote that primitive value to its own abstraction. This might sound silly at first, but such abstraction will do a much better job in describing its functionality. In your case for instance, the abstraction should probably be named ICaseContext:

public interface ICaseContext
{
    int CurrentCaseId { get; }
}

By hiding the int behind this abstraction we effectively:

  • Made the role of this int very explicit.
  • Removed any redundancy with any other values of type int that your application might need.
  • Delayed the resolving of this int till after the object graph has been built.

You can define this ICaseContext in a core layer of your application and everybody can depend on it. In your Web API project you can define a Web API-specific implementation of this ICaseContext abstraction. For instance:

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

This implementation can be registered as follows:

unityContainer.RegisterType<ICaseContext, WebApiCaseContext>();

UPDATE

Do note that your own new CaseProvider(SessionManager.GetCaseID()) configuration does not solve all problems, because this means that there must be a session available when verifying the object graph, which will neither be the case during application startup and inside a unit/integration test.

Steven
  • 166,672
  • 24
  • 332
  • 435