Как избежать локатора служб/внедрить локатор служб с помощью CastleWindsor в ASP.NET MVC

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

Но есть некоторые конкретные случаи, когда внедрение зависимостей (внедрение конструктора) не будет работать. Например: я хочу иметь возможность разрешать свои зависимости по-прежнему с помощью IOC в некоторых служебных классах или методах расширения (например, HtmlHelper) в моих представлениях. Я знаю, что некоторые люди не согласятся с этим и предпочли бы оставить свои взгляды глупыми, но давайте не будем обсуждать это.

Таким образом, это в основном оставляет мне один вариант, и это использование... локатора сервисов. Итак, я знаю, что большинство людей считают Service Locator антишаблоном, и я понимаю, почему. Но как разрешить свои зависимости с помощью IOC, если вы не можете использовать внедрение зависимостей? Все, что я знаю, это то, что все же лучше использовать сервисный локатор для IOC, чем не иметь ничего. Я хотел бы избежать шаблона локатора сервисов, но, похоже, не понимаю, как его избежать в некоторых конкретных случаях.

Следующий вопрос... поэтому, даже если вам нравится/не нравится локатор сервисов. Как лучше всего реализовать это с помощью CastleWindsor?

Итак, я предполагаю, что варианты будут такими:

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

  2. Я также нашел: https://www.nuget.org/packages/CommonServiceLocator.WindsorAdapter и у него много загрузок.. (Тот же принцип, что и вариант 1, но более общий и обертывает контейнер, поэтому вы можете легко поменять инфраструктуру DI) Я просмотрел код и обнаружил, что у адаптера есть только методы для разрешения объектов . Так что я как бы задался вопросом, почему нет метода выпуска. Означает ли это, что у этого пакета есть проблемы с утечкой памяти с временными объектами образа жизни?

Надеюсь, кто-нибудь может дать мне несколько советов по этим вопросам!


person qkp    schedule 03.10.2015    source источник
comment
Можно ли преобразовать ваши служебные классы (я предполагаю, что они являются статическими классами или содержат статические методы) и ваш метод расширения в нестатические классы и заставить их объявлять свои зависимости в конструкторе, а затем заставить их реализовать некоторые интерфейсы и внедрить их в классы (я думаю, контроллеры), которые их используют? Я говорю это потому, что обычно все, что требует зависимостей, не должно быть статическим методом.   -  person Yacoub Massad    schedule 04.10.2015


Ответы (1)


Как избежать использования локатора сервисов в статических методах расширения (HTML Helpers)?

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

HTML-помощники

ОБНОВЛЕНИЕ 30 01 2017 г. Лучший подход к использованию внедрения зависимостей с помощниками HTML — использовать абстрактную фабрику, как в этом answer, который позволяет управлять временем существования контейнера зависимостей зависимостей HTML-помощника.

Когда вам нужно использовать статический метод, одним из подходов к внедрению зависимостей является использование внедрения свойств.

public static class MyHtmlHelperExtensions
{
    private static IHtmlHelperService htmlHelperService;

    // Property for use with dependency injection in the composition root
    public static IHtmlHelperService HtmlHelperService
    {
        set
        {
            if (value == null)
                throw new ArgumentNullException("value");
            if (htmlHelperService != null)
                throw new ArgumentExeption("HtmlHelperService cannot be set twice");
            htmlHelperService = value;
        }
    }

    // The static method simply calls the instance method of our service,
    // but does not contain any logic.
    public static MvcHtmlString MyHtmlHelper(this HtmlHelper htmlHelper)
    {
        return htmlHelperService.MyHtmlHelper(htmlHelper);
    }
}

По сути, статический помощник HTML — это просто фасад, который делегирует свои методы Aggregate Service., который содержит настоящие службы, выполняющие реальную работу.

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

// DIConfig.Register() will create the container and register all of our type mappings.
var container = DIConfig.Register();

// While we are still in the composition root, we instantiate and 
// assign our HtmlHelperService along with its dependency graph.
MyHtmlHelperExtensions.HtmlHelperService = container.Resolve<IHtmlHelperService>();

ПРИМЕЧАНИЕ. В MVC6 будет представление компонентов, которые больше похожи на контроллеры, чем на статические помощники HTML, чтобы исключить необходимость создания статических помощников HTML с зависимостями.

Атрибуты

Что касается Attributes, которые являются еще одним распространенным источником проблем внедрения зависимостей, которые приводят к локатору службы, лучший подход — определить атрибут без поведения, что можно сделать, разделив ActionFilterAttribute производных типов на "немой" атрибут и глобальный фильтр действий, дружественный к DI, который разрешается в корне композиции. См. >этот пример MVC IActionFilter и этот пример MVC AuthorizeAttribute.

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

person NightOwl888    schedule 04.10.2015