2016-08-16 14 views
0

У меня есть клиент 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); 

Вы знаете лучший способ сделать это? Это обычный сценарий, например, когда у вас несколько баз данных.

UPDATE: - 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 об этом арендаторе?

+0

Ваш вопрос в настоящее время слишком расплывчатый. Пожалуйста, покажите код с вашим вопросом. – Steven

+0

Я обновил потенциальное решение, дайте мне знать, если требуется более подробная информация. – Rober

ответ

2

Если добавление абстракции ICommunicationClientProvider приводит к радикальным изменениям во всем приложении, очевидно, что-то не так. Обычно вы должны иметь возможность добавлять функции и вносить изменения, не выполняя радикальных изменений. И, на самом деле, я думаю, что ваш нынешний дизайн уже позволяет это.

Ваш ICommunicationClientProvider) действует как завод, и factories are hardly ever the right solution. Вместо этого вы гораздо лучше используете Composite design pattern. Например:

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.NET. У вас, вероятно, уже есть код для обнаружения текущего арендатора; вам может потребоваться переместить этот код на такой класс AspNetTenantContext.

+0

ICommunicationClient - это куча интерфейсов, не уверенный, как сделать последний бит в вашем закрытом классе. Это консольное приложение, в котором нет никаких компонентов ASP.Net. Добавляя: ICommunicationClient Я в конечном итоге «реализую» все методы из интерфейса: S – Rober

+0

@Rober: В вашем консольном приложении у вас будет другой ' ITenentContext'. Если ваш «ICommunicationClient» имеет много членов, вы нарушаете [Принцип разделения сегрегации] (https://en.wikipedia.org/wiki/Interface_segregation_principle). Вы должны это исправить, и это решит проблему с уродливым композитом. – Steven

+0

Спасибо @Steven все еще не совсем уверен, где заполнить ITenantContext, но я заработаю его. Я получил составные вещи – Rober

 Смежные вопросы

  • Нет связанных вопросов^_^