Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Injecting runtime value into Unity dependency resolver

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())));
like image 261
SecretDeveloper Avatar asked Dec 16 '25 15:12

SecretDeveloper


1 Answers

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.

like image 122
Steven Avatar answered Dec 19 '25 03:12

Steven



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!