view Implab.ServiceHost/Unity/FactoryElement.cs @ 278:6691aff01de1 v3

Implab: added XmlDefaultSeializer (SerializersPool is now obsolete) Implab.ServiceHost: rewritten TypeReference (added support for nested types), stable API
author cin
date Thu, 03 May 2018 09:59:44 +0300
parents
children 8714471e8d78
line wrap: on
line source

using System;
using System.Xml.Serialization;
using Implab.Components;

namespace Implab.ServiceHost.Unity {
    /// <summary>
    /// Расширяет стандартную регистрацию типа до фабрики, вместе с регистрацией
    /// самой фабрики создаются регистрации сервисов, которые она предоставляет.
    /// </summary>
    public class FactoryElement : RegisterElement {

        /// <summary>
        /// Записи о сервисах, которые создаются данной фабрикой.
        /// </summary>
        /// <remarks>
        /// Сервисы, которые указаны в регистарциях они должны соответсвовать тому,
        /// что фабрика возвращает, но это остается на откуп контейнера
        /// </remarks>
        [XmlElement("provides")]
        public ProvidesElement[] Provides { get; set; }

        /// <summary>
        /// Переопределяет стандарное поведение регистрации типа в контейнере,
        /// дополняя его регистрацией фабричных методов для получения типов.
        /// </summary>
        /// <param name="builder">Объект для конфигурирования контейнера.</param>
        public override void Visit(ContainerBuilder builder) {
            var factoryType = GetRegistrationType(builder.ResolveType);

            base.Visit(builder);

            if (Provides != null && Provides.Length > 0) {
                // если регистрации явно заданы, используеися информация из них
                foreach(var item in Provides) {
                    var activator = new FactoryActivator {
                        Name = item.RegistrationName,
                        RegistrationType = builder.ResolveType(item.RegistrationType),
                        FactoryName = Name,
                        FactoryType = factoryType
                    };
                    activator.Visit(builder);
                }
            } else {
                // если регистрация явно не задана, в качестве сервиса для регистрации
                // используется тип создаваемый фабрикой, который будет добавлен в контейнер
                // с темже именем, что и сама фабрика (разные типы могут иметь одно имя для регистрации)
                var providedType = (
                        factoryType.IsGenericType && factoryType.GetGenericTypeDefinition() == typeof(IFactory<>) ?
                        factoryType :
                        factoryType.GetInterface(typeof(IFactory<>).FullName)
                    )?
                    .GetGenericArguments()[0];

                // не удалось определеить тип
                if (providedType == null)
                    throw new ArgumentException("Failed to determine a type provided by the factory");

                if (providedType.IsGenericParameter)
                    throw new ArgumentException("Can't register a generic type paramter as a service");

                var activator = new FactoryActivator {
                    Name = Name,
                    RegistrationType = providedType,
                    FactoryName = Name,
                    FactoryType = factoryType
                };

                activator.Visit(builder);
            }
        }
    }
}