用不同的配置多次注册同一个对象

本文关键字:注册 一个对象 配置 | 更新日期: 2023-09-27 18:02:32

我有这个api客户端ICommunicationClient(url, tenant)注册在我的IoC容器。现在我面临的情况是,我可以有1到n api客户端。我需要登记所有的人,我不知道该怎么处理。我在SI中看到过这个RegisterCollection

我正在考虑使用ICommunicationClientProvider作为实际客户端的包装器。它包含一个列表,其中包含所有已注册的客户端和用于检索它们的方法。我觉得这不是最好的方法,当然,它"迫使"我去触摸应用的其他部分。

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

承载集合

public class CommunicationClientCollection : Dictionary<string, ICommunicationClient>
{
}

这里我将集合注册到SI

        var clients = new CommunicationClientProvider();
        foreach (var supportedTenant in supportedTenants)
        {
            clients.CommunicationClientsCollection
                .Add(supportedTenant, new CommunicationClient(
                    new Uri(configuration.AppSettings["communication_api." + supportedTenant]),
                    new TenantClientConfiguration(supportedTenant)));
        }
        container.RegisterSingleton<ICommunicationClientProvider>(clients);

你知道更好的方法吗?这是一个正常的场景,例如当您有多个数据库时。

更新: - - ITenantContext部分这基本上就是我的租户上下文界面的样子:

public interface ITenantContext
{
    string Tenant { get; set; }
}

这是我调用通信api的地方:

public class MoveRequestedHandler : IHandlerAsync<MoveRequested>
{
    private readonly IJctConfigurationService _communicationClient;
    private readonly ITenantContext _tenantContext;
    public MoveRequestedHandler(IJctConfigurationService communicationClient, ITenantContext tenantContext)
    {
        _communicationClient = communicationClient;
        _tenantContext = tenantContext;
    }
    public async Task<bool> Handle(MoveRequested message)
    {
        _tenantContext.Tenant = message.Tenant;
        _communicationClient.ChangeApn(message.Imei, true);
        return await Task.FromResult(true);
    }
}

我在这里注册了ITenantContext

container.RegisterSingleton<ITenantContext, TenantContext>();

租户在MoveRequested对象(message.Tenant)中定义。如何使CommunicationClient意识到该租户?

用不同的配置多次注册同一个对象

如果添加ICommunicationClientProvider抽象导致您在整个应用程序中进行彻底的更改,那么显然有什么地方出了问题。您通常应该能够添加功能并进行更改,而无需进行全面更改。事实上,我认为你们目前的设计已经允许这样做了。

你的ICommunicationClientProvider)就像一个工厂,而工厂几乎从来都不是正确的解决方案。相反,使用Composite设计模式会好得多。例如:

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) =>
        this.clients[this.tenantContext.CurrentTenantName].ClientMethod(parameter);
}

你可以按以下方式注册这个类:

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)));
}
container.RegisterSingleton<ICommunicationClient>(
    new TenantCommunicationClientComposite(
        new AspNetTenantContext(),
        dictionary));

这里的ITenantContext是一个抽象,它允许您获得代表当前请求运行的当前租户。AspNetTenantContext是一种实现,它允许您在ASP中检索当前租户。网络应用程序。您可能已经编写了一些代码来检测当前租户;您可能需要将该代码移动到这样的AspNetTenantContext类。