Главная страница
Навигация по странице:

  • Что находится в загруженном файле

  • Какие платформы поддерживаются .NET 3.5 SP1, .NET 4 Сколько он стоит

  • StructureMap основана данная глава

  • Контейнер или O bjectFactory

  • Внедрение зависимостей в. Внедрение зависимостей в .NET. Руководство по применению этого механизма. Net приложениях. Книга демонстрирует основные паттерны на обычном языке C#, поэтому вы в полной мере поймете, как работает механизм внедрения зависимостей


    Скачать 5.66 Mb.
    НазваниеРуководство по применению этого механизма. Net приложениях. Книга демонстрирует основные паттерны на обычном языке C#, поэтому вы в полной мере поймете, как работает механизм внедрения зависимостей
    АнкорВнедрение зависимостей в .net
    Дата14.12.2019
    Размер5.66 Mb.
    Формат файлаpdf
    Имя файлаВнедрение зависимостей в .NET.pdf
    ТипРуководство
    #100226
    страница29 из 43
    1   ...   25   26   27   28   29   30   31   32   ...   43
    Откуда мне его получить?
    Перейти на сайт http://structuremap.github.com /struct urem ap/index.html и нажать на ссылку
    Download the Latest Release
    Из Visual Studio 2010 можно получить его посредством NuGet. Имя пакета – structurem ap.

    Что находится в загруженном файле?
    Можно загрузить zip-файл, содержащий предварительно скомпилированные бинарные файлы. Кроме того, можно получить текущий исходный код и скомпилить его самостоятельно.
    Бинарные файлы – это dll-файлы, которые можно размещать там, где захочется, и ссылаться на них из собственного кода.

    Какие платформы поддерживаются?
    .NET 3.5 SP1, .NET 4

    Сколько он стоит?
    Нисколько. Это программное обеспечение с открытым исходным кодом.

    Откуда мне получить помощь?
    Гарантированная поддержка отсутствует, но получить помощь можно на официальном форуме http://groups.google.com/group/structurem ap user s
    На какой версии

    StructureMap основана данная глава?
    2.6.1
    Как и в случае с Castle Windsor, при использовании StructureMap соблюдается простой ритм, проиллюстрированный на рисунке 11-2.

    412
    Рисунок 11-2: Полноценный паттерн применения StructureMap довольно прост: сначала мы конфигурируем контейнер, а затем разрешаем компоненты из этого контейнера. В большинстве случаев мы создаем экземпляр класса
    Container и полностью конфигурируем его перед тем, как начать разрешать компоненты из него. Мы разрешаем компоненты того же экземпляра, который и конфигурировали.

    Контейнер или O bjectFactory?
    В более ранних версиях StructureMap статический класс
    ObjectFactory использовался в качестве одиночного контейнера приложений. Он использовался следующим образом:
    SauceBéarnaise sauce = ObjectFactory.GetInstance();
    Среди нескольких проблем, возникающих при использовании статической фабрики, можно выделить тот факт, что статическая фабрика способствует неправильному ее использованию в качестве Service Locator. На сегодняшний момент использование класса
    ObjectFactory не приветствуется, при этом предпочтение отдается экземплярам контейнеров. На сайте StructureMap (и не только на нем) представлено множество примеров, в которых образцы кода
    ObjectFactory используются для демонстрации различных возможностей StructureMap. Но мы должны рассматривать их как рудименты более ранних лет.
    В остальных частях данной главы мы будем игнорировать тот факт, что
    ObjectFactory существует и концентрируется исключительно на экземплярах контейнера.
    Предупрежде ние
    API StructureMap за последнее время значительно изменилось. Очень часто мы находим в интернете пример кода, в котором используется метод или класс, недоступный в текущей версии. Скорее всего, он был переименован или, в противном случае, был выполнен его рефакторинг. Несмотря на то, что при написании данной главы все примеры кода компилировались и работали, возможно, некоторые составляющие API изменились за период, начиная с момента написания главы и до момента ее прочтения вами.
    После прочтения этого раздела вы приобретете полноценное понимание всей сущности паттерна применения StructureMap и сможете начать использовать его в сценариях, в которых все компоненты руководствуются должным DI-паттерном, например, Constructor
    Injection. Давайте начнем с простейшего сценария и посмотрим, как можно разрешать объекты с помощью контейнера StructureMap.

    413
    Разрешение объектов
    Ключевая обязанность любого DI-контейнера – разрешение компонентов. В данном разделе мы рассмотрим API, позволяющее нам разрешать компоненты с помощью
    StructureMap.
    Если вы помните, как мы обсуждали процесс разрешения компонентов с помощью Castle
    W indsor, то, возможно, вспомните, что Windsor требует, чтобы вы регистрировали все соответствующие компоненты перед тем, как сможете их разрешить. StructureMap этого не требует. Если вы запрашиваете конкретный тип с конструктором по умолчанию, то никакой конфигурации не нужно. Самый простой вариант использования StructureMap представлен ниже: var container = new Container();
    SauceBéarnaise sauce = container.GetInstance();
    Если у вас есть экземпляр
    StructureMap.Container
    , то для получения экземпляра конкретного класса
    SauceBéarnaise
    , вы можете использовать generic-метод
    GetInstance
    Поскольку у этого класса есть конструктор по умолчанию, StructureMap автоматически поймет, как создать его экземпляр. При этом никакой явной конфигурации контейнера не требуется.
    П римечание
    Метод
    GetInstance
    аналогичен методу
    Resolve
    контейнера Windsor.
    Поскольку StructureMap поддерживает возможность автоматической интеграции, то даже при отсутствии конструктора по умолчанию он сможет создавать экземпляры без предварительной конфигурации. Делать он это сможет, пока все рассматриваемые параметры конструктора относятся к конкретным типам, а полноценное дерево параметров имеет такие типы листьев, которые обладают конструкторами по умолчанию.
    В качестве примера рассмотрите приведенный ниже конструктор
    Mayonnaise
    : public Mayonnaise(EggYolk eggYolk, OliveOil oil)
    Между тем, как рецепт майонеза достаточно прост, и
    EggYolk
    , и
    OliveOil являются конкретными классами, обладающими конструкторами по умолчанию. Несмотря на то, что сам
    Mayonnaise не имеет конструктора по умолчанию, StructureMap все равно может создать его, не выполняя при этом никакой конфигурации: var container = new Container(); var mayo = container.GetInstance();
    Это происходит, потому что StructureMap может определять, каким образом создавать все необходимые параметры конструктора. Тем не менее, как только мы введем слабое связывание, нам нужно будет сконфигурировать StructureMap таким образом, чтобы абстракции преобразовывались в конкретные типы.

    414
    П реобразование абстракций в конкретны е типы
    Несмотря на то, что способность StructureMap автоматически интегрировать конкретные типы, наверняка, время от времени может искусно появляться, при слабом связывании обычно необходимо преобразовывать абстракции в конкретные типы. Создание экземпляров на основании таких преобразований – ключевая услуга, предлагаемая любым
    DI-контейнером, но вам все равно нужно задать соответствие.
    В данном примере вы преобразуете интерфейс
    IIngredient в конкретный класс
    SauceBéarnaise
    , который позволяет успешно разрешать
    IIngredient
    : var container = new Container(); container.Configure(r => r
    .For()
    .Use());
    IIngredient ingredient = container.GetInstance();
    Метод
    Configure предоставляет возможность сконфигурировать
    ConfigurationExpression с помощью блока кода (объяснение смотри в приведенном ниже блоке "Nested Closures" (вложенные замыкания)). Оператор конфигурации читается почти как предложение (или как инструкция из кулинарной книги): для
    IIngredient
    используйт е
    SauceBéarnaise
    . Метод
    For позволяет определить абстракцию, а метод
    Use позволяет определить конкретный тип, реализующий абстракцию.
    Строго типизированное API, предоставляемо е классом
    ConfigurationExpression
    , помогает предотвратить ошибки конфигурации, поскольку метод
    Use имеет generic- ограничение, настаивающее на том, чтобы тип, указанный в аргументе типа, наследовался от аргумента типа абстракции, указанного в методе
    For
    . Предыду щий пример кода компилируется, поскольку
    SauceBéarnaise реализует
    IIngredient
    В большинстве случаев строго типизированное API – это все, что нам нужно, так как оно предоставляет желаемую проверку во время компиляции, Мы должны использовать его там, где это возможно. Однако существуют ситуации, когда нам нужен более слабо типизированный способ разрешения сервисов. Это тоже возможно.
    Разрешение слабо типизированных сервисов
    Иногда мы не можем использовать generic API, так как во время проектирования мы не знаем, какой тип нам понадобится. Все, что у нас есть – это экземпляр
    Type
    , но нам все равно хотелось бы получить экземпляр этого типа. Пример этого вы видели в разделе 7-2
    "Построение ASP.NET MVC приложений", где мы обсуждали ASP.NET MVC класс
    DefaultControllerFactory
    . Соответствующий метод представлен ниже: protected internal virtual IController GetControllerInstance(
    RequestContext requestContext, Type controllerType);
    Поскольку у вас есть только экземпляр
    Type
    , вы не можете воспользоваться generic'ами и вместо них должны обратиться к слабо типизированным API. К счастью, StructureMap предлагает слабо типизированную перегрузку метода
    GetInstance
    , которая позволяет реализовать метод
    GetControllerInstance приведенным ниже способом: return (IController)this.container.GetInstance(controllerType);

    415
    Слабо типизированная перегрузка
    GetInstance позволяет передавать аргумент controllerType прямо в StructureMap, но также требует, чтобы вы явным образом привели возвращаемое значение к
    IController
    Не важно, какую перегрузку
    GetInstance вы используете, StructureMap гарантирует, что эта перегрузка вернет экземпляр требуемого типа или выдаст исключение, если есть зависимости, которые не могут соответствовать заданным требованиям. После того, как все необходимые зависимости сконфигурированы должным образом, StructureMap может автоматически интегрировать необходимый тип.
    В предыдущем примере this.container
    – это экземпляр
    StructureMap.IContainer
    . Для обеспечения возможности разрешать необходимый тип все слабо связанные зависимости должны быть заранее сконфигурированы. Существует множество способов конфигурации
    StructureMap. В следующем разделе приводится обзор самых универсальных способов.
    Конфигурирование контейнера
    Как обсуждалось в разделе 3-2 "Конфигурирование DI-контейнеров", существует несколько концептуально разных способов конфигурирования DI-контейнера. На рисунке
    11-3 представлен обзор возможных вариантов.
    Рисунок 11-3: Концептуально разные варианты конфигурирования. Использование кода в качестве конфигурации подразумевает строгую типизированность и имеет тенденцию к явному определению. XML, с другой стороны, предполагает позднее связывание, но тоже склонно к явному определению. Автоматическая регистрация, напротив, полагается на соглашения, которые могут быть и строго типизированными, и более слабо определенными.
    Как и другие, имеющие длительную историю DI-контейнеры, StructureMap сначала использовал XML в качестве основного источника конфигурации. Тем не менее, многие команды разработчиков вскоре узнали, что определение регистраций типа в XML чрезвычайно хрупко, поэтому на сегодняшний день мы предпочитаем строго типизированную конфигурацию. Строго типизированну ю конфигурацию можно

    416 выполнить, используя код в качестве конфигурации, но чаще всего наиболее эффективной является основанная на соглашениях автоматическая регистрация.
    StructureMap поддерживает все три подхода и даже позволяет нам сочетать их в пределах одного и того же контейнера. В этом отношении StructureMap предоставляет нам все, что мы только можем попросить. В данном разделе вы увидите, как можно использовать каждый из этих трех видов источников конфигурации.
    Конфигурация в коде
    В разделе 11.1.1 "Разрешение объектов" вы уже видели небольшой намек на строго типизированное API для конфигурации StructureMap. В данном разделе мы рассмотрим его подробнее.
    Существует несколько точек входа в конфигурационное API. Вы уже видели, что оно вызывается посредством явного использования метода
    Configure
    : var container = new Container(); container.Configure(r => r
    .For()
    .Use());
    Еще один вариант – определение точно такого же блока кода прямо при создании экземпляра
    Container
    : var container = new Container(r => r
    .For()
    .Use());
    Результат тот же, однако, в данной главе я руководствуюсь соответствующим соглашением и предпочитаю использовать метод
    Configure
    , а не конструктор.
    Вложенные замыкания
    StructureMap широко использует паттерн Вложенное замыкание (Nested Closure), в котором конфигурация определяется блоками кода (известными как лямбда-выражения).
    В качестве примера ниже приведена сигнатура метода
    Configure
    : public void Configure(Action configure);
    Параметр configure
    – делегат, который принимает
    ConfigurationExpression в качестве входного параметра. В примерах кода, приведенных в этой главе, этот параметр обычно обозначается как r
    , и обычно я передаю делегат в виде блока кода, выраженного посредством параметра r
    При просмотре примеров кода, встречающихся на сайте StructureMap или в блоге
    Джереми Миллера, можно обнаружить, что иногда имя параметра, используемого в блоке кода, задается как x
    , а иногда – как registry
    . Поскольку подходящие преценденты отсутствуют, я решил использовать r
    (соответствующее registry
    ) в качестве условного обозначения, которое будет применяться в данной главе. Несмотря на то, что r
    не является достаточно понятным именем для переменной, рассматриваемые здесь небольшие по объему блоки кода делают r
    более подходящим для этих целей именем, нежели более длинное и менее краткое имя.

    417
    Класс
    ConfigurationExpression содержит множество методов, которые можно использовать для конфигурирования StructureMap. Один из этих методов,
    For
    , мы уже видели ранее. Как вы увидите в данном разделе позднее, еще одним таким методом является метод
    Scan с приведенной ниже сигнатурой: public void Scan(Action action);
    Обратите внимание на то, что сам метод
    Scan принимает делегат в качестве входного параметра. Когда вы передаете блок кода метода
    Scan
    , то получается, что у вас имеется один блок кода внутри другого блока кода – отсюда и название Nested Closure (вложенное замыкание).
    В отличие от Castle Windsor преобразование
    IIngredient в
    SauceBéarnaise продемонстрированным ранее способом не исключает разрешения самого
    SauceBéarnaise
    . Т о есть, и sauce
    , и ingredient будут разрешены должным образом: container.Configure(r => r.For().Use()); var sauce = container.GetInstance(); var ingredient = container.GetInstance();
    Если вы вспомните обсуждение, проводимое в разделе 10.1.2 "Конфигурирование контейнера", то вспомните и то, что преобразование
    IIngredient в
    SauceBéarnaise с помощью Castle Windsor приводит к тому, что "исчезает" конкретный класс
    (
    SauceBéarnaise
    ), и вам приходится использовать перенаправление типов (Type
    Forwarding), чтобы суметь разрешить и
    IIngredient
    , и
    SauceBéarnaise
    . При использовании StructureMap такие дополнительные шаги выполнять не нужно, поскольку
    StructureMap умеет преобразовывать и
    IIngredient
    , и
    SauceBéarnaise
    . В обоих случаях возвращаемые объекты являются экземплярами
    SauceBéarnaise
    В реальных приложениях нам всегда нужно преобразовывать более одной абстракции, поэтому нам необходимо сконфигурировать составные преобразования. Сделать это можно при помощи единичного вызова метода
    Configure или посредством составных последовательных вызовов. Приведенные ниже примеры аналогичны: container.Configure(r =>
    { r.For()
    .Use(); r.For()
    .Use();
    }); и container.Configure(r => r
    .For()
    .Use()); container.Configure(r => r
    .For()
    .Use());
    Несмотря на то, что во втором примере для конфигурации используются два последовательных вызова, в первом примере блок кода с большим количеством операторов передается в единичный вызов метода
    Configure
    . Оба примера кода

    418 завершаются регистрацией корректных преобразований как для интерфейса
    ICourse
    , так и для интерфейса
    IIngredient
    . Тем не менее, конфигурирование одной и той же абстракции несколько раз приводит к интересным результатам: container.Configure(r => r.For().Use()); container.Configure(r => r.For().Use());
    В этом примере вы регистрируете
    IIngredient дважды. Если вы разрешаете
    IIngredient
    , то получаете экземпляр
    Steak
    . Выигрывает последняя конфигурация, но предыдущие конфигурации не забыты. StructureMap отлично управляет составными конфигурациями одной и той же абстракции, но к этой теме мы вернемся в разделе 11.3.1 "Выбор из составных кандидатов".
    Возможны более продвинутые варианты конфигурирования StructureMap, но можно сконфигурировать все приложение при помощи продемонстрированных ниже методов.
    Для того чтобы избежать излишнего явного сопровождения конфигурации контейнера, мы могли бы рассмотреть подход, в большей мере основанный на соглашениях, – автоматическую регистрацию.
    Автоматическая регистрация
    В большинстве случаев регистрации будут аналогичными. Т акие регистрации трудно сопровождать, а явная регистрация каждого компонента, возможно, не самый продуктивный подход.
    Рассмотрим библиотеку, которая состоит из множества реализаций
    IIngredient
    . Мы можем сконфигурировать каждый класс индивидуальным образом, но это приведет к многочисленным, схожим по внешнему виду вызовам метода
    Configure
    . Что еще хуже, всякий раз при добавлении новой реализации
    IIngredient
    , мы должны также явным образом конфигурировать эту реализацию в контейнере, если хотим, чтобы она была доступной. Было бы более продуктивно установить, что все реализации
    IIngredient
    , находящиеся в данной сборке, необходимо зарегистрировать.
    Это возможно благодаря методу
    Scan
    , который является еще одним примером обширного применения StructureMap делегатов. Метод
    Scan доступен в классе
    ConfigurationExpression
    , который уже доступен через блок кода. Именно здесь мы и видим паттерн Nested Closure в действии. Приведенный ниже пример кода конфигурирует все реализации
    IIngredient одним махом: container.Configure(r => r.Scan(s =>
    { s.AssemblyContainingType(); s.AddAllTypesOf();
    }));
    Метод
    Scan расположен в пределах блока кода
    Configure
    . Переменная s
    представляет собой экземпляр
    IAssemblyScanner
    , который можно использовать для определения того, каким образом необходимо просматривать сборку и как должны конфигурироваться типы.

    419
    Экземпляр
    IAssemblyScanner предоставляет несколько методов, которые можно использовать для того, чтобы определить, какие сборки необходимо просматривать и как конфигурировать типы из этой сборки. Мы можем использовать generic-метод
    AssemblyContainingType для идентификации сборки по типу представителя, но существует несколько других методов, позволяющих нам предоставить экземпляр
    Assembly или даже добавить все сборки, находящиеся по данному пути.
    Другой набор методов дает нам возможность определить, какие типы добавлять и как их преобразовывать. Метод
    AddAllTypesOf обеспечивает самый быстрый способ добавления всех типов, реализующих данный интерфейс, но существует и несколько других методов, которые позволяют нам тщательно контролировать то, как конфигурируются типы.
    Предыду щий пример, безусловно, конфигурирует все реализации интерфейса
    IIngredient
    , но мы можем предоставить фильтры, которые позволят нам выбирать только подмножества. Ниже приведен пример сканирования на основании соглашений, при котором вы добавляете только те классы, имена которых начинаются с
    Sauce
    : container.Configure(r => r.Scan(s =>
    { s.AssemblyContainingType(); s.AddAllTypesOf(); s.Include(t => t.Name.StartsWith("Sauce"));
    }));
    Единственное отличие от предыдущего примера заключается в добавлении вызова метода
    Include
    , который вводит третий уровень Nested Closure. Метод
    Include принимает в качестве параметра предикат, который используется для определения того, нужно ли включать данный
    Type или нет. В этом примере ответ – true
    , поскольку
    Name для
    Type начинается с
    Sauce
    Если мы хотим полностью контролировать процесс конфигурирования на основании соглашений, мы можем определить пользовательское соглашение путем реализации интерфейса
    IRegistrationConvention
    . В следующем листинге демонстрируется соглашение
    Sauce
    , реализованное в виде пользовательского соглашения.
    Листинг 11-1: Реализация пользовательского соглашения public class SauceConvention : IRegistrationConvention
    { public void Process(Type type, Registry registry)
    { var interfaceType = typeof(IIngredient); if (!interfaceType.IsAssignableFrom(type))
    { return;
    } if (!type.Name.StartsWith("Sauce"))
    { return;
    } registry.For(interfaceType).Use(type);
    }
    }

    420
    Класс
    SauceConvention реализует
    IRegistrationConvention
    , который определяет единичный член. Метод
    Process будет вызываться StructureMap для каждого типа сборки, определенного в методе
    Scan
    , поэтому вы должны явным образом предоставить набор граничных операторов, которые отфильтровывают все не нужные вам типы.
    Граничные операторы гарантируют, что любой тип, проходящий через них, – это
    IIngredient
    , чье имя начинается с
    Sauce
    , поэтому теперь вы можете зарегистрировать этот тип с помощью registry
    . Обратите внимание на то, что
    Registry
    , между прочим, предоставляется посредством Method Injection, который имеет огромный смысл, поскольку
    IRegistrationConvention определяет встраиваемый элемент для StructureMap.
    Можно использовать класс
    SauceConvention в методе
    Scan следующим образом: container.Configure(r => r.Scan(s =>
    { s.AssemblyContainingType(); s.Convention();
    }));
    Обратите внимание на то, что вы все равно определяете сборку за рамками соглашения.
    Это позволяет вам менять источники типов, которые обрабатываются независимо от самого соглашения.
    SauceConvention определяется с помощью метода
    Convention
    Данный метод требует, чтобы
    IRegistrationConvention
    , указанный в качестве аргумента типа, имел конструктор по умолчанию. Но существует также метод
    With
    , принимающий в качестве входного параметра экземпляр
    IRegistrationConvention
    , который можно создать вручную любым необходимым способом.
    Поскольку вы можете использовать метод
    Scan для того, чтобы просматривать все сборки в указанной папке, вы также можете применять его для реализации дополнительно й функциональности, в которой дополнения могут добавляться без повторной компиляции основного приложения. Это один из способов реализации позднего связывания. Еще один вариант – использовать конфигурационное API, основанное на XML.
    XML конфигурация
    XML конфигурация – отличный вариант в тех ситуациях, когда нам необходимо уметь изменять конфигурацию без повторной компиляции приложения.
    П одсказка
    Используйте XML конфигурацию только для тех типов, изменить которые вам нужно, не выполняя при этом повторной компиляции приложения. В остальных случаях применяйте автоматическую регистрацию или технологию использования кода в качестве конфигурации.
    Мы можем использовать специализированные XML-файлы для того, чтобы сконфигурировать StructureMap, или даже вставить конфигурацию в стандартный конфигурационный файл приложения. Т ем не менее, удивительно, но возможность вставки конфигурации в конфигурационный файл приложения напрямую не поддерживается в StructureMap, поэтому давайте сначала рассмотрим использование специализированных XML-файлов.

    421
    Конфигурацию можно определить в XML и прочитать при помощи метода
    AddConfigurationFromXmlFile
    : container.Configure(r => r.AddConfigurationFromXmlFile(configName));
    В данном примере configName
    – это строка, которая содержит имя соответствующего
    XML-файла. Если вы захотите использовать стандартный конфигурационный файл приложения, то вам нужно будет использовать AppDomain API для того, чтобы определить путь к текущему конфигурационному файлу: var configName =
    AppDomain.CurrentDomain.SetupInformation.ConfigurationFile;
    П римечание
    Несмотря на то, что статический класс
    ObjectFactory напрямую поддерживает чтение конфигурации из App.config, данная возможность не поддерживается для экземпляров контейнера. Использование AppDom ain API для получения имени файла – рекомендуемая технология работы.
    Помимо направления StructureMap к соответствующему файлу XML конфигурацию можно передать в виде
    XmlNode
    : container.Configure(r => r.AddConfigurationFromNode(xmlNode));
    Данный код позволяет вам получать XML конфигурацию не только из файлов, но и из таких произвольных мест, как базы данных или вложенные ресурсы.
    Не важно, каков источник XML, схема остается той же. Ниже приведена простая конфигурация, которая преобразует
    IIngredient в
    Steak
    :

    PluggedType="Ploeh.Samples.MenuModel.Steak,
    ➥ Ploeh.Samples.MenuModel" />

    Обратите внимание на то, что вы должны передавать квалифицированное имя типа сборки как для абстракции, так и для реализации – StructureMap называет их Плагинам и (Plugins) или Подключаемыми т ипами (Plugged types).
    Если вы хотите вставить данный код XML в конфигурационный файл приложения, то вы должны зарегистрировать элемент
    StructureMap в виде раздела конфигурации:




    422
    XML конфигурация – отличный вариант в тех ситуациях, когда вам необходимо изменить конфигурацию одного или более одного компонента, не выполняя при этом повторной компиляции приложения. Т ем не менее, поскольку этот вариант довольно хрупок, поберегите его для таких конкретных ситуаций, а для основной части конфигурации контейнера используйте либо автоматическую регистрацию, либо код в качестве конфигурации.
    Подсказка
    Помните, что выигрывает последняя конфигурация типа? Данное поведение вы можете использовать для того, чтобы перезаписать жестко-зако диро ванну ю конфигурацию XML конфигурацией. Для этого вы должны не забывать считывать XML конфигурацию после того, как будут сконфигурированы любые другие компоненты.
    В данном разделе мы, главным образом, рассматривали различные API для конфигурации
    StructureMap. Несмотря на то, что, наверняка, можно записать один большой блок неструктурированного кода конфигурации, лучше всего разделить конфигурацию на модули. StructureMap поддерживает эту возможность посредством регист ров (Registries).
    Пакетирование конфигурации
    Иногда существует необходимость упаковать логику конфигурации в повторно используемые группы. И даже в тех случаях, когда само по себе повторное использование не является для вас высшим приоритетом, вы можете захотеть предоставить некоторого рода структуру, когда вам нужно конфигурировать большое и сложное приложение.
    В рамках StructureMap мы можем упаковывать конфигурацию в регистры (Registries), которые представляют собой классы, унаследованные от конкретного класса
    Registry
    Рисунок 11-4 демонстрирует взаимосвязь между классом
    Registry и методом
    Configure
    , который использовался в разделе 11.1.2 "Конфигурирование контейнера".
    Рисунок 11-4: Метод
    Configure класса
    Container принимает в качестве входного параметра делегат, который действует для
    ConfigurationExpression
    – в данной главе мы обозначаем экземпляр этого
    ConfigurationExpression с помощью имени переменной r
    Класс
    ConfigurationExpression
    – дочерний класс конкретного класса
    Registry
    Каждый раз при использовании метода
    Configure в этой главе вы представляете экземпляр
    ConfigurationExpression с помощью имени переменной r
    . Большинство методов, вызываемых для r
    (например, методы
    For и
    Scan
    ), определены в классе
    Registry
    Для того чтобы реализовать
    Registry
    , мы реализуем класс, который наследуется от
    Registry
    . Приведенный ниже листинг демонстрирует пример, который конфигурирует используемый по умолчанию
    ICourse
    , а также добавляет типы
    IIngredient из сборки. В нем используется то же самое API, которое мы ранее использовали в разделе 11.1.2

    423
    "Конфигурирование контейнера", но в настоящее время это API упаковано в отдельный класс.
    Листинг 11-2: Реализация регистра public class MenuRegistry : Registry
    { public MenuRegistry()
    { this.For().Use(); this.Scan(s =>
    { s.AssemblyContainingType(); s.AddAllTypesOf();
    });
    }
    }

    1   ...   25   26   27   28   29   30   31   32   ...   43


    написать администратору сайта