Обработка зависимостей с IoC, которые изменяются в пределах одного вызова функции - PullRequest
2 голосов
/ 09 апреля 2010

Мы пытаемся выяснить, как настроить внедрение зависимостей для ситуаций, когда у классов обслуживания могут быть разные зависимости в зависимости от того, как они используются. В нашем конкретном случае у нас есть веб-приложение, в котором 95% времени строка подключения одинакова для всего запроса (это веб-приложение), но иногда оно может измениться.

Например, у нас может быть 2 класса со следующими зависимостями (упрощенная версия - сервис фактически имеет 4 зависимости):

public LoginService (IUserRepository userRep)
{
}

public UserRepository (IContext dbContext)
{
}

В нашем контейнере IoC большинство наших зависимостей имеют автоматическую привязку, кроме контекста, для которого у меня есть что-то вроде этого (не фактический код, это из памяти ... это StructureMap) x.ForRequestedType (). С помощью () .WithCtorArg ( "ConnectionString") EqualTo (Session [ "ConnString"]);.

Для 95% нашего веб-приложения это работает отлично. Однако у нас есть некоторые функции типа администратора, которые должны работать с тысячами баз данных (по одной на каждого клиента). По сути, мы бы хотели сделать это:

public CreateUserList(IList<string> connStrings)
{
   foreach (connString in connStrings)
   {
       //first create dependency graph using new connection string 
       ????       
       //then call service method on new database
       _loginService.GetReportDataForAllUsers();
   }
}

Мой вопрос таков: как мы можем создать этот новый граф зависимостей каждый раз в цикле, сохраняя при этом что-то, что можно легко проверить?

Ответы [ 4 ]

2 голосов
/ 09 апреля 2010

Чтобы отложить создание объекта до времени выполнения, вы можете использовать фабрику:

public interface ILoginServiceFactory
{
    ILoginService CreateLoginService(string connectionString);
}

Использование:

public void CreateUserList(IList<string> connStrings)
{
    foreach(connString in connStrings)
    {
        var loginService = _loginServiceFactory.CreateLoginService(connString);

        loginService.GetReportDataForAllUsers();
    }
}
0 голосов
/ 11 апреля 2010

В итоге мы просто создали конкретный контекст и внедрили его, а затем изменили, создав класс-оболочку, который изменил строку соединения контекста. Казалось, работает нормально.

0 голосов
/ 09 апреля 2010

Таким образом, большинство UserRepository методов используют одну строку подключения, полученную из сеанса, но несколько методов должны работать со списком строк подключения?

Эту проблему можно решить, повысив зависимость строки соединения от IContext до репозитория и добавив две дополнительные зависимости - фабрику контекста и список всех возможных строк соединений, которые могут понадобиться репозиторию для его работы:

public UserRepository(IContextFactory contextFactory, 
                      string          defaultConnectionString, 
                      List<string>    allConnectionStrings)

Тогда каждый из его методов может построить столько IContext экземпляров, сколько им нужно:

// In UserRepository

public CreateUserList() {
    foreach (string connString in allConnectionStrings) {
        IContext context = contextFactory.CreateInstance(connString);
        // Build the rest of the dependency graph, etc. 
        _loginService.GetReportDataForAllUsers();
    }
}

public LoginUser() {
    IContext context = contextFactory.CreateInstance(defaultConnectionString);
    // Build the rest of the dependency graph, etc.
}
0 голосов
/ 09 апреля 2010

В цикле выполните:

container.With("connectionString").EqualTo(connString).GetInstance<ILoginService>()

где "connectionString" - это имя параметра конструктора строки в конкретной реализации ILoginService.

...