changeset 279:8714471e8d78 v3

Container configuration cleanup, RC2
author cin
date Fri, 04 May 2018 18:12:42 +0300
parents 6691aff01de1
children f07be402ab02
files Implab.Playground/Program.cs Implab.ServiceHost/Unity/AbstractMemberInjection.cs Implab.ServiceHost/Unity/AbstractRegistration.cs Implab.ServiceHost/Unity/ConstructorInjectionElement.cs Implab.ServiceHost/Unity/ContainerBuilder.cs Implab.ServiceHost/Unity/ContainerLifetimeElement.cs Implab.ServiceHost/Unity/ContextLifetimeElement.cs Implab.ServiceHost/Unity/DependencyParameterElement.cs Implab.ServiceHost/Unity/FactoryAbstractRegistration.cs Implab.ServiceHost/Unity/FactoryActivator.cs Implab.ServiceHost/Unity/FactoryElement.cs Implab.ServiceHost/Unity/FactoryRegistrationBuilder.cs Implab.ServiceHost/Unity/HierarchicalLifetimeElement.cs Implab.ServiceHost/Unity/IFactoryMemberInjection.cs Implab.ServiceHost/Unity/IFactoryRegistration.cs Implab.ServiceHost/Unity/InjectionParameterElement.cs Implab.ServiceHost/Unity/InjectionValueBuilder.cs Implab.ServiceHost/Unity/InstanceAbstractRegistration.cs Implab.ServiceHost/Unity/LifetimeElement.cs Implab.ServiceHost/Unity/MethodInjectionElement.cs Implab.ServiceHost/Unity/PropertyInjectionElement.cs Implab.ServiceHost/Unity/RegisterElement.cs Implab.ServiceHost/Unity/SerializedElement.cs Implab.ServiceHost/Unity/SingletonLifetimeElement.cs Implab.ServiceHost/Unity/TypeAbstractRegistration.cs Implab.ServiceHost/Unity/TypeRegistrationBuilder.cs Implab.ServiceHost/Unity/TypeResolver.cs Implab.ServiceHost/Unity/UnityContainerExtensions.cs Implab.ServiceHost/Unity/ValueElement.cs
diffstat 29 files changed, 252 insertions(+), 270 deletions(-) [+]
line wrap: on
line diff
--- a/Implab.Playground/Program.cs	Thu May 03 09:59:44 2018 +0300
+++ b/Implab.Playground/Program.cs	Fri May 04 18:12:42 2018 +0300
@@ -94,22 +94,27 @@
             source.Switch.Level = SourceLevels.All;
             source.Listeners.Add(listener);
 
-            var resolver = new TypeResolver();
-            resolver.AddNamespace("System");
-            resolver.AddNamespace("System.Collections.Generic");
-            resolver.AddNamespace("Implab.Playground");
-            resolver.AddMapping("string", typeof(string));
-            resolver.AddMapping("listOf`1", typeof(List<>));
+            var stopwatch = new Stopwatch();
+            stopwatch.Start();
+
+            var container = new UnityContainer();
+
+            Console.WriteLine($"Created: {stopwatch.ElapsedMilliseconds}");
+            stopwatch.Restart();
+            
+            container.LoadXmlConfiguration("data/sample.xml");
 
-            var spec = TypeReference.Parse("Container{listOf{string}}+Bar{List{string}}");
+            Console.WriteLine($"Loaded: {stopwatch.ElapsedMilliseconds}");
 
-            var t = resolver.Resolve(spec, true);
+            stopwatch.Restart();
+            var instace1 = container.Resolve<IContainer<string>>();
+            Console.WriteLine($"Resolved1: {stopwatch.ElapsedMilliseconds}");
 
-            Console.WriteLine("{0}", t);
-            Console.WriteLine("Spec: {0}", spec);
-            Console.WriteLine("IsGenericType: {0}", t.IsGenericType);
-            Console.WriteLine("IsGenericTypeDefinition: {0}", t.IsGenericTypeDefinition);
-            Console.WriteLine("ContainsGenericParameters: {0}", t.ContainsGenericParameters);
+            stopwatch.Restart();
+            var instace2 = container.Resolve<IContainer<Foo>>();
+            Console.WriteLine($"Resolved2: {stopwatch.ElapsedMilliseconds}");
+
+            DisplayContainerRegistrations(container);
         }
 
         static void DisplayContainerRegistrations(IUnityContainer theContainer) {
--- a/Implab.ServiceHost/Unity/AbstractMemberInjection.cs	Thu May 03 09:59:44 2018 +0300
+++ b/Implab.ServiceHost/Unity/AbstractMemberInjection.cs	Fri May 04 18:12:42 2018 +0300
@@ -4,7 +4,7 @@
     /// <summary>
     /// Base class for injections, each injection is applied to the type registration context.
     /// </summary>
-    public abstract class AbstractMemberInjection {
-        internal abstract void Visit(TypeRegistrationBuilder context);
+    public abstract class AbstractMemberInjection : ITypeMemberInjection {
+        public abstract void Visit(TypeRegistrationBuilder builder);
     }
 }
\ No newline at end of file
--- a/Implab.ServiceHost/Unity/AbstractRegistration.cs	Thu May 03 09:59:44 2018 +0300
+++ b/Implab.ServiceHost/Unity/AbstractRegistration.cs	Fri May 04 18:12:42 2018 +0300
@@ -8,7 +8,7 @@
     /// <summary>
     /// Базовая информаци о регистрации в контейнере: тип, имя и время жизни
     /// </summary>
-    public abstract class AbstractRegistration : AbstractContainerItem {
+    public abstract class AbstractRegistration : AbstractContainerItem, IRegistration {
 
         /// <summary>
         /// An optional name for a registration in the container
@@ -30,13 +30,19 @@
         [XmlAttribute("type")]
         public string RegistrationType { get; set; }
 
+        public virtual LifetimeManager GetLifetime(ContainerBuilder builder) {
+            return Lifetime?.GetLifetime(builder);
+        }
+
         public virtual Type GetRegistrationType(Func<string,Type> resolver) {
             return resolver(RegistrationType);
         }
 
-        public virtual void Visit(RegistrationBuilder builder) {
-            Lifetime?.Visit(builder);
+        public virtual Type GetRegistrationType(ContainerBuilder builder) {
+            return builder.ResolveType(RegistrationType);
         }
 
+        
+
     }
 }
\ No newline at end of file
--- a/Implab.ServiceHost/Unity/ConstructorInjectionElement.cs	Thu May 03 09:59:44 2018 +0300
+++ b/Implab.ServiceHost/Unity/ConstructorInjectionElement.cs	Fri May 04 18:12:42 2018 +0300
@@ -10,8 +10,8 @@
         [XmlElement("array", typeof(ArrayParameterElement))]
         public InjectionParameterElement[] Parameters { get; set; }
 
-        internal override void Visit(TypeRegistrationBuilder context) {
-            context.Visit(this);
+        public override void Visit(TypeRegistrationBuilder builder) {
+            builder.Visit(this);
         }
     }
 }
\ No newline at end of file
--- a/Implab.ServiceHost/Unity/ContainerBuilder.cs	Thu May 03 09:59:44 2018 +0300
+++ b/Implab.ServiceHost/Unity/ContainerBuilder.cs	Fri May 04 18:12:42 2018 +0300
@@ -7,11 +7,11 @@
 
         readonly TypeResolver m_resolver;
 
-        readonly UnityContainer m_container;
+        readonly IUnityContainer m_container;
 
         readonly ContainerConfigurationSchema m_schema;
 
-        public UnityContainer Container {
+        public IUnityContainer Container {
             get {
                 return m_container;
             }
@@ -20,66 +20,14 @@
         public ContainerBuilder() : this(null, null) {
         }
 
-        public ContainerBuilder(UnityContainer container, ContainerConfigurationSchema schema) {
+        public ContainerBuilder(IUnityContainer container, ContainerConfigurationSchema schema) {
             m_container = container ?? new UnityContainer();
             m_resolver = new TypeResolver();
             m_schema = schema ?? ContainerConfigurationSchema.Default;
         }
 
         public Type ResolveType(string typeReference) {
-            return m_resolver.Resolve(typeReference, true);
-        }
-
-
-        internal void Visit(TypeAbstractRegistration typeRegistration) {
-            var registrationType = typeRegistration.GetRegistrationType(ResolveType);
-            var implementationType = typeRegistration.GetImplementationType(ResolveType) ?? registrationType;
-
-            var registrationContext = new TypeRegistrationBuilder(
-                m_resolver,
-                registrationType,
-                implementationType
-            );
-
-            typeRegistration.Visit(registrationContext);
-
-            m_container.RegisterType(
-                registrationContext.RegistrationType,
-                registrationContext.ImplementationType,
-                typeRegistration.Name,
-                registrationContext.Lifetime,
-                registrationContext.Injections
-            );
-        }
-
-        internal void Visit(InstanceAbstractRegistration instanceRegistration) {
-            var registrationType = instanceRegistration.GetRegistrationType(ResolveType);
-
-            var builder = new InstanceRegistrationBuilder(m_resolver, registrationType);
-
-            instanceRegistration.Visit(builder);
-
-            m_container.RegisterInstance(
-                builder.ValueBuilder.ValueType,
-                instanceRegistration.Name,
-                builder.ValueBuilder.Value,
-                builder.Lifetime
-            );
-        }
-
-        internal void Visit(FactoryAbstractRegistratrion factoryRgistration) {
-            var registrationType = factoryRgistration.GetRegistrationType(ResolveType);
-
-            var builder = new FactoryRegistrationBuilder(registrationType);
-
-            factoryRgistration.Visit(builder);
-
-            m_container.RegisterType(
-                builder.RegistrationType,
-                factoryRgistration.Name,
-                builder.Lifetime,
-                builder.Factory
-            );
+            return string.IsNullOrEmpty(typeReference) ? null : m_resolver.Resolve(typeReference, true);
         }
 
         public void Visit(ITypeRegistration registration) {
@@ -136,25 +84,11 @@
             m_container.RegisterInstance(
                 builder.RegistrationType ?? builder.ValueBuilder.ValueType,
                 registration.Name,
-                builder.ValueBuilder.Injection,
+                builder.ValueBuilder.Value,
                 builder.Lifetime                
             );
         }
 
-        public void Visit(IFactoryRegistration registration) {
-            Safe.ArgumentNotNull(registration, nameof(registration));
-
-            var registrationType = registration.GetRegistrationType(this);
-
-            var builder = new FactoryRegistrationBuilder(registrationType);
-
-            if (registration.MemberInjections != null) {
-                foreach(var member in registration.MemberInjections)
-                    member?.Visit(builder);
-            }
-
-        }
-
         public void AddNamespace(string ns) {
             m_resolver.AddNamespace(ns);
         }
--- a/Implab.ServiceHost/Unity/ContainerLifetimeElement.cs	Thu May 03 09:59:44 2018 +0300
+++ b/Implab.ServiceHost/Unity/ContainerLifetimeElement.cs	Fri May 04 18:12:42 2018 +0300
@@ -3,8 +3,10 @@
 namespace Implab.ServiceHost.Unity
 {
     public class ContainerLifetimeElement : LifetimeElement {
-        public override void Visit(RegistrationBuilder builder) {
-            builder.Visit(this);
+        public override LifetimeManager GetLifetime(ContainerBuilder builder) {
+            return new ContainerControlledLifetimeManager();
         }
+
+        
     }
 }
\ No newline at end of file
--- a/Implab.ServiceHost/Unity/ContextLifetimeElement.cs	Thu May 03 09:59:44 2018 +0300
+++ b/Implab.ServiceHost/Unity/ContextLifetimeElement.cs	Fri May 04 18:12:42 2018 +0300
@@ -3,8 +3,8 @@
 namespace Implab.ServiceHost.Unity
 {
     public class ContextLifetimeElement : LifetimeElement {
-        public override void Visit(RegistrationBuilder builder) {
-            builder.Visist(this);
+        public override LifetimeManager GetLifetime(ContainerBuilder builder) {
+            return new PerResolveLifetimeManager();
         }
     }
 }
\ No newline at end of file
--- a/Implab.ServiceHost/Unity/DependencyParameterElement.cs	Thu May 03 09:59:44 2018 +0300
+++ b/Implab.ServiceHost/Unity/DependencyParameterElement.cs	Fri May 04 18:12:42 2018 +0300
@@ -11,7 +11,7 @@
 
         public override  void Visit(InjectionParameterBuilder builder) {
             var type = builder.ResolveInjectedValueType(TypeName);
-            builder.SetDependencyReference(type, DependencyName, Optional);
+            builder.SetDependency(type, DependencyName, Optional);
         }
     }
 }
\ No newline at end of file
--- a/Implab.ServiceHost/Unity/FactoryAbstractRegistration.cs	Thu May 03 09:59:44 2018 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,11 +0,0 @@
-namespace Implab.ServiceHost.Unity {
-    public class FactoryAbstractRegistratrion : AbstractRegistration {
-        public override void Visit(ContainerBuilder builder) {
-            builder.Visit(this);
-        }
-
-        public virtual void Visit(FactoryRegistrationBuilder builder) {
-            base.Visit(builder);
-        }
-    }
-}
\ No newline at end of file
--- a/Implab.ServiceHost/Unity/FactoryActivator.cs	Thu May 03 09:59:44 2018 +0300
+++ b/Implab.ServiceHost/Unity/FactoryActivator.cs	Fri May 04 18:12:42 2018 +0300
@@ -1,29 +1,63 @@
 using System;
+using System.Collections.Generic;
+using System.Reflection;
+using Implab.Components;
+using Unity;
+using Unity.Injection;
+using Unity.Lifetime;
 
 namespace Implab.ServiceHost.Unity {
-    public class FactoryActivator : FactoryAbstractRegistratrion {
+    public class FactoryActivator : ITypeRegistration {
+
+        class FactoryInjector : ITypeMemberInjection {
+            public InjectionFactory Factory { get; set; }
+            public void Visit(TypeRegistrationBuilder builder) {
+                builder.AddInjectionMember(Factory);
+            }
+        }
+
 
         public Type FactoryType { get; set; }
 
         public string FactoryName { get; set; }
 
-        public new Type RegistrationType { get; set; }
+        public Type RegistrationType { get; set; }
 
-        public override void Visit(FactoryRegistrationBuilder builder) {
-            base.Visit(builder);
+        public LifetimeManager Lifetime { get; set; }
 
-            builder.GetType()
-                .GetMethod(
-                    nameof(FactoryRegistrationBuilder.SetFactoryDependency)
-                    , new[] { typeof(string) }
-                )
-                .MakeGenericMethod(FactoryType, RegistrationType)
-                .Invoke(builder, new[] { FactoryName });
+        public IEnumerable<ITypeMemberInjection> MemberInjections {
+            get {
+                yield return new FactoryInjector {
+                    Factory = (InjectionFactory)GetType()
+                        .GetMethod(nameof(CreateInjectionFactory), BindingFlags.Static | BindingFlags.NonPublic)
+                        .MakeGenericMethod(FactoryType, RegistrationType)
+                        .Invoke(null, new [] { FactoryName })
+                };
+            }
         }
 
-        public override Type GetRegistrationType(Func<string, Type> resolver) {
+        public string Name { get; set; }
+
+        public Type GetRegistrationType(ContainerBuilder builder) {
             return RegistrationType;
         }
 
+        public LifetimeManager GetLifetime(ContainerBuilder builder) {
+            return Lifetime;
+        }
+
+        public Type GetImplementationType(ContainerBuilder builder) {
+            return null;
+        }
+
+        /// <summary>
+        /// Указывает зависимость, реализующую интерфейс <see cref="IFactory{TObj}"/>,
+        /// которая будет использоваться в качестве фабрики для создания объектов
+        /// </summary>
+        /// <param name="dependencyName"></param>
+        static InjectionFactory CreateInjectionFactory<TFac, TObj>(string dependencyName) where TFac : IFactory<TObj> {
+            
+            return new InjectionFactory(c => c.Resolve<TFac>(dependencyName).Create());
+        }
     }
 }
\ No newline at end of file
--- a/Implab.ServiceHost/Unity/FactoryElement.cs	Thu May 03 09:59:44 2018 +0300
+++ b/Implab.ServiceHost/Unity/FactoryElement.cs	Fri May 04 18:12:42 2018 +0300
@@ -7,7 +7,7 @@
     /// Расширяет стандартную регистрацию типа до фабрики, вместе с регистрацией
     /// самой фабрики создаются регистрации сервисов, которые она предоставляет.
     /// </summary>
-    public class FactoryElement : RegisterElement {
+    public class FactoryElement : RegisterElement, ITypeRegistration {
 
         /// <summary>
         /// Записи о сервисах, которые создаются данной фабрикой.
@@ -38,7 +38,7 @@
                         FactoryName = Name,
                         FactoryType = factoryType
                     };
-                    activator.Visit(builder);
+                    builder.Visit(activator);
                 }
             } else {
                 // если регистрация явно не задана, в качестве сервиса для регистрации
@@ -65,7 +65,7 @@
                     FactoryType = factoryType
                 };
 
-                activator.Visit(builder);
+                builder.Visit(activator);
             }
         }
     }
--- a/Implab.ServiceHost/Unity/FactoryRegistrationBuilder.cs	Thu May 03 09:59:44 2018 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,54 +0,0 @@
-using System;
-using Implab.Components;
-using Unity;
-using Unity.Injection;
-using Unity.Registration;
-
-namespace Implab.ServiceHost.Unity
-{
-    public class FactoryRegistrationBuilder : RegistrationBuilder {
-        
-        internal InjectionMember Factory { get; private set; }
-
-        internal FactoryRegistrationBuilder(Type registrationType) : base(registrationType) {
-        }
-
-        /// <summary>
-        /// Задает делегат, который будет использоваться в качестве фабрики
-        /// для создания экземпляров, параметры делагата будет заполнены
-        /// соответствующими зависимостями.
-        /// </summary>
-        /// <param name="factory">Фабрика для создания экземпляров.</param>
-        public void SetFactoryDelegate(Delegate factory) {
-            Safe.ArgumentNotNull(factory, nameof(factory));
-
-            Factory = new DelegateInjectionFactory(factory);
-        }
-
-        /// <summary>
-        /// Указывает зависимость типа <typeparamref name="T"/> с именем
-        /// <paramref name="dependencyName"/>, которая будет передана в качетве
-        /// параметра делегату <paramref name="factory"/>
-        /// </summary>
-        /// <param name="dependencyName">Имя зависимости</param>
-        /// <param name="factory">Фабрика для создания экземпляра</param>
-        public void SetFactoryDependency<T>(string dependencyName, Func<T, object> factory) {
-            Safe.ArgumentNotNull(factory, nameof(factory));
-
-            Factory = new InjectionFactory((c,t,name) => {
-                var backend = c.Resolve<T>(dependencyName);
-                return factory(backend);
-            });
-        }
-
-        /// <summary>
-        /// Указывает зависимость, реализующую интерфейс <see cref="IFactory{TObj}"/>,
-        /// которая будет использоваться в качестве фабрики для создания объектов
-        /// </summary>
-        /// <param name="dependencyName"></param>
-        public void SetFactoryDependency<TFac, TObj>(string dependencyName) where TFac : IFactory<TObj> {
-            
-            Factory = new InjectionFactory(c => c.Resolve<TFac>(dependencyName).Create());
-        }
-    }
-}
\ No newline at end of file
--- a/Implab.ServiceHost/Unity/HierarchicalLifetimeElement.cs	Thu May 03 09:59:44 2018 +0300
+++ b/Implab.ServiceHost/Unity/HierarchicalLifetimeElement.cs	Fri May 04 18:12:42 2018 +0300
@@ -3,8 +3,8 @@
 namespace Implab.ServiceHost.Unity
 {
     public class HierarchicalLifetimeElement : LifetimeElement {
-        public override void Visit(RegistrationBuilder builder) {
-            builder.Visit(this);
+        public override LifetimeManager GetLifetime(ContainerBuilder builder) {
+            return new HierarchicalLifetimeManager();
         }
     }
 }
\ No newline at end of file
--- a/Implab.ServiceHost/Unity/IFactoryMemberInjection.cs	Thu May 03 09:59:44 2018 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,5 +0,0 @@
-namespace Implab.ServiceHost.Unity {
-    public interface IFactoryMemberInjection {
-        void Visit(FactoryRegistrationBuilder builder);
-    }
-}
\ No newline at end of file
--- a/Implab.ServiceHost/Unity/IFactoryRegistration.cs	Thu May 03 09:59:44 2018 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,7 +0,0 @@
-using System.Collections.Generic;
-
-namespace Implab.ServiceHost.Unity {
-    public interface IFactoryRegistration : IRegistration {
-        IEnumerable<IFactoryMemberInjection> MemberInjections { get; }
-    }
-}
\ No newline at end of file
--- a/Implab.ServiceHost/Unity/InjectionParameterElement.cs	Thu May 03 09:59:44 2018 +0300
+++ b/Implab.ServiceHost/Unity/InjectionParameterElement.cs	Fri May 04 18:12:42 2018 +0300
@@ -2,7 +2,7 @@
 using System.Xml.Serialization;
 
 namespace Implab.ServiceHost.Unity {
-    public abstract class InjectionParameterElement {
+    public abstract class InjectionParameterElement : IInjectionParameter {
         
         [XmlAttribute("type")]
         public string TypeName { get; set; }
--- a/Implab.ServiceHost/Unity/InjectionValueBuilder.cs	Thu May 03 09:59:44 2018 +0300
+++ b/Implab.ServiceHost/Unity/InjectionValueBuilder.cs	Fri May 04 18:12:42 2018 +0300
@@ -1,4 +1,5 @@
 using System;
+using System.Collections;
 using System.Collections.Generic;
 using System.ComponentModel;
 using System.Linq;
@@ -15,17 +16,32 @@
 
         public Type ValueType { get; private set; }
 
-        public object Value { get; set; }
+        object m_value;
 
-        internal InjectionParameterValue Injection {
+        public object Value {
             get {
-                if (Value != null)
-                    return InjectionParameterValue.ToParameter(Value);
+                if (!ValueSpecified)
+                    throw new InvalidOperationException("The regular value must be set (dependency or array are not situable in this context)");
+                return m_value;
+            }
+        }
+
+        public bool ValueSpecified { get; private set; }
+
+        InjectionParameterValue m_injection;
 
-                return new InjectionParameter(ValueType, null);
+        public InjectionParameterValue Injection {
+            get {
+                if (m_injection == null)
+                    throw new InvalidOperationException("The injection parameter is not specified");
+                return m_injection;
             }
         }
 
+        public bool InjectionSpecified {
+            get { return m_injection != null; }
+        }
+
         internal InjectionParameterBuilder(TypeResolver resolver, Type defaultType) {
             m_resolver = resolver;
             DefaultType = defaultType;
@@ -41,33 +57,42 @@
         }
 
         public Type ResolveType(string typeSpec) {
-            return m_resolver.Resolve(typeSpec, true);
+            return string.IsNullOrEmpty(typeSpec) ? null : m_resolver.Resolve(typeSpec, true);
         }
 
         public void SetValue(Type type, object value) {
+            Safe.ArgumentNotNull(type, nameof(type));
+
             ValueType = type;
-            Value = value;
+            m_value = value;
+            ValueSpecified = true;
+
+            m_injection = new InjectionParameter(type, value);
         }
 
-        public void SetValue<T>(T value) {
-            SetValue(typeof(T), value);
-        }
+        public void SetDependency(Type type, string name, bool optional) {
+            Safe.ArgumentNotNull(type, nameof(type));
 
-        public void SetDependencyReference(Type type, string name, bool optional) {
             ValueType = type;
-            Value = optional ? (object)new OptionalParameter(type, name) : new ResolvedParameter(type, name);
+            ValueSpecified = false;
+            m_value = null;
+            
+            m_injection = optional ? (InjectionParameterValue)new OptionalParameter(type, name) : new ResolvedParameter(type, name);
         }
 
         internal void Visit(ArrayParameterElement arrayParameter) {
             Type itemsType = null;
             var arrayType = string.IsNullOrEmpty(arrayParameter.TypeName) ? null : ResolveType(arrayParameter.TypeName);
 
+            if (arrayType == null)
+                arrayType = DefaultType;
+
+
             if (!string.IsNullOrEmpty(arrayParameter.ItemsType)) {
                 itemsType = ResolveType(arrayParameter.ItemsType);
-                if (arrayType == null)
-                    arrayType = itemsType.MakeArrayType();
+                arrayType = itemsType.MakeArrayType();
             } else {
-                itemsType = arrayType?.GetInterface(typeof(IEnumerable<>).FullName)?.GetGenericArguments()[0];
+                itemsType = GetItemsType(arrayType);
             }
 
             if (itemsType == null)
@@ -82,11 +107,31 @@
                 .ToArray();
 
             var array = itemsType.IsGenericParameter ?
-                (object)new GenericResolvedArrayParameter(itemsType.Name, injections) :
+                (InjectionParameterValue)new GenericResolvedArrayParameter(itemsType.Name, injections) :
                 new ResolvedArrayParameter(itemsType, injections);
 
             ValueType = arrayType;
-            Value = array;
+            m_value = null;
+            ValueSpecified = false;
+            
+            m_injection = array;
+        }
+
+        Type GetItemsType(Type collectionType) {
+            if (collectionType == null)
+                return null;
+
+            Type itemsType = null;
+
+            if (collectionType.GetGenericTypeDefinition() == typeof(IEnumerable<>)) {
+                itemsType = collectionType.GetGenericArguments()[0];
+            } else if (collectionType == typeof(IEnumerable)) {
+                itemsType = typeof(object);
+            } else {
+                itemsType = collectionType.GetInterface(typeof(IEnumerable<>).FullName)?.GetGenericArguments()[0];
+            }
+            
+            return itemsType;
         }
     }
 }
\ No newline at end of file
--- a/Implab.ServiceHost/Unity/InstanceAbstractRegistration.cs	Thu May 03 09:59:44 2018 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,12 +0,0 @@
-namespace Implab.ServiceHost.Unity
-{
-    public abstract class InstanceAbstractRegistration : AbstractRegistration {
-        public override void Visit(ContainerBuilder builder) {
-            builder.Visit(this);
-        }
-
-        public virtual void Visit(InstanceRegistrationBuilder builder) {
-            base.Visit(builder);
-        }
-    }
-}
\ No newline at end of file
--- a/Implab.ServiceHost/Unity/LifetimeElement.cs	Thu May 03 09:59:44 2018 +0300
+++ b/Implab.ServiceHost/Unity/LifetimeElement.cs	Fri May 04 18:12:42 2018 +0300
@@ -1,5 +1,7 @@
+using Unity.Lifetime;
+
 namespace Implab.ServiceHost.Unity {
     public abstract class LifetimeElement {
-        public abstract void Visit(RegistrationBuilder builder);
+        public abstract LifetimeManager GetLifetime(ContainerBuilder builder);
     }
 }
\ No newline at end of file
--- a/Implab.ServiceHost/Unity/MethodInjectionElement.cs	Thu May 03 09:59:44 2018 +0300
+++ b/Implab.ServiceHost/Unity/MethodInjectionElement.cs	Fri May 04 18:12:42 2018 +0300
@@ -13,7 +13,7 @@
         [XmlElement("array", typeof(ArrayParameterElement))]
         public InjectionParameterElement[] Parameters { get; set; }
 
-        internal override void Visit(TypeRegistrationBuilder context) {
+        public override void Visit(TypeRegistrationBuilder context) {
             context.Visit(this);
         }
     }
--- a/Implab.ServiceHost/Unity/PropertyInjectionElement.cs	Thu May 03 09:59:44 2018 +0300
+++ b/Implab.ServiceHost/Unity/PropertyInjectionElement.cs	Fri May 04 18:12:42 2018 +0300
@@ -13,7 +13,7 @@
         [XmlElement("array", typeof(ArrayParameterElement))]
         public InjectionParameterElement Value { get; set; }
 
-        internal override void Visit(TypeRegistrationBuilder context) {
+        public override void Visit(TypeRegistrationBuilder context) {
             context.Visit(this);
         }
     }
--- a/Implab.ServiceHost/Unity/RegisterElement.cs	Thu May 03 09:59:44 2018 +0300
+++ b/Implab.ServiceHost/Unity/RegisterElement.cs	Fri May 04 18:12:42 2018 +0300
@@ -1,4 +1,5 @@
 using System;
+using System.Collections.Generic;
 using System.Xml.Serialization;
 using Unity.Lifetime;
 using Unity.Registration;
@@ -6,7 +7,7 @@
 namespace Implab.ServiceHost.Unity {
 
     [XmlRoot("register", Namespace = Schema.ContainerConfigurationNamespace)]
-    public class RegisterElement : TypeAbstractRegistration  {
+    public class RegisterElement : AbstractRegistration, ITypeRegistration  {
         
         /// <summary>
         /// An optional type which is registered as a service in the container, must be assignable to <see cref="ProvidesType">.
@@ -20,17 +21,19 @@
         [XmlElement("method", typeof(MethodInjectionElement))]
         public AbstractMemberInjection[] Injectors { get; set; }
 
-        public override Type GetImplementationType(Func<string, Type> resolver) {
-            return string.IsNullOrEmpty(MapToType) ? null : resolver(MapToType);
+        IEnumerable<ITypeMemberInjection> ITypeRegistration.MemberInjections {
+            get {
+                return Injectors;
+            }
         }
 
-        public override void Visit(TypeRegistrationBuilder builder) {
-            if(Injectors != null)
-                foreach(var injector in Injectors)
-                    injector.Visit(builder);
+        public Type GetImplementationType(ContainerBuilder builder) {
+            return builder.ResolveType(MapToType);
         }
 
-        
+        public override void Visit(ContainerBuilder builder) {
+            builder.Visit(this);
+        }
     }
     
 }
\ No newline at end of file
--- a/Implab.ServiceHost/Unity/SerializedElement.cs	Thu May 03 09:59:44 2018 +0300
+++ b/Implab.ServiceHost/Unity/SerializedElement.cs	Fri May 04 18:12:42 2018 +0300
@@ -1,10 +1,10 @@
 using System;
+using System.Collections.Generic;
 using System.Xml;
 using System.Xml.Serialization;
 
-namespace Implab.ServiceHost.Unity
-{
-    public class SerializedElement : InstanceAbstractRegistration {
+namespace Implab.ServiceHost.Unity {
+    public class SerializedElement : AbstractRegistration, IInstanceRegistration {
         [XmlAttribute("href")]
         public string Location { get; set; }
 
@@ -15,15 +15,18 @@
         [XmlAnyElement]
         public XmlElement[] Content { get; set; }
 
-        public override void Visit(InstanceRegistrationBuilder builder) {
-            base.Visit(builder);
+        public IEnumerable<IInjectionParameter> MemberInjections {
+            get {
+                yield return new SerializedParameterElement {
+                    TypeName = SerializedType,
+                    Location = Location,
+                    Content = Content
+                };
+            }
+        }
 
-            var parameter = new SerializedParameterElement {
-                TypeName = SerializedType,
-                Location = Location,
-                Content = Content
-            };
-            parameter.Visit(builder.ValueBuilder);
+        public override void Visit(ContainerBuilder builder) {
+            builder.Visit(this);
         }
     }
 }
\ No newline at end of file
--- a/Implab.ServiceHost/Unity/SingletonLifetimeElement.cs	Thu May 03 09:59:44 2018 +0300
+++ b/Implab.ServiceHost/Unity/SingletonLifetimeElement.cs	Fri May 04 18:12:42 2018 +0300
@@ -1,8 +1,10 @@
+using Unity.Lifetime;
+
 namespace Implab.ServiceHost.Unity
 {
     public class SingletonLifetimeElement : LifetimeElement {
-        public override void Visit(RegistrationBuilder builder) {
-            builder.Visit(this);
+        public override LifetimeManager GetLifetime(ContainerBuilder builder) {
+            return new SingletonLifetimeManager();
         }
     }
 }
\ No newline at end of file
--- a/Implab.ServiceHost/Unity/TypeAbstractRegistration.cs	Thu May 03 09:59:44 2018 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,17 +0,0 @@
-using System;
-
-namespace Implab.ServiceHost.Unity
-{
-    public abstract class TypeAbstractRegistration : AbstractRegistration {
-
-        public abstract Type GetImplementationType(Func<string,Type> resolver);
-        
-        override public void Visit(ContainerBuilder builder)  {
-            builder.Visit(this);
-        }
-
-        public virtual void Visit(TypeRegistrationBuilder builder) {
-            base.Visit(builder);
-        }
-    }
-}
\ No newline at end of file
--- a/Implab.ServiceHost/Unity/TypeRegistrationBuilder.cs	Thu May 03 09:59:44 2018 +0300
+++ b/Implab.ServiceHost/Unity/TypeRegistrationBuilder.cs	Fri May 04 18:12:42 2018 +0300
@@ -71,5 +71,11 @@
             var injection = new InjectionProperty(propertyInjection.Name, valueContext.Injection);
             m_injections.Add(injection);
         }
+
+        public void AddInjectionMember(InjectionMember injection) {
+            Safe.ArgumentNotNull(injection, nameof(injection));
+
+            m_injections.Add(injection);
+        }
     }
 }
\ No newline at end of file
--- a/Implab.ServiceHost/Unity/TypeResolver.cs	Thu May 03 09:59:44 2018 +0300
+++ b/Implab.ServiceHost/Unity/TypeResolver.cs	Fri May 04 18:12:42 2018 +0300
@@ -27,6 +27,7 @@
         }
 
         public Type Resolve(string typeSpec, bool throwOnFail) {
+            Safe.ArgumentNotEmpty(typeSpec, nameof(typeSpec));
             var typeReference = TypeReference.Parse(typeSpec);
             return Resolve(typeReference, throwOnFail);
         }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Implab.ServiceHost/Unity/UnityContainerExtensions.cs	Fri May 04 18:12:42 2018 +0300
@@ -0,0 +1,40 @@
+using System.IO;
+using Unity;
+
+namespace Implab.ServiceHost.Unity
+{
+    public static class UnityContainerExtensions
+    {
+        public static IUnityContainer LoadXmlConfiguration(this IUnityContainer container, string file, ContainerConfigurationSchema schema) {
+            Safe.ArgumentNotNull(container, nameof(container));
+            var builder = new ContainerBuilder(container,schema);
+            builder.LoadConfig(file);
+            return builder.Container;
+        }
+
+        public static IUnityContainer LoadXmlConfiguration(this IUnityContainer container, Stream stream, ContainerConfigurationSchema schema) {
+            Safe.ArgumentNotNull(container, nameof(container));
+            Safe.ArgumentNotNull(stream, nameof(stream));
+            
+            if (schema == null)
+                schema = ContainerConfigurationSchema.Default;
+
+            var builder = new ContainerBuilder(container,schema);
+            var config = (ContainerElement)schema.Serializer.Deserialize(stream);
+            if (config.Items != null) {
+                foreach(var item in config.Items)
+                    item?.Visit(builder);
+            }
+
+            return builder.Container;
+        }
+
+        public static IUnityContainer LoadXmlConfiguration(this IUnityContainer container, Stream stream) {
+            return LoadXmlConfiguration(container, stream, ContainerConfigurationSchema.Default);
+        }
+
+        public static IUnityContainer LoadXmlConfiguration(this IUnityContainer container, string file) {
+            return LoadXmlConfiguration(container, file, ContainerConfigurationSchema.Default);
+        }
+    }
+}
\ No newline at end of file
--- a/Implab.ServiceHost/Unity/ValueElement.cs	Thu May 03 09:59:44 2018 +0300
+++ b/Implab.ServiceHost/Unity/ValueElement.cs	Fri May 04 18:12:42 2018 +0300
@@ -1,8 +1,9 @@
+using System.Collections.Generic;
 using System.Xml.Serialization;
 
 namespace Implab.ServiceHost.Unity {
-    public class ValueElement : InstanceAbstractRegistration {
-        
+    public class ValueElement : AbstractRegistration, IInstanceRegistration {
+
         [XmlAttribute("value")]
         public string Value { get; set; }
 
@@ -19,13 +20,17 @@
             }
         }
 
-        public override void Visit(InstanceRegistrationBuilder builder) {
-            base.Visit(builder);
-            var parameter = new ValueParameterElement {
-                Value = Value,
-                Text = Text
-            };
-            parameter.Visit(builder.ValueBuilder);
+        public IEnumerable<IInjectionParameter> MemberInjections {
+            get {
+                yield return new ValueParameterElement {
+                    Value = Value,
+                    Text = Text
+                };
+            }
+        }
+
+        public override void Visit(ContainerBuilder builder) {
+            builder.Visit(this);
         }
     }
 }
\ No newline at end of file