Подтвердить что ты не робот

Веб-формы и инъекции зависимостей

Сейчас я внедряю инфраструктуру Injection Dependency в существующее приложение WebForms (используя Castle Windsor).

У меня довольно глубокий опыт работы с DI, и я очень сильно рекомендую впрыск конструктора над инъекцией сеттера. Если вы знакомы с Webforms, вы знаете, что инфраструктура ASP.Net обрабатывает конструкцию страниц и объектов управления, что делает невозможным истинное вложение конструктора.

Мое текущее решение - зарегистрировать контейнер в событии Application_Start для Global.asax и сохранить контейнер как общедоступную статическую переменную в Global. Затем я просто разрешаю каждую услугу, которая мне нужна непосредственно на странице, или управление, когда она мне нужна. Поэтому в верхней части каждой страницы я получаю код следующим образом:

private readonly IMyService _exposureManager = Global.IoC.Resolve<IMyService>();
private readonly IMyOtherService _tenCustomersExposureManager = Global.IoC.Resolve<IMyOtherService>();

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

Есть ли более элегантное решение для использования DI с Webforms?

4b9b3361

Ответ 1

Я согласен с @DarinDimitrov, что MVP - интересный вариант. Однако при работе с устаревшим приложением переписывание существующей страницы в шаблон MVP - это чертовски работа. В этом случае лучше начать с шаблона Locator (но только в ваших классах пользовательского интерфейса), как вы уже делаете. Однако измените одно. Не выставляйте выбранный контейнер DI в приложение, так как я ожидаю, что вы выполняете его с свойством Global.IoC.

Вместо этого создайте статический метод Resolve<T> в классе Global. Это полностью скрывает контейнер и позволяет выполнять операции замены, не изменяя ничего на ваших веб-страницах. Когда вы это делаете, нет никакой пользы в использовании Common Service Locator, как предлагает @Wiktor. Локатор общих служб - это еще одна абстракция для чего-то, что не нужно абстрагировать (поскольку вы уже отбросили контейнер с помощью Global.Resolve<T>).

К сожалению, с веб-формами, на самом деле нет хорошего способа сделать это. Для Simple Injector я написал руководство по интеграции для веб-форм, который в основном описывает использование метода Global.Resolve<T>, но также показывает способ тестирования, если классы страницы могут быть созданы. Руководство также может использоваться для других контейнеров DI.

Кстати, пожалуйста, имейте в виду, что с Castle Windsor все, что вы запрашиваете, должно быть открыто выпущено (Register Resolve Release pattern). Это немного неприятно (IMO) и отличается от того, как работают другие контейнеры, и может быть источником утечек памяти, если вы этого не сделаете правильно.

Последняя записка. Можно выполнить инъекцию конструктора с помощью Web Forms. Ну... вроде, так как это вызовет перегруженный конструктор, используя отражение после того, как Form был создан с использованием конструктора по умолчанию, поэтому это вызывает Temporal Coupling.

Ответ 2

Есть ли более элегантное решение для использования DI с Webforms?

Yeap, шаблон MVP позволяет вам иметь четкое разделение проблем в приложении WebForms. И когда у вас есть разделение проблем и слабая связь, DI легко.

И в ASP.NET MVC, который встроен.

Ответ 3

ASP.NET MVC имеет IDependencyResolver и класс статического менеджера, который позволяет вам установить и установить преобразователь. Мне не понравилась идея ссылки на System.Web.Mvc в проекте веб-форм, поэтому я пошел с IServiceLocator, который делает примерно то же самое вещь:

public static class Bootstrapper
{
    private static readonly IUnityContainer _container = new UnityContainer();

    public static void Initialize()
    {
        ServiceLocator.SetLocatorProvider(() => new UnityServiceLocator(_container));

        _container.RegisterType<IDriverService, DriverService>();
    }

    public static void TearDown()
    {
        _container.Dispose();
    }
}

public class Global : HttpApplication
{
    protected void Application_Start(object sender, EventArgs e)
    {
        Bootstrapper.Initialize();
    }

    protected void Application_End(object sender, EventArgs e)
    {
        Bootstrapper.TearDown();
    }
}

Затем в классе страницы...

IDriverService service = ServiceLocator.Current.GetInstance<IDriverService>();

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

В моем примере используется Unity, но вы можете легко адаптировать его к любой другой реализации DI.

Ответ 4

Как @DarinDimitrov говорит, что шаблон MVP - это способ использовать DI/IOC с Webforms.

Либо вы можете выполнить собственную реализацию, либо использовать существующую инфраструктуру. Я хорошо слышал о Webforms MVP, но я его на самом деле не использовал.

Согласно документам, он встроил поддержку DI через Castle Windsor, Autofac и Unity. Он также имеет автоматическое обнаружение на основе конвенций для докладчиков.

Ответ 5

На самом деле то, что вы только что создали, - это ваша собственная реализация Locator. Но, почти наверняка, реализация уже существует для рамки IoC по вашему выбору.

http://commonservicelocator.codeplex.com/