Search code examples
c#dependency-injectionstructuremap

How to specify a dependency to a parent dependency?


I am working on a project:

  • that depends on multiple Services;
  • that depends on multiple HttpClient;
  • that depends on configurations per region: CA, US and EU.
public class CustomersService : ICustomersService
{
    public CustomersService(CustomersHttpClient customersHttpClient)
    // ...
}

public class CustomersHttpClient : ICustomersHttpClient
{
    public CustomersHttpClient(RegionConfiguration configuration)
    // ...
}

public class RegionConfiguration
{
    public string BaseUrl { get; set; }
    public string ApiKey { get; set; }
    // ...
}

I am able to configure the DI:

  
 var caConfiguration = new RegionConfiguration
 {
    BaseUrl = "https://site.ca",
    ApiKey = "secret"
    // ...
 };

 var usConfiguration = new RegionConfiguration
 {
    BaseUrl = "https://site.us",
    ApiKey = "secret"
    // ...
 };

 var euConfiguration = new RegionConfiguration
 {
    BaseUrl = "https://site.eu",
    ApiKey = "secret"
    // ...
 };

 var container = new Container(containerConfiguration =>
            {
                containerConfiguration
                    .For<ICustomerHttpClient>()
                    .Use<CustomerHttpClient>()
                    .Ctor<RegionConfiguration>("configuration")
                    .Is(caConfiguration);
                
                containerConfiguration
                    .For<IInvoiceHttpClient>()
                    .Use<InvoiceHttpClient>()
                    .Ctor<RegionConfiguration>("configuration")
                    .Is(caConfiguration);

                containerConfiguration
                    .For<ICustomersService>()
                    .Use<CustomersService>();

                containerConfiguration
                    .For<IInvoicesService>()
                    .Use<InvoicesService>();
            });

And able to query a region:

            var customersService = container.GetInstance<ICustomersService>();
            var customers = await customersService.GetEnabledCustomersAsync();

            foreach (var customer in customers)
            {
                System.Console.WriteLine(customer);
            }

But I am not able to specify the RegionConfiguration to the HttpClient to query a specific region.

How should I modify the DI configuration to be able to specify which ConfigurationRegion the HttpClient should use when requesting a service?

Example: one query to retrieve customers from US region and a second query to retrieve customers from EU region?

GitHub working example: https://github.com/tsawyer999/uri-di/blob/main/UriDi.Console/Program.cs

Thank you very much for your help!


Solution

  • You must named the container configuration by region key (ca,us,eu) first

    private static Container CreateContainer(Dictionary<string, RegionConfiguration> configurations)
    {
        return new Container(containerConfiguration =>
        {
            foreach (var kvp in configurations) 
            {
                containerConfiguration
                    .For<ICustomersService>()
                    .Use<CustomersService>()
                    .Ctor<ICustomerHttpClient>()
                    .Is<CustomerHttpClient>(act =>
                    {
                        act.Ctor<RegionConfiguration>("configuration").Is(kvp.Value);
                    })
                    .Named(kvp.Key);
    
                containerConfiguration
                    .For<IInvoicesService>()
                    .Use<InvoicesService>()
                    .Ctor<IInvoiceHttpClient>()
                    .Is<InvoiceHttpClient>(act =>
                    {
                        act.Ctor<RegionConfiguration>("configuration").Is(kvp.Value);
                    })
                    .Named(kvp.Key);
            }
        });
    }
    

    Then:

    container.GetInstance<ICustomersService>(region)