Search code examples
dependency-injectionunity-container

Inject dependency in injected dependency with different InjectionConstructor parameters


I'm using a helpful RestClient, which handles Rest-calls to other Webservices. This RestClient is part of bigger Service-Clients which handle different Webservices by providing convenience-methods which are used by the businesslogic etc.. I'm using UnityContainers for dependency-injection.

I've got some sort of RestClient:

public interface IRestClient
{
    T PostSomething<T>();
}

public class RestClient : IRestClient
{
    public RestClient(string baseUrl) { }
    public T PostSomething<T>() { /* post something */ }
}

Which i use in multiple ServiceClients:

public interface IServiceClient1
{
    void Work1();
}

public class ServiceClient1 : IServiceClient1
{
    private RestClient client;
    private string myRestUrl = "ServiceUrl1";

    public ServiceClient1(IRestClient client)
    {
        this.client = client;
        client.SetUrl(myRestUrl); // i don't want to do this here. This should be done by unity when RestClient is instantiated
    }
    public void Work1()
    {
        /* do something */
        client.PostSomething<string>();
    }
}

public interface IServiceClient2
{
    void Work2();
}

public class ServiceClient2 : IServiceClient2
{
    private RestClient client;
    private string myRestUrl = "ServiceUrl2";

    public ServiceClient2(IRestClient client)
    {
        this.client = client;
        client.SetUrl(myRestUrl); // i don't want to do this here. This should be done by unity when RestClient is instantiated
    }
    public void Work2()
    {
        /* do something */
        client.PostSomething<string>();
    }
}

Now I want to Inject those classes with UnityContainers:

container.RegisterType<IServiceClient1, ServiceClient1 >();
container.RegisterType<IServiceClient2, ServiceClient2 >();

// And here comes the problem:
container.RegisterType<IRestClient, RestClient>(new InjectionConstructor("ThisParameterShouldBeSetByServiceClient"));

Both ServiceClients are much more different as shown in this example. This example may only show the problem.

I want to register the type RestClient and I want that ServiceClientX selects the string-parameter for the Constructor of RestClient. And I don't want to set the Url in the Constructor of ServiceClient.

How can I achieve this with UnityContainers?


Solution

  • You have to use a factory for this. If the ServiceClient decides how to create a RestClient:

    public class ServiceClient1 : IServiceClient1
    {
        private RestClient client;
        private string myRestUrl = "ServiceUrl1";
    
        public ServiceClient1(IRestClientFactory clientFactory)
        {
            this.client = clientFactory.CreateClient(myRestUrl);
        }
        public void Work1()
        {
            /* do something */
        }
    }
    

    Unity injects the Factory and not the RestClient.

    If the RestClient should be mocked the factory should be switched to a mock-factory.