diff 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 diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Implab.ServiceHost/Unity/FactoryElement.cs	Thu May 03 09:59:44 2018 +0300
@@ -0,0 +1,72 @@
+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);
+            }
+        }
+    }
+}
\ No newline at end of file