Rober Rober - 2 months ago 5
C# Question

Register same object multiple times with different configuration

I have this api client

ICommunicationClient(url, tenant)
registered in my IoC container. Now I'm facing the scenario where I can have 1 to n api clients. I need to register all of them and I'm not sure how to handle that. I've seen there's this
in SI though.

I'm considering use a
as a wrapper around the actual clients. It contains a list with all the registered clients and methods to retrieve them. I feel this is not the best approach and of course, it "forces" me to touch other pieces of the app.

public class CommunicationClientProvider : ICommunicationClientProvider
public CommunicationClientCollection CommunicationClientsCollection { get; set; }
public string Tenant { get; set; }

public ICommunicationClient GetClients()
return CommunicationClientsCollection[Tenant];
public void SetClients(CommunicationClientCollection clients)
CommunicationClientsCollection = clients;

public interface ICommunicationClientProvider
ICommunicationClient GetClients();
void SetClients(CommunicationClientCollection clients);

This to host the collection

public class CommunicationClientCollection : Dictionary<string, ICommunicationClient>

Here I register the collection against SI

var clients = new CommunicationClientProvider();
foreach (var supportedTenant in supportedTenants)
.Add(supportedTenant, new CommunicationClient(
new Uri(configuration.AppSettings["communication_api." + supportedTenant]),
new TenantClientConfiguration(supportedTenant)));

Do you know a better way of doing this? This is a normal scenario for example when you have multiple databases.

UPDATE: - ITenantContext part -
This is basically how my tenant context interface looks like:

public interface ITenantContext
string Tenant { get; set; }

and this is where I'm making my call to communication api:

private readonly ICommunicationClient _communicationClient;

public JctMoveToPrivateApnRequestedHandler(ICommunicationClient communicationClient)
_communicationClient = communicationClient;

public async Task<bool> Handle(MoveRequested message)
_communicationClient.Move(message.Id, true);
return await Task.FromResult(true);

The tenant is defined within the
object (
How can I make CommunicationClient aware of that tenant?


If adding an ICommunicationClientProvider abstraction causes you to make sweeping changes throughout your application, there is clearly something wrong. You should typically be able to add features and make changes without having to do sweeping changes. And as a matter of fact, I think your current design already allows this.

Your ICommunicationClientProvider) acts like a factory, and factories are hardly ever the right solution. Instead, your are much better of using the Composite design pattern. For instance:

sealed class TenantCommunicationClientComposite : ICommunicationClient
    private readonly ITenantContext tenantContext;
    private readonly Dictionary<string, ICommunicationClient> clients;

    public TenantCommunicationClientComposite(ITenantContext tenantContext,
        Dictionary<string, ICommunicationClient> clients) {
        this.tenantContext = tenantContext;
        this.clients = clients;

    object ICommunicationClient.ClientMethod(object parameter) =>

You can register this class as follows:

var dictionary = new Dictionary<string, ICommunicationClient>();
foreach (var supportedTenant in supportedTenants) {
    dictionary.Add(supportedTenant, new CommunicationClient(
        new Uri(configuration.AppSettings["communication_api." + supportedTenant]),
        new TenantClientConfiguration(supportedTenant)));

    new TenantCommunicationClientComposite(
        new AspNetTenantContext(),

Here the ITenantContext is an abstraction that allows you to get the current tenant on who's behalf the current request is running. The AspNetTenantContext is an implementation that allows you to retrieve the current tenant in an ASP.NET application. You probably already have some code to detect the current tenant; you might need to move that code to such AspNetTenantContext class.