StructureMap 3/3

Перехватчики

С версии 2.5+ появилась возможность постобработки только что созданного объекта, либо полной его замены. В данном случае не ставится целью создать еще одни AOP фреймворк, так как их уже достаточно в мире, просто это может облегчить жизнь.

Для постобработки существует два+ метода:

  • OnCreation – принимает в качестве параметра Action, позволяет провести свою (custom) инициализацию объекта. Есть доступ к контексту SturctureMap.
  • EnrichWith – принимает в качестве параметра Function. Может возвращать любой тип совместимый с запрашиваемым.
  • Свои перехватчики

Честно сказать, в простых примерах не очень хорошо получается передать разницу и преимущества использования OnCreation перед EnrichWith и наоборот.

OnCreation

Для демонстрации можно воспользоваться следующим простым классом:

Теперь, можно продемонстрировать использование метода OnCreation.

 

При получении класса из IoC фреймворка мы можем увидеть, что значение Counter равняется -100. Как видите, в применении все очень просто и опять же интуитивно понятно, что будет делать код. Неподготовленный человек сможет прочитать определение класса в StructureMap и сразу понять, что и как здесь происходит.

Так же возможен вариант, когда в метод инициализации надо передать объект сконструированный средствами самого StructureMap. Для этих целей используем тот же перегруженный метод.

 

В данном случае в лямбда-выражении есть доступ к самому контейнеру и можно получать объекты, конструирование которых возложено на StructureMap.

EnrichWith

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

 

Тогда можно будет его получать из StructureMap с помощью следующего кода:

 

В результате, при попытке получить экземпляр класса реализующего интерфейс IClassS мы будем получать класс ClassSs.

Шаблонные (generic) типы

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

Итак, допустим у нас есть шаблонный адаптер.

 

Так же существует несколько его наследников с конкретными типами

Никаких ограничений на типы Т в адаптере не предусмотрены.

Есть несколько способов для работы с шаблонными типами. Самый простой способ это зарегистрировать и вызывать конкретные типы StringAdapter, IntAdapter.

 

В примере показано два идентичных способа регистрации шаблонного класса.

Вызывать их можно несколькими способами.

Способ раз: Можно попросить контейнер выдать нам адаптер по конкретному типу.

 

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

Составление контейнера остается тем  же, изменяется способ получения.

 

Т.е. сообщаем контейнеру что будем требовать шаблонный тип, для такого-то типа, и вернуть экземпляр как тип IAdapter.

Для реального испльзование оно бы выглядело как:

 

Конкретный адаптер  будет определяться по типу передаваемого параметра T.

Аттрибуты

StructureMap может быть сконфигурирован до определенной степени с помощью атрибутов. Уже освещался атрибут DefaultCounstructor, который указывает на конструктор, который должен использоваться по умолчанию. Есть атрибуты для указания классов и интерфейсов для регистрации, какие свойства класса автоматически заполнять, а так же задавать методы для валидации.

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

Самый полезный атрибут уже указан, следующий по полезности ValidationMethod,  остальные использовать не рекомендуется, но если очень хочется, то вот краткое описание.

ValidationMethod

Используется для самопроверки классов. Т.е. вы написали какой-то класс и можно написать метод, который будет определять правильность создания класса. StructureMap может его подцеплять и выполнять для самопроверки. Кажется это вообще уникальная способность рассматриваемого фреймворка.

Пусть у нас есть класс, для которого надо задавать определенное свойство. Это может быть строка соединения с базой данных, настройки взаимодействия, сложные связи. В нашем примере ограничимся просто тем, что поле не должно быть пустым.

 

Видно, что метод помечен как ValidationMethod. Вообще таких методов может быть больше одного, StructureMap сканирует их всех и пытается выполнить поочередно при вызове методаAssertConfigurationIsValid. Будьте осторожны с этим методом, так как при большой конфигурации фреймворк попробует построить все зависимости, заполнить все поля, запустить все методы помеченные рассматриваемым атрибутом.

Регистрация класса пусть будет проведена следующим образом:

 

Теперь можно попробовать его получить из контейнера.

 

При вызове метода выше, вы получите StructureMapConfigurationException где будет показаны внутренние исключения вызванные проверками внутреннего устройства StructureMap.

 

На скриншоте видно, что в сообщении об исключительной ситуации как раз фигурирует наше сообщение.

PluginFamily

Указывает StructureMap, что помеченный тип будет использоваться как тип плагинов. Эквивалентно тому, как если бы мы написали .For<plugin type>.

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


Pluggable

Помеченный тип будет включен в коллекцию плагинов, указывает на конкретную реализацию. Эквивалентно использованию .Use<pluggable type>. Необходимо всегда использовать имя для типа.

SetterProperty

Указывает на то, что помеченное атрибутом свойство нужно инициализировать средствами фреймворка. Они будут являться обязательными и если StructureMap не сможет их инициализировать, то будет ошибка исполнения.

Тесты

Помимо того, что StructureMap может сам себя проверить на корректность определения всех классов, параметров и других составляющих, он еще позволяет точечно работать с проверкой зарегистрированных классов. В фреймворк встроены средства для тестирования, чтобы не пришлось изобретать велосипеды, а красиво и лаконично писать тесты.

В StructureMap встроены RhinoMock и Moq фреймворки. Для того, чтобы ими воспользоваться необходимо будет доставить пакет NuGet  structuremap.automocking, после чего можно будет использовать мокирование объектов.

Рассмотрение работы Moq и RhinoMock не входит в рамки статьи.

 

Заключение

Надеюсь, что у вас появилось желание поподробнее и на практике изучить StructureMap. Еще очень советую посмотреть на исходники проекта, можно подчерпнуть интересные и полезные идеи.

За бортом статьи остались темы по созданию контейнера на основе файла конфигурации. Работа с вложенными контейнерами и зачем они нужны. Я надеюсь, что в недалеком будущем этот пробел будет восполнен.

 

2 комментарий на “StructureMap 3/3

  1. Наверное, при описании generic-типов Вы забыли самый простой метод — IAssemblyScanner.ConnectToTypesClosing(typeof(Adapter));

    • эм… не видел такой, если честно, и даже не знал. В тех доках, по которым изучал, не было описания данной фичи, и как-то я сам не наткнулся. Но спасибо что сказали, покопаю в эту сторону.

Оставить комментарий