Альтернативный поиск сервисов в ASP.NET MVC

Прочитав сообщение в блоге Марка Симанна вместе с ответом, который ссылается на него, я понял недостатки использования шаблона локатора службы по сравнению с внедрением зависимости через конструктор класса. Я также прочитал это внедрение зависимостей с помощью Ninject, MVC 3 и использование шаблона локатора служб, в котором также обсуждается эта проблема.

Тем не менее, мой вопрос касается этого конкретного случая:

public class MyController
{
    public void GetData()
    {
        using (var repository = new Repository())
        {
            // Use the repository which disposes of an Entity Framework
            // data context at the end of its life.
        }
    }

    // Lots of other methods.
}

Здесь у меня есть контроллер, который содержит метод, который вызывает хранилище, которое автоматически создает внутренний контекст данных Entity Framework. Этот единственный контекст данных используется, потому что контекст вызывается каждым методом в хранилище, поэтому имеет смысл использовать один и тот же контекст на протяжении всего времени существования объекта хранилища.

Теперь, когда класс контроллера большой, существует большая вероятность, что данный репозиторий не будет использоваться. Поскольку я предполагаю (возможно, неправильно), что создание экземпляра DC является дорогостоящей операцией, я бы предпочел не делать этого. Использование шаблона локатора службы позволяет мне отложить создание экземпляра до тех пор, пока контекст фактически не понадобится, но, учитывая действительные аргументы против него в приведенных выше ссылках, я бы предпочел избежать этого.

Так что я хотел бы знать, есть ли более эффективный способ использования внедрения зависимостей в вышеупомянутом случае, который бы помешал мне без необходимости создавать экземпляр моего хранилища и нижележащий контекст данных.

3 ответа

Решение

Я думаю, что ответ зависит от того, как ваш репозиторий управляет соединениями. Если при создании он открывает соединение с базой данных, то, я думаю, проблема в вашем репозитории, а не в Dependency Injection. Ваш репозиторий должен открывать соединение только тогда, когда сделан запрос, и закрывать его, как только получен ответ. Следуя этой схеме, внедрение зависимостей все еще имеет смысл.


Исходя из вашего обновления, вам все-таки лучше использовать DI, потому что EF не открывает соединение с базой данных при построении, только когда сделан запрос. Ваш контекст данных настолько мал, что стоит небольшого количества накладных расходов, необходимых для создания контекста для каждого запроса.


Еще один комментарий: вам также следует подумать о том, чтобы вставить свой контекст данных в свои репозитории и позволить контейнеру DI контролировать время существования контекста. Это позволяет использовать один и тот же контекст в одном или нескольких хранилищах во время одного запроса. Вот довольно хороший ресурс, объясняющий, как реализовать шаблоны Repository и Unit of Work с помощью Entity Framework в ASP.NET MVC.

Поскольку класс контроллера велик, существует большая вероятность, что соединение не будет использоваться ни в одной конкретной конструкции, поэтому нет смысла создавать экземпляр репозитория и открывать соединение, используя стандартный DI на основе конструктора.

Внедрить Lazy, Funcили вместо фабрики:

public class MyController
{
    // Use constructor injection to populate this.
    private Func<MyRepository> _repository;

    public void GetData()
    {
        using (var repository = _repository())
        {
            // ...
        }
    }
}

Таким образом, вы можете избежать создания реальных экземпляров, пока они вам не понадобятся.

Ответ @sellmeadog тоже хорош.

Вы спрашиваете, стоит ли вводить соединение с базой данных в конструктор репозитория? Вы можете попробовать использовать шаблон проектирования Abstract Factory, внедряющий фабрику соединений с базой данных вместо фактического соединения с базой данных.

public class MyController
{
    public void GetData()
    {
        using (var repository = new Repository(IDatabaseConnectionFactory dbConnFac))
        {
            // Use the repository which disposes of a database connection
            // at the end of its life.
        }
    }

    // Lots of other methods.
}

Таким образом, вы получаете преимущества внедрения зависимостей, в то же время позволяя репозиторию управлять жизненным циклом своих соединений с базой данных.

Другие вопросы по тегам