view Implab.ServiceHost/docs/XmlConfiguration.md @ 281:e0916ddc9950 v3 tip

code cleanup and refactoring
author cin
date Fri, 01 Jun 2018 21:35:24 +0300
parents 963b17c275be
children
line wrap: on
line source

# XML Конфигурация IoC контейнера

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

На данный момент поддерживается единственный вид контейнера - [Unity Container](https://unitycontainer.github.io/)

Unity уже обладает средствами загрузки конфигурации из XML, данная библиотека реализует аналогичный функционал, кроме того, позволяет решать следующие задачи:

- Конфигурация является простым Xml документом, который можно получить из любого источика и не ограничивается `.config` файлами приложения
- Включение существующе конфигурации `<include href='config.xml'/>` в текущую
- Поддержка сериализованных объектов в качестве регистраций сервисов и параметров
- Поддержка специфиакции генериков любой вложенности, например `Dictionary{Foo,Bar{Int32}}`
- Поддержка фабрик в XML конфигурации
- Расширение схемы XML конфигурации собственными элементами

## Общая архитектура

Пространство имен `Implab.ServiceHost.Unity` содержит в себе классы для загрузки и применения XML конфигурации к IoC контейнеру.

Применение конфигурации к контейнеру состоит из следующих основных шагов:

1. Настраивается схема `ContainerConfigurationSchema` XML конфигурации контейнера
2. Загружается документ и десереализуется в виде `ContainerElement`
3. Создается `ContainerBuilder` при помощи которого применяются настройки из `ContainerElement` к контейнеру

Схема `ContainerConfigurationSchema` определяет элементы документа, которые могут быть использованы в конфигурации контейнера, позволяет создать `XmlSerializer`, который используется для загрузки конфигурации.

`ContainerBuilder` - основной класс, который используется для применения конфигурации к контейнеру, он добавляет записи регистрации сервисов из конфигурации в контейнер.

`ContainerElement` - Конфигурация контейнера, которая загружается из документа, состоит из директив для `ContainerBuilder`, а также из записей регистрации сервисов.

В библиотеки приняты следующие правила именования классов:

- `***Builder` используются для применения конфигурации к контейнеру,
- `***Element` содержат информацию о конфигурации и десериализуются из исходного документа.

## Структура конфигурации контейнера

Элемент верхнего уровня всегда `container`, он используется для хранения набора элеметов, которые распознаются и выполняются `ContainerBuilder`.

Все элементы, входящие в контейнер наследуются от абстрактного класса `ContainerItemElement`,
который позволяет получить текущий `ContainerBuilder` и выполнить над ним какие-либо действия.

Основные элементы конфигурации контенейра

- `<include href='config.xml'/>` - включение конфигурации из указанного места
- `<namespace name='My.App'/>` - добавление пространства имен для поиска типов
- `<register type='MyGenericType{}'/>` - добавление в контейнер регистрации типа ``My.App.MyGenericType`1``
- `<factory type='IFactory{Foo}' mapTo ='MyFactory'/>` - фабрика, регистрирует свой тип, а также тип `Foo`
- `<serialized />` - сериализованный экземпляр объекта, использует `XmlSerializer` для десериализации
- `<value />` - значение объекта в виде строки, используется для простых типов

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

### register

О


Например, мы используем компоненту `MyHttpClient` для загрузки данных

```xml
    <register type="IClient" mapTo="MyHttpClient">
        <property name="proxy">
            <value>socks5://proxy1.my.company</value>
        </property>
    </register>
```

При частом использовании можно сделать описание конфигурации несколько проще,
описав новый эелемент конфигурации

```csharp
public class MyHttpClientElement : ContainerItemElement {

    public string Proxy { get; set; }

    public override void Visit(ContainerBuilder builder) {
        // создаем описание элемента
        var registration = new RegistrationElement {
            RegistrationType = "IClient",
            ImplementationType = "My.App.MyHttpClient",
            Injectors = new [] {
                new PropertyInjectionElement {
                    Name = "Proxy",
                    Value = ValueParameterElement {
                        Value = Proxy
                    }
                }
            }
        };

        // применяем созданное описание к контейнеру
        builder.Visit(registration)
    }
}
```

Регистрируем новый элемент в схеме

```csharp
schema.RegisterContainerElement<MyHttpClientElement>("http");
```

Используем новый элемент в конфигурации

```xml
    <http>
        <proxy>socks5://proxy1.my.company</propxy>
    </http>
```