Доступ к HttpContext в конструкторе для поддельного DI - PullRequest
0 голосов
/ 02 июня 2018

Я работаю над приложением asp.net mvc, у которого еще нет DI или модульного тестирования.Поэтому я начал реструктурировать приложение для проведения модульных тестов, разделив его на 3 уровня: Контроллеры - Сервисы - DataAccess.

Некоторые контроллеры использовали Session и Cookies для хранения и получения значений.Поэтому я создаю интерфейс и класс, который занимается сохранением и получением значений из Session и Cookies.

Я сделал это только с помощью модульного тестирования и никогда не запускал приложение.

Так как приложение сделалоУ меня не было DI. Я создал на контроллере контроллера ContextService, указав в качестве входного параметра HttpContext контроллера.

Однако при запуске приложения значения не были получены или сохранены в сеансе или файлах cookie.Похоже, что HttpContext является нулевым на конструкторе.

Вопрос 1: Как мне поступить с моим ContextService.Следует ли использовать статическое свойство HttpContext.Current для доступа к сеансу и файлам cookie (как это будет проверяться модулем) или ...?

Вопрос 2: Если вы знаете другое решение, как его следует адаптировать вДля того, чтобы иметь также DI в будущем.

1 Ответ

0 голосов
/ 02 июня 2018

Я создал на контроллере контроллера ContextService, задав в качестве входного параметра HttpContext контроллера.

Передав HttpContext от контроллера в службу,вы делаете контроллер ответственным за создание этого сервиса.Это тесно связывает контроллер со службой, в то время как целью является слабая связь.

если он использует статическое свойство HttpContext.Current для доступа к сеансу и файлам cookie

как будетэто будет юнит-тест

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

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

Вам следует скрыть доступ к HttpContext.Current за абстракцией.Но когда вы это сделаете, убедитесь, что вы определили абстракцию так, чтобы она лучше всего подходила для вашего приложения.Например, внимательно посмотрите, чего хочет ваш ContextService.Действительно ли он хочет получить доступ к файлам cookie?Возможно нет.Или он хочет имя или идентификатор текущего вошедшего в систему пользователя?Это более вероятно.Таким образом, вы должны смоделировать свои абстракции вокруг этого.

В качестве примера определите абстракцию, которая позволяет коду приложения получать доступ к информации о зарегистрированном пользователе, используя IUserContext:

public interface IUserContext
{
    string UserName { get; }
}

OneВозможная реализация этой абстракции - та, которая извлекает эту информацию из файла cookie HTTP:

public class CookieUserContext : IUserContext
{
    public string UserName => HttpContext.Current.Cookies["name"];
}

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

Если вам интересно, книга Внедрение зависимостей в .NET Марк Симанн (Mark Seemann) подробно рассказывает об этих видах паттернов и принципах, таких как причины применения DI, предотвращения тесной связи.Второе издание этой книги (выход которого запланирован на осень 2018 г.), которое я и Симанн, даже более подробно рассказываем о вещах, с которыми вы боретесь, таких как предотвращение утечек абстракций, как отделить поведениев классы и проектирование приложений с использованием принципов SOLID.Домашняя страница книги содержит ссылку для загрузки первой главы, которую можно загрузить бесплатно.

...