Веб-формы и внедрение зависимостей - PullRequest
18 голосов
/ 21 января 2012

Я нахожусь в процессе внедрения инфраструктуры внедрения зависимостей в существующее приложение 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?

Ответы [ 6 ]

19 голосов
/ 21 января 2012

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

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

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

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

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

4 голосов
/ 21 января 2012

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

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

И в ASP.NET MVC это встроено.

2 голосов
/ 03 октября 2018

Знайте, что это довольно старо, но теперь в WebForms есть DI, начиная с .NET 4.7.2. Относительно этой статьи: Блог ASP.NET: использование внедрения зависимостей в приложении WebForms

Просто установите Microsoft.AspNet.WebFormsDependencyInjection.Unity пакет и зарегистрируйте ваши классы в Global.asax:

protected void Application_Start(object sender, EventArgs e)
{
    var container = this.AddUnity();

    container.RegisterType<IPopularMovie, MovieManager>();
    container.RegisterType<IMovieRepository, XmlMovieRepository>();
}

Надеюсь, это поможет.

2 голосов
/ 21 января 2012

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();
    }
}

Тогда в вашем классе Page ...

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

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

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

1 голос
/ 21 января 2012

Как говорит @DarinDimitrov, шаблон MVP - это путь для использования DI / IOC с веб-формами.

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

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

0 голосов
/ 21 января 2012

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

http://commonservicelocator.codeplex.com/

...