Внедрение зависимостей в. Внедрение зависимостей в .NET. Руководство по применению этого механизма. Net приложениях. Книга демонстрирует основные паттерны на обычном языке C#, поэтому вы в полной мере поймете, как работает механизм внедрения зависимостей
Скачать 5.66 Mb.
|
7. .BasedOn 8. .Configure(r => r.LifeStyle.PerWebRequest)); 9. 10. container.Register(AllTypes 11. .FromAssemblyContaining 12. .Where(t => t.Name.EndsWith("Service")) 13. .WithService 14. .FirstInterface()); 15. 16. container.Register(AllTypes 17. .FromAssemblyContaining 18. .Where(t => t.Name.EndsWith("Policy")) 19. .WithService 20. .Select((t, b) => new[] { t.BaseType })); 21. 22. string connectionString = ConfigurationManager 23. .ConnectionStrings["CommerceObjectContext"] 24. .ConnectionString; 25. 26. container.Register(AllTypes 27. .FromAssemblyContaining 28. .Where(t => t.Name.StartsWith("Sql")) 29. .WithService 30. .Select((t, b) => new[] { t.BaseType }) 31. .Configure(r => r.LifeStyle.PerWebRequest 32. .DependsOn((new 33. { 34. connString = connectionString 35. })))); 36. } 37. } Строка 5, 10, 16, 26: Вызовы Register 112 CommerceWindsorInstaller кажется сложным, но важно отметить, что он инкапсулирует четыре вызова метода Register и что это единственный способ, с помощью которого он взаимодейст вует с контейнером. Остальная часть кода сейчас не важна. В нем используются соглашения для конфигурации контейнера. Более подробно об API механизма автоматической регистрации Castle Windsor вы можете прочитать в разделе "Конфигурирование контейнера" (глава "Castle Windsor"). Поскольку шаблонное приложение является веб-сайтом, Resolve и Release должны быть реализованы в единой паре. Для каждого HTTP-запроса вы должны преобразовать диаграмму объектов, которая будет обрабатывать этот запрос, а когда это закончится, вы должны выпустить его снова. Вы делаете это из класса под названием WindsorControllerFactory , который наследуется от DefaultControllerFactory , относящегося к ASP.NET MVC – более подробно о шве ASP.NET MVC вы можете прочитать в разделе "Построение ASP.NET MVC приложений". ASP.NET MVC фреймворк вызывает метод GetControllerInstance для того, чтобы преобразовать IControllers и метод ReleaseController при обработке запроса. Ниже приведены подходящие для нас методы вызова методов Resolve и Release : protected override IController GetControllerInstance( RequestContext requestContext, Type controllerType) { var controller = this.container.Resolve(controllerType); return (IController)controller; } public override void ReleaseController(IController controller) { this.container.Release(controller); } В методе GetControllerInstance вы передаете аргумент controllerType в метод Resolve и возвращаете результирующую диаграмму объектов. При обработке запроса ASP.NET MVC фреймворк вызывает метод ReleaseController с экземпляром IController , созданным до этого с помощью метода GetControllerInstance , и вы можете передать этот экземпляр controller в метод Release Обратите внимание на то, что это единственное появление методов Resolve и Release во всей базе кода приложения. Этот пример погружается несколько глубже предыдущего примера, который демонстрировал паттерн Com position Root, но в сущности это тот же самый код. Паттерн Composition Root указывает, где вам следует формировать диаграммы объектов, тогда как Register Resolve Release имеет дело с тем, как использовать DI-контейнер в пределах Composition Root. В следующей главе я сделаю обзор большего количества DI-паттернов, но перед тем, как это сделать, я хочу сделать небольшой крюк и обсудить то, как DI-контейнеры приспосабливаются к всеобщей .NET экосистеме. 113 3.4. Перспектива DI-контейнеров Т еперь, когда я описал, что такое DI-контейнер и как применить его в Composition Root, я хочу слегка сменить темп и предоставить вам обзор текущего состояния DI-контейнеров в .NET экосистеме. Это такие самые устойчивые аспекты DI-контейнеров, как историческое происхождение, и то, почему доступно так много контейнеров с открытым исходным кодом. Поскольку для выбора предлагается большое изобилие DI-контейнеров, я также хочу предоставить вам некоторое руководство по тому, как выбрать контейнер. В ыбор DI-контейнера Решение использовать механизм внедрения зависимостей в качестве технологии не должно зависеть от выбора конкретного DI-контейнера. Механизм внедрения зависимостей в первую очередь является технологией, и я буду использовать Poor man's DI на протяжении почти всех частей "Каталог DI" и "DI самостоятельно" для того, чтобы подчеркнуть этот вопрос. Однако DI-контейнер упростит вашу жизнь, поэтому используйте его там, где только можете. Если использовать контейнеры согласно выделенным в этой книге паттернам, то можно столкнуться с несколькими недостатками, но нужно рассмотреть еще кое-что. П роцесс принятия решения DI-контейнер – это стабильная зависимость, поэтому с точки зрения DI использование DI- контейнера не является проблемой, но существуют другие, второстепенные проблемы, которые нужно рассмотреть: Добавление другой библиотеки всегда добавляет некоторую сложность в приложение – не в терминах удобства сопровождения, а в терминах кривой обучения. Новым разработчикам нужно будет не только понять код приложения, но также понять API выбранного DI-контейнера. Надеюсь, что в этой главе я сумел дать вам понять, что с помощью изолированного использования контейнера в Composition Root вы сможете защитить контейнер от начинающих разработчиков. Если вы используете механизм автоматической регистрации, то контейнер может даже взять на себя заботу об инфраструктуре, не привлекая при этом к себе внимание. За исключением платформы Managed Extensibility Framework (MEF), вам нужно разворачивать сборки DI-контейнера вместе со своим приложением. Это могло бы потенциально иметь легальные последствия, хотя это и не правдоподобно. Все универсальные DI-контейнеры с открытым исходным кодом имеют разрешающие лицензии, но я не судья, поэтому не делайте ставку на мои слова: проконсультируйтесь со своим собственным консультантом. И еще раз за исключением MEF все остальные DI-контейнеры являются библиотеками с открытым исходным кодом. Для каждого из этих контейнеров вам приходится оценивать, насколько вы доверяете людям или организации, создавшим эти контейнеры. Существуют технические различия между различными DI-контейнерами. Во введении к части "DI-контейнеры" я предоставил вам таблицу, в которой перечисляются преимущества и недостатки каждого контейнера, рассматриваемого 114 в этой книге. Вы можете использовать эту таблицу как стартовую точку, а потом чтение глав о каждом из контейнеров станет для вас интересным. Выбор DI-контейнера не должен быть сложным. Возьмите один для раскрутки, а потом посмотрите, подходит ли он вашим нуждам – если не подходит, то замените его другим. Когда вы заключите DI-контейнер в Com position Root, вы сможете заменять контейнеры относительно свободно. Выбранные DI-контейнеры Я не хочу рассказывать вам о том, какой DI-контейнер выбрать. Выбор DI-контейнера включает в себя больше чем просто техническую оценку. Вы также должны оценить, подходит ли вам лицензионная модель, доверяете ли вы людям и организации, которая разрабатывает и поддерживает в работоспособном состоянии DI-контейнер, насколько он подходит IT -стратегии вашей организации и т.д. Большинство .NET DI-контейнеров являются проектами с открытым исходным кодом – это также следует иметь ввиду, поскольку для них может и не быть официальной поддержки, а документация часто ограничена. В таблице 3-4 перечисляются DI-контейнеры, рассматриваемые в части "DI-контейнеры". Выбор основывается на таких критериях, как релевантность, доля на рынке, характерные черты, но этот список является субъективным и неокончательным. Несколько популярных контейнеров (например, Ninject) не включены в этот список, главным образом, из-за ограничений во времени и пространстве. Таблица 3-4: Выбранные DI-контейнеры. Доступно больше контейнеров, но эти выбраны либо потому что они широко используются, либо они представляют собой интересный аспект DI или потому что они станут важными в будущем Название Организация Комментарии Castle W indsor Open Source Состоявшийся и широко используемый StructureMap Open Source Состоявшийся и широко используемый Spring.NET SpringSource Состоявшийся и широко используемый порт Java Spring DI-контейнера Autofac Open Source Наиболее современный DI-контейнер, созданный на основании характеристик языка C# 3.0 Unity Microsoft patterns& practices Первая роль компании Microsoft в пространстве DI, но не продукт по существу Managed Ext ensibility Fram ework (MEF) Microsoft Поставляется вместе с .NET 4, но в действительности не является DI- контейнером Часть "DI-контейнеры" посвящена этим DI-контейнерам, причем для каждого из них выделена отдельная глава. Обратите внимание на то, как в этой области доминируют проекты с открытым исходным кодом и другие некоммерческие проекты, причем компания Microsoft играет незначительную роль в этом деле. 115 Microsoft и DI Несмотря на то, что платформа .NET является продуктом компании Microsoft, другие организации (часто отдельные лица) становятся более известными, когда дело доходит до механизма внедрения зависимостей в .NET . Вкратце это может относиться к тому факту, что компания Microsoft не предлагает ни одного DI-контейнера в стандартной библиотеке классов (BCL). Хотя как предложение единственным DI-контейнером компании Microsoft является появившийся относительно недавно Unity. Думаю, справедливо будет сказать, что за множество первых лет жизни .NET Framework компания Microsoft блаженно игнорировала любую сущность DI. Не просто точно объяснить, почему так происходило, и я сомневаюсь, что это когда-либо было явной стратегией. Краткая история DI в .NET Ниже приведена моя субъективная попытка сделать обзор истории DI в .NET для того, чтобы объяснить, почему компания Microsoft столь долго игнорировала механизм внедрения зависимостей (см. рисунок 3-14). Насколько я осведомлен, на этот вопрос нет авторитетного ответа. Рисунок 3-14: Временные рамки релизов выбранных платформ и DI-контейнеров. Обратите внимание на то, насколько состоявшейся оказалась Java в 2004 году по сравнению с .NET . Кажется, что до того, как попасть в .NET, DI выросла из сообщества Java с открытым исходным кодом. Мартин Фаулер опубликовал свою статью о DI в начале 2004 года в качестве реакции на непрерывную работу. В это время текущей версией .NET была версия 1.1, и компания Microsoft работала над версией .NET 2.0, в то время как Java быстрыми темпами достигала своего десятилетия. Я верю, что компания Microsoft в то время просто направила свои усилия в другом направлении. Даже если бы они в то время были хорошо осведомлены насчет DI, думаю, для них все равно были бы приоритетны другие возможности, например, дженерики. В июне 2004 года был выпущен DI-контейнер StructureMap, обогнав Castle W indsor всего на полгода. 116 В конце 2005 года компания Microsoft выпустила .NET 2.0, главной новой возможностью которой стали дженерики, а затем Microsoft решила сфокусироваться на WCF, WPF, а позднее LINQ для своего следующего крупного релиза (Visual Studio 2008). Т ем временем DI медленно приобретал популярность. В 2006 году появился Spring.NET. В начале 2008 M icrosoft patterns& practices выпустили Unit y, которая для большинства последователей школы Microsoft казалась приближением к DI. Этот четырехгодовалый промежуток времени дал опытным личностям хороший старт, а популярность DI- контейнеров, подобных StructureMap и Castle W indsor, возросла. О снова DI Интересным наблюдением из рисунка 3-14 является то, как быстро члены сообщества .NET разработчиков подхватили идею DI. Согласно домашней странице Castle Windsor понятия зарождались даже до статьи Фаулера: Castle вырос из проект а Apache Avalon в середине 2003 года в виде попыт ки создания самой прост ой инверсии управления контейнером. Веб-страничка Castle от 01.08.2008 На протяжении длительного времени для .NET DI-контейнеры оставались источником движения, а многие ведущие члены симпатизировали разработке Agile. В действительности даже если архитектура модульного приложения имеет множество различных преимуществ, все равно кажется, что в первую очередь именно вопрос тестируемости мотивировал людей на разработку и использование DI-контейнеров (что также является справедливым и в моем случае). В это время официальной методологией разработки в компании Microsoft была Microsoft Solutions Framework (M SF) 3.0 – каскадный процесс, который оставляет небольшое пространство для таких приемов разработки Agile, как разработка через тестирование (T DD). Короче говоря, это было совершенно другим образом мышления. С течением времени разработка Agile, T DD и DI доказали свою эффективнос ть и приобрели популярность, а Microsoft , казалось, также медленно продвигалась к поддержке этого стиля. В противоположност ь ситуации 2004 года команды разработки теперь открыто обсуждают DI, T DD и другие вопросы, относящиеся к разработке Agile. DI-конте йнеры компании Microsoft С течением времени команда patterns&practices компании Microsoft разработала множество корректур для различных областей, относящихся к .NET . Большая часть опыта, приобретенного из этих проектов, использовалас ь для определения рамок дальнейшей разработки самого .NET Fram ework. В качестве примера Updater Application Block предоставил богатый опыт, который в дальнейшем использовался при разработке ClickOnce. В начале 2008 года команда patterns& practices выпустила свою первую Com munity T echnical Preview (CTP) (небольшая ознакомительная версия) версию Unity, их новый DI- контейнер, а в апреле 2008 года вышел релиз 1.0. Unity – это развитый DI-контейнер, который поддерживает композицию объектов, механизм управления жизненным циклом и 117 механизм перехвата. Это не продукт компании Microsoft, но скорее проект с открытым исходным кодом, который возможно разработан Microsoft. O bje ct Builder Кажется, существует некоторая путаница в вопросе о том, когда точно patterns&practices представили миру DI-контейнер. При введении в начале 2006 года Enterprise Library для .NET 2.0 команды patterns&practices она содержала модуль с названием Object Builder, который использовался для создания сложных объектов из составных элементов. Она была атрибутно-управляемой и работала только для классов, которые были сильно интегрированы с самим Object Builder. Его никогда не представляли как DI-контейнер, хотя было общепризнано, что на его основе можно было бы создать DI-контейнер. Многие люди ошибочно верят, что Object Builder был первым DI-контейнером компании Microsoft, но это не правда: этот титул получил Unity. Вместе с .NET 4.0 компания Microsoft предоставила Managed Ext ensibility Fram ework (MEF), который отмечает, что к первым DI сущностям явно обращались в рамках самой .NET . При первом выпуске MEF не был полноценным контейнером, который поддерживал все три аспекта DI, но скорее был движком, который фокусировался на композиции объектов. Команда MEF хорошо осведомлена о таких аспектах, как управление жизненным циклом и механизм перехвата, поэтому не маловероятно, что мы будем свидетелями того, что MEF будет включен в полноценный DI-контейнер в следующие несколько лет (как я пишу здесь, технические обзоры указывают на то, что это будет именно так). 118 3.5. Резюме DI-контейнер может стать чрезвычайно полезным инструментом, если вы правильно его используете. Самое важное – понять, что использование механизма внедрения зависимостей никоим образом не зависит от использования DI-контейнера. Приложение может состоять из множества слабо связанных классов и модулей, и ни один из этих модулей не должен ничего знать о контейнере. Наиболее эффективный способ убедиться в том, что код приложения не осведомлен ни об одном DI-контейнере, – жестко реализовать паттерн Register Resolve Release в Composition Root. Это эффективно предостережет вас от случайного применения анти-паттерна Service Locator, потому что он заключает контейнер в небольшую изолированную область кода. Если использовать DI-контейнер таким образом, то он станет движком, который берет на себя заботу о большей части инфраструктуры приложения. Он формирует диаграмму объектов на основании его конфигурации. Это может быть особенно существенно, если вы применяете конфигурацию, базирующуюся на соглашениях – при соответствующей реализации он может заботиться о формировании диаграммы объектов, и вы можете сконцентрировать ваши усилия на добавлении новых классов, реализующих новые возможности. Контейнер будет автоматически обнаруживать новые классы, которые соответствуют установленным соглашениям, и делать их доступными для пользователей. В некоторых случаях вам нужно больше явного контроля над конфигурацией контейнера. Наиболее эффективно использовать код в качестве конфигурации, но если вам нужно поддерживать позднее связывание, вы также можете использовать XML для конфигурации DI-контейнеров. Эта глава подытоживает первую часть книги. Целью первой части было знакомство с DI. Предыду щие главы в общих чертах знакомили с механизмом внедрения зависимостей, тогда как данная глава объясняет то, как DI-контейнеры относятся к DI, а также в общих чертах объясняет процесс проектирования приложения. Я подумал, что исторический обзор DI-контейнеров в .NET экосистеме как раз подходит для завершения главы, чтобы действительно ввести в игру различные контейнеры. Глава представляет Composition Root и Register Resolve Release как два мини-паттерна, которые относятся к DI-контейнерам. В следующей главе мы сосредоточимся на паттернах проектирования. |