Альтернатива локатора службы в ASP.NET MVC [закрыта]

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

Однако мой вопрос касается именно этого случая:

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. Этот единственный контекст данных используется, потому что контекст вызывается каждым методом в репозитории, поэтому кажется целесообразным совместно использовать один контекст для всего жизненного цикла объекта репозитория.

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

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


person Levi Botelho    schedule 03.01.2013    source источник
comment
Этот вопрос слишком субъективен. лучше очень расплывчато.   -  person Travis J    schedule 04.01.2013
comment
Я отредактировал вопрос, пытаясь уточнить, о чем я спрашивал.   -  person Levi Botelho    schedule 04.01.2013


Ответы (3)


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


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


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

person sellmeadog    schedule 03.01.2013
comment
Я учитывал это при написании своего репозитория, однако, поскольку каждый метод в репозитории использует одно и то же соединение, удобно связать время жизни соединения с жизнью экземпляра хранилища. Есть ли веская причина не делать этого? - person Levi Botelho; 04.01.2013
comment
Если ваш контроллер используется в ASP.NET MVC, то каждый метод не будет использовать одно и то же соединение, потому что каждый запрос будет создавать экземпляр нового контроллера, таким образом, новый репозиторий и, следовательно, новое соединение. - person sellmeadog; 04.01.2013
comment
Я обновил вопрос, добавив дополнительную информацию в ответ на ваш комментарий. - person Levi Botelho; 04.01.2013
comment
Спасибо за обновления. Хорошее рассуждение о создании контекста. - person Levi Botelho; 04.01.2013
comment
Обновил мой ответ хорошим ресурсом об использовании EF с шаблонами репозитория и единицы работы. - person sellmeadog; 04.01.2013

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

Вместо этого введите Lazy, Func или фабрику:

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

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

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

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

person StriplingWarrior    schedule 03.01.2013
comment
Я бы рекомендовал этот подход, если вы не контролируете репозиторий. - person sellmeadog; 04.01.2013

Вы спрашиваете, следует ли вставлять соединение с базой данных в конструктор репозитория? Вы можете попробовать использовать шаблон проектирования Abstract Factory, внедрив соединение с базой данных 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.
}

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

person Raymond Saltrelli    schedule 03.01.2013