changeset 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 963b17c275be
children 8714471e8d78
files Implab.Playground/Program.cs Implab.Playground/data/sample.xml Implab.ServiceHost/Unity/ArrayParameterElement.cs Implab.ServiceHost/Unity/ArrayTypeReference.cs Implab.ServiceHost/Unity/AssemblyElement.cs Implab.ServiceHost/Unity/ContainerBuilder.cs Implab.ServiceHost/Unity/ContainerConfigurationSchema.cs Implab.ServiceHost/Unity/DefaultParameterElement.cs Implab.ServiceHost/Unity/DependencyParameterElement.cs Implab.ServiceHost/Unity/FactoryActivator.cs Implab.ServiceHost/Unity/FactoryElement.cs Implab.ServiceHost/Unity/FactoryRegistrationBuilder.cs Implab.ServiceHost/Unity/IFactoryMemberInjection.cs Implab.ServiceHost/Unity/IFactoryRegistration.cs Implab.ServiceHost/Unity/IInjectionParameter.cs Implab.ServiceHost/Unity/IInstanceRegistration.cs Implab.ServiceHost/Unity/IRegistration.cs Implab.ServiceHost/Unity/ITypeMemberInjection.cs Implab.ServiceHost/Unity/ITypeRegistration.cs Implab.ServiceHost/Unity/IncludeElement.cs Implab.ServiceHost/Unity/InjectionParameterElement.cs Implab.ServiceHost/Unity/InjectionValueBuilder.cs Implab.ServiceHost/Unity/InstanceRegistrationBuilder.cs Implab.ServiceHost/Unity/NamespaceElement.cs Implab.ServiceHost/Unity/NestedTypeReference.cs Implab.ServiceHost/Unity/ProvidesElement.cs Implab.ServiceHost/Unity/RootTypeReference.cs Implab.ServiceHost/Unity/SerializedParameterElement.cs Implab.ServiceHost/Unity/SpecializedTypeReference.cs Implab.ServiceHost/Unity/TypeReference.cs Implab.ServiceHost/Unity/TypeReferenceParser.cs Implab.ServiceHost/Unity/TypeRegistrationBuilder.cs Implab.ServiceHost/Unity/TypeResolutionContext.cs Implab.ServiceHost/Unity/TypeResolver.cs Implab.ServiceHost/Unity/ValueParameterElement.cs Implab/Xml/SerializationHelpers.cs Implab/Xml/SerializersPool.cs Implab/Xml/XmlDefaultSerializer.cs Implab/Xml/XmlSerializerExtensions.cs
diffstat 39 files changed, 1011 insertions(+), 203 deletions(-) [+]
line wrap: on
line diff
--- a/Implab.Playground/Program.cs	Sat Apr 28 18:48:09 2018 +0300
+++ b/Implab.Playground/Program.cs	Thu May 03 09:59:44 2018 +0300
@@ -2,6 +2,7 @@
 using System.Collections.Generic;
 using System.Diagnostics;
 using System.Linq;
+using Implab.Components;
 using Implab.Diagnostics;
 using Implab.ServiceHost.Unity;
 using Implab.Xml;
@@ -29,11 +30,39 @@
 
     }
 
+    public class FooFactory : IFactory<Foo>, IFactory<Foo.Bar> {
+
+        public bool UseSsl { get; set; }
+
+        public string Connection { get; set; }
+        
+        public Foo Create() {
+            return new Foo() {
+                Name = "AutoFac"
+            };
+        }
+
+        Foo.Bar IFactory<Foo.Bar>.Create() {
+            return new Foo.Bar(); 
+        }
+    }
+
     public interface IContainer<T> {
         T Instance { get; set; }
     }
 
     public class Container<T> : IContainer<T> {
+        public class Bar {
+
+        }
+
+        public class Bar<T2> {
+            public class Baz {
+
+            }
+
+        }
+
         public Container() {
 
         }
@@ -65,29 +94,22 @@
             source.Switch.Level = SourceLevels.All;
             source.Listeners.Add(listener);
 
-            var stopwatch = new Stopwatch();
-            stopwatch.Start();
-
-            var ctx = new ContainerBuilder();
-
-            Console.WriteLine($"Created: {stopwatch.ElapsedMilliseconds}");
-            stopwatch.Restart();
-            
-            ctx.LoadConfig("data/sample.xml");
-
-            Console.WriteLine($"Loaded: {stopwatch.ElapsedMilliseconds}");
+            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 container = ctx.Container;
+            var spec = TypeReference.Parse("Container{listOf{string}}+Bar{List{string}}");
 
-            stopwatch.Restart();
-            var instace1 = container.Resolve<IContainer<string>>();
-            Console.WriteLine($"Resolved1: {stopwatch.ElapsedMilliseconds}");
+            var t = resolver.Resolve(spec, true);
 
-            stopwatch.Restart();
-            var instace2 = container.Resolve<IContainer<Foo>>();
-            Console.WriteLine($"Resolved2: {stopwatch.ElapsedMilliseconds}");
-
-            DisplayContainerRegistrations(container);
+            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);
         }
 
         static void DisplayContainerRegistrations(IUnityContainer theContainer) {
--- a/Implab.Playground/data/sample.xml	Sat Apr 28 18:48:09 2018 +0300
+++ b/Implab.Playground/data/sample.xml	Thu May 03 09:59:44 2018 +0300
@@ -2,6 +2,7 @@
 <container xmlns="http://implab.org/schemas/servicehost/unity.v1.xsd">
     <namespace name="System"/>
     <namespace name="System.Collections.Generic"/>
+    <namespace name="Implab.Components"/>
     <namespace name="Implab.Playground"/>
     
     <!-- foo1 -->
@@ -36,7 +37,7 @@
         </method>
         <method name="AddRange">
             <array itemsType="T">
-                <dependency name="foo2"/>
+                <dependency name="foo2-bar"/>
             </array>
         </method>
     </register>
@@ -61,8 +62,13 @@
     <value name="connection1" type="String"><![CDATA[Connect me <here>!]]></value>
     <value name="name1" type="String" value="Hello!"/>
 
-    <factory name="foo3" type="FooFactory">
-        <parameter name="FooName"><![CDATA[Wired "" objecty <> name @#$%^&]]></parameter>
+    <factory name="foo3" type="IFactory{Foo}" mapTo="FooFactory">
+        <property name="Connection">
+            <value><![CDATA[Wired "" objecty <> name @#$%^&]]></value>
+        </property>
+        <property name="UseSsl">
+            <value>false</value>
+        </property>
     </factory>
 
 </container>
\ No newline at end of file
--- a/Implab.ServiceHost/Unity/ArrayParameterElement.cs	Sat Apr 28 18:48:09 2018 +0300
+++ b/Implab.ServiceHost/Unity/ArrayParameterElement.cs	Thu May 03 09:59:44 2018 +0300
@@ -13,7 +13,7 @@
         [XmlElement("default", typeof(DefaultParameterElement))]
         public InjectionParameterElement[] Items { get; set; }
 
-        public override void Visit(InjectionValueBuilder builder) {
+        public override void Visit(InjectionParameterBuilder builder) {
             builder.Visit(this);
         }
     }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Implab.ServiceHost/Unity/ArrayTypeReference.cs	Thu May 03 09:59:44 2018 +0300
@@ -0,0 +1,57 @@
+using System;
+using System.Text;
+
+namespace Implab.ServiceHost.Unity {
+    public class ArrayTypeReference : TypeReference {
+        public int Rank { get; private set; }
+
+        public TypeReference ItemsType { get; private set; }
+
+        public override string Name {
+            get {
+                return ItemsType.Name;
+            }
+        }
+
+        public override string ClrName {
+            get {
+                return new StringBuilder()
+                    .Append(ItemsType.ClrName)
+                    .Append("[")
+                    .Append(',', Rank - 1)
+                    .Append("]")
+                    .ToString();
+            }
+        }
+
+        public override string Namespace {
+            get {
+                return ItemsType.Namespace;
+            }
+        }
+
+        public override int GenericParametersCount {
+            get {
+                return 0;
+            }
+        }
+
+        internal ArrayTypeReference(TypeReference itemsType, int rank) {
+            ItemsType = itemsType;
+            Rank = rank;
+        }
+
+        internal override void Visit(TypeResolutionContext visitor) {
+            visitor.Visit(this);
+        }
+
+        override public string ToString() {
+            return new StringBuilder()
+                .Append(ItemsType.ToString())
+                .Append('[')
+                .Append(',', Rank - 1)
+                .Append(']')
+                .ToString();
+        }
+    }
+}
\ No newline at end of file
--- a/Implab.ServiceHost/Unity/AssemblyElement.cs	Sat Apr 28 18:48:09 2018 +0300
+++ b/Implab.ServiceHost/Unity/AssemblyElement.cs	Thu May 03 09:59:44 2018 +0300
@@ -8,7 +8,7 @@
         public string AssemblyName { get; set; }
         
         public override void Visit(ContainerBuilder builder) {
-            builder.Visit(this);
+            builder.AddAssembly(AssemblyName);
         }
     }
 }
\ No newline at end of file
--- a/Implab.ServiceHost/Unity/ContainerBuilder.cs	Sat Apr 28 18:48:09 2018 +0300
+++ b/Implab.ServiceHost/Unity/ContainerBuilder.cs	Thu May 03 09:59:44 2018 +0300
@@ -1,17 +1,8 @@
 using System;
-using System.Collections.Generic;
-using System.Text.RegularExpressions;
-using Implab.Diagnostics;
+using System.Reflection;
+using Unity;
 
 namespace Implab.ServiceHost.Unity {
-    using System.Linq;
-    using System.Reflection;
-    using System.Text;
-    using global::Unity;
-    using global::Unity.Registration;
-    using Implab.Xml;
-    using static Trace<ContainerBuilder>;
-
     public class ContainerBuilder {
 
         readonly TypeResolver m_resolver;
@@ -36,7 +27,7 @@
         }
 
         public Type ResolveType(string typeReference) {
-            return m_resolver.Resolve(typeReference);
+            return m_resolver.Resolve(typeReference, true);
         }
 
 
@@ -91,16 +82,85 @@
             );
         }
 
-        internal void Visit(NamespaceElement namespaceElement) {
-            m_resolver.AddNamespace(namespaceElement.Name);
+        public void Visit(ITypeRegistration registration) {
+            Safe.ArgumentNotNull(registration, nameof(registration));
+
+            var registrationType = registration.GetRegistrationType(this);
+            var implementationType = registration.GetImplementationType(this) ?? registrationType;
+
+            if (registrationType == null)
+                throw new Exception($"A type must be specified for the registration {registration.Name}");
+
+            var builder = new TypeRegistrationBuilder(
+                m_resolver,
+                registrationType,
+                implementationType
+            );
+
+            builder.Lifetime = registration.GetLifetime(this);
+
+            if (registration.MemberInjections != null) {
+                foreach(var member in registration.MemberInjections)
+                    member.Visit(builder);
+            }
+
+            m_container.RegisterType(
+                builder.RegistrationType,
+                builder.ImplementationType,
+                registration.Name,
+                builder.Lifetime,
+                builder.Injections
+            );
         }
 
-        internal void Visit(AssemblyElement assemblyElement) {
-            Assembly.Load(assemblyElement.AssemblyName);
+        public void Visit(IInstanceRegistration registration) {
+            Safe.ArgumentNotNull(registration, nameof(registration));
+
+            var registrationType = registration.GetRegistrationType(this);
+
+            var builder = new InstanceRegistrationBuilder (
+                m_resolver,
+                registrationType
+            );
+
+            builder.Lifetime = registration.GetLifetime(this);
+
+            if (registration.MemberInjections != null) {
+                foreach(var member in registration.MemberInjections)
+                    member.Visit(builder.ValueBuilder);
+            }
+
+            if (builder.RegistrationType == null && builder.ValueBuilder.ValueType == null)
+                throw new Exception($"A type must be specified for the registration {registration.Name}");
+
+            m_container.RegisterInstance(
+                builder.RegistrationType ?? builder.ValueBuilder.ValueType,
+                registration.Name,
+                builder.ValueBuilder.Injection,
+                builder.Lifetime                
+            );
         }
 
-        internal void Visit(IncludeElement includeElement) {
-            Include(includeElement.Href);
+        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);
+        }
+
+        public void AddAssembly(string assembly) {
+
         }
 
         public void Include(string file) {
@@ -110,9 +170,8 @@
 
         public void LoadConfig(string file) {
             var config = m_schema.LoadFile(file);
-            
             config.Visit(this);
         }
-        
+
     }
 }
\ No newline at end of file
--- a/Implab.ServiceHost/Unity/ContainerConfigurationSchema.cs	Sat Apr 28 18:48:09 2018 +0300
+++ b/Implab.ServiceHost/Unity/ContainerConfigurationSchema.cs	Thu May 03 09:59:44 2018 +0300
@@ -55,6 +55,7 @@
             var schema = new ContainerConfigurationSchema();
 
             schema.RegisterContainerElement<RegisterElement>("register");
+            schema.RegisterContainerElement<FactoryElement>("factory");
             schema.RegisterContainerElement<SerializedElement>("serialized");
             schema.RegisterContainerElement<ValueElement>("value");
             schema.RegisterContainerElement<IncludeElement>("include");
--- a/Implab.ServiceHost/Unity/DefaultParameterElement.cs	Sat Apr 28 18:48:09 2018 +0300
+++ b/Implab.ServiceHost/Unity/DefaultParameterElement.cs	Thu May 03 09:59:44 2018 +0300
@@ -5,7 +5,7 @@
             get { return null; }
         }
 
-        public override void Visit(InjectionValueBuilder builder) {
+        public override void Visit(InjectionParameterBuilder builder) {
             var type = builder.ResolveInjectedValueType(TypeName);
             builder.SetValue(type, Safe.CreateDefaultValue(type));
         }
--- a/Implab.ServiceHost/Unity/DependencyParameterElement.cs	Sat Apr 28 18:48:09 2018 +0300
+++ b/Implab.ServiceHost/Unity/DependencyParameterElement.cs	Thu May 03 09:59:44 2018 +0300
@@ -9,7 +9,7 @@
         [XmlAttribute("optional")]
         public bool Optional { get; set; }
 
-        public override  void Visit(InjectionValueBuilder builder) {
+        public override  void Visit(InjectionParameterBuilder builder) {
             var type = builder.ResolveInjectedValueType(TypeName);
             builder.SetDependencyReference(type, DependencyName, Optional);
         }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Implab.ServiceHost/Unity/FactoryActivator.cs	Thu May 03 09:59:44 2018 +0300
@@ -0,0 +1,29 @@
+using System;
+
+namespace Implab.ServiceHost.Unity {
+    public class FactoryActivator : FactoryAbstractRegistratrion {
+
+        public Type FactoryType { get; set; }
+
+        public string FactoryName { get; set; }
+
+        public new Type RegistrationType { get; set; }
+
+        public override void Visit(FactoryRegistrationBuilder builder) {
+            base.Visit(builder);
+
+            builder.GetType()
+                .GetMethod(
+                    nameof(FactoryRegistrationBuilder.SetFactoryDependency)
+                    , new[] { typeof(string) }
+                )
+                .MakeGenericMethod(FactoryType, RegistrationType)
+                .Invoke(builder, new[] { FactoryName });
+        }
+
+        public override Type GetRegistrationType(Func<string, Type> resolver) {
+            return RegistrationType;
+        }
+
+    }
+}
\ No newline at end of file
--- /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
--- a/Implab.ServiceHost/Unity/FactoryRegistrationBuilder.cs	Sat Apr 28 18:48:09 2018 +0300
+++ b/Implab.ServiceHost/Unity/FactoryRegistrationBuilder.cs	Thu May 03 09:59:44 2018 +0300
@@ -13,12 +13,25 @@
         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));
 
@@ -28,6 +41,11 @@
             });
         }
 
+        /// <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());
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Implab.ServiceHost/Unity/IFactoryMemberInjection.cs	Thu May 03 09:59:44 2018 +0300
@@ -0,0 +1,5 @@
+namespace Implab.ServiceHost.Unity {
+    public interface IFactoryMemberInjection {
+        void Visit(FactoryRegistrationBuilder builder);
+    }
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Implab.ServiceHost/Unity/IFactoryRegistration.cs	Thu May 03 09:59:44 2018 +0300
@@ -0,0 +1,7 @@
+using System.Collections.Generic;
+
+namespace Implab.ServiceHost.Unity {
+    public interface IFactoryRegistration : IRegistration {
+        IEnumerable<IFactoryMemberInjection> MemberInjections { get; }
+    }
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Implab.ServiceHost/Unity/IInjectionParameter.cs	Thu May 03 09:59:44 2018 +0300
@@ -0,0 +1,5 @@
+namespace Implab.ServiceHost.Unity {
+    public interface IInjectionParameter {
+        void Visit(InjectionParameterBuilder builder);
+    }
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Implab.ServiceHost/Unity/IInstanceRegistration.cs	Thu May 03 09:59:44 2018 +0300
@@ -0,0 +1,8 @@
+using System.Collections.Generic;
+
+namespace Implab.ServiceHost.Unity {
+    public interface IInstanceRegistration : IRegistration {
+
+        IEnumerable<IInjectionParameter> MemberInjections { get; }
+    }
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Implab.ServiceHost/Unity/IRegistration.cs	Thu May 03 09:59:44 2018 +0300
@@ -0,0 +1,12 @@
+using System;
+using Unity.Lifetime;
+
+namespace Implab.ServiceHost.Unity {
+    public interface IRegistration {
+        string Name { get; }
+        
+        Type GetRegistrationType(ContainerBuilder builder);
+
+        LifetimeManager GetLifetime(ContainerBuilder builder);
+    }
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Implab.ServiceHost/Unity/ITypeMemberInjection.cs	Thu May 03 09:59:44 2018 +0300
@@ -0,0 +1,6 @@
+namespace Implab.ServiceHost.Unity
+{
+    public interface ITypeMemberInjection {
+         void Visit(TypeRegistrationBuilder builder);
+    }
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Implab.ServiceHost/Unity/ITypeRegistration.cs	Thu May 03 09:59:44 2018 +0300
@@ -0,0 +1,10 @@
+using System;
+using System.Collections.Generic;
+
+namespace Implab.ServiceHost.Unity {
+    public interface ITypeRegistration : IRegistration {
+        Type GetImplementationType(ContainerBuilder builder);
+
+        IEnumerable<ITypeMemberInjection> MemberInjections { get; }
+    }
+}
\ No newline at end of file
--- a/Implab.ServiceHost/Unity/IncludeElement.cs	Sat Apr 28 18:48:09 2018 +0300
+++ b/Implab.ServiceHost/Unity/IncludeElement.cs	Thu May 03 09:59:44 2018 +0300
@@ -6,8 +6,8 @@
         [XmlAttribute("href")]
         public string Href { get; set; }
 
-        public override void Visit(ContainerBuilder context) {
-            context.Visit(this);
+        public override void Visit(ContainerBuilder builder) {
+            builder.Include(Href);
         }
     }
 }
\ No newline at end of file
--- a/Implab.ServiceHost/Unity/InjectionParameterElement.cs	Sat Apr 28 18:48:09 2018 +0300
+++ b/Implab.ServiceHost/Unity/InjectionParameterElement.cs	Thu May 03 09:59:44 2018 +0300
@@ -7,6 +7,6 @@
         [XmlAttribute("type")]
         public string TypeName { get; set; }
 
-        public abstract void Visit(InjectionValueBuilder builder);
+        public abstract void Visit(InjectionParameterBuilder builder);
     }
 }
\ No newline at end of file
--- a/Implab.ServiceHost/Unity/InjectionValueBuilder.cs	Sat Apr 28 18:48:09 2018 +0300
+++ b/Implab.ServiceHost/Unity/InjectionValueBuilder.cs	Thu May 03 09:59:44 2018 +0300
@@ -7,7 +7,7 @@
 
 namespace Implab.ServiceHost.Unity {
 
-    public class InjectionValueBuilder {
+    public class InjectionParameterBuilder {
 
         readonly TypeResolver m_resolver;
 
@@ -26,7 +26,7 @@
             }
         }
 
-        internal InjectionValueBuilder(TypeResolver resolver, Type defaultType) {
+        internal InjectionParameterBuilder(TypeResolver resolver, Type defaultType) {
             m_resolver = resolver;
             DefaultType = defaultType;
         }
@@ -37,11 +37,11 @@
                     throw new Exception("The type must be specified");
                 return DefaultType;
             }
-            return m_resolver.Resolve(typeSpec);
+            return m_resolver.Resolve(typeSpec, true);
         }
 
         public Type ResolveType(string typeSpec) {
-            return m_resolver.Resolve(typeSpec);
+            return m_resolver.Resolve(typeSpec, true);
         }
 
         public void SetValue(Type type, object value) {
@@ -75,13 +75,16 @@
 
             InjectionParameterValue[] injections = (arrayParameter.Items ?? new InjectionParameterElement[0])
                 .Select(x => {
-                    var builder = new InjectionValueBuilder(m_resolver, itemsType);
+                    var builder = new InjectionParameterBuilder(m_resolver, itemsType);
                     x.Visit(builder);
                     return builder.Injection;
                 })
                 .ToArray();
 
-            var array = itemsType.IsGenericParameter ? (object)new GenericResolvedArrayParameter(itemsType.Name, injections) : new ResolvedArrayParameter(itemsType, injections);
+            var array = itemsType.IsGenericParameter ?
+                (object)new GenericResolvedArrayParameter(itemsType.Name, injections) :
+                new ResolvedArrayParameter(itemsType, injections);
+
             ValueType = arrayType;
             Value = array;
         }
--- a/Implab.ServiceHost/Unity/InstanceRegistrationBuilder.cs	Sat Apr 28 18:48:09 2018 +0300
+++ b/Implab.ServiceHost/Unity/InstanceRegistrationBuilder.cs	Thu May 03 09:59:44 2018 +0300
@@ -4,10 +4,10 @@
 {
     public class InstanceRegistrationBuilder : RegistrationBuilder {
 
-        public InjectionValueBuilder ValueBuilder { get; private set; }
+        public InjectionParameterBuilder ValueBuilder { get; private set; }
 
         internal InstanceRegistrationBuilder(TypeResolver typeResolver, Type registrationType) : base(registrationType) {
-            ValueBuilder = new InjectionValueBuilder(typeResolver, registrationType);
+            ValueBuilder = new InjectionParameterBuilder(typeResolver, registrationType);
         }
     }
 }
\ No newline at end of file
--- a/Implab.ServiceHost/Unity/NamespaceElement.cs	Sat Apr 28 18:48:09 2018 +0300
+++ b/Implab.ServiceHost/Unity/NamespaceElement.cs	Thu May 03 09:59:44 2018 +0300
@@ -8,8 +8,8 @@
         [XmlAttribute("name")]
         public string Name { get; set; }
 
-        public override void Visit(ContainerBuilder context) {
-            context.Visit(this);
+        public override void Visit(ContainerBuilder builder) {
+            builder.AddNamespace(Name);
         }
     }
 }
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Implab.ServiceHost/Unity/NestedTypeReference.cs	Thu May 03 09:59:44 2018 +0300
@@ -0,0 +1,48 @@
+using System;
+using System.Text;
+
+namespace Implab.ServiceHost.Unity {
+    public class NestedTypeReference : TypeReference {
+
+        readonly string m_name;
+
+        readonly int m_genericParametersCount;
+
+        public TypeReference DeclaringType { get; private set; }
+
+        public override string Name {
+            get {
+                return m_name;
+            }
+        }
+
+        public override string Namespace {
+            get {
+                return DeclaringType.Namespace;
+            }
+        }
+
+        public override int GenericParametersCount {
+            get {
+                return m_genericParametersCount;
+            }
+        }
+
+        internal NestedTypeReference(TypeReference declaringType, string name, int parametersCount) {
+            DeclaringType = declaringType;
+            m_name = name;
+            m_genericParametersCount = parametersCount;
+        }
+
+        internal override void Visit(TypeResolutionContext visitor) {
+            visitor.Visit(this);
+        }
+
+        internal override void WriteTypeName(StringBuilder builder) {
+            builder
+                .Append(DeclaringType)
+                .Append('+')
+                .Append(Name);
+        }
+    }
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Implab.ServiceHost/Unity/ProvidesElement.cs	Thu May 03 09:59:44 2018 +0300
@@ -0,0 +1,11 @@
+using System.Xml.Serialization;
+
+namespace Implab.ServiceHost.Unity {
+    public class ProvidesElement {
+        [XmlAttribute("type")]
+        public string RegistrationType { get; set; }
+
+        [XmlAttribute("name")]
+        public string RegistrationName { get; set; }
+    }
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Implab.ServiceHost/Unity/RootTypeReference.cs	Thu May 03 09:59:44 2018 +0300
@@ -0,0 +1,36 @@
+using System;
+
+namespace Implab.ServiceHost.Unity
+{
+    public class RootTypeReference : TypeReference {
+        readonly string m_name;
+
+        readonly string m_namespace;
+
+        readonly int m_genericParametersCount;
+
+        public override string Name {
+            get { return m_name; }
+        }
+
+        public override string Namespace {
+            get { return m_namespace; }
+        }
+
+        public override int GenericParametersCount {
+            get { return m_genericParametersCount; }
+        }
+
+        internal RootTypeReference(string ns, string name, int genericParameters) {
+            m_name = name;
+            m_genericParametersCount = genericParameters;
+            m_namespace = ns;
+        }
+
+        internal override void Visit(TypeResolutionContext visitor) {
+            visitor.Visit(this);
+        }
+
+
+    }
+}
\ No newline at end of file
--- a/Implab.ServiceHost/Unity/SerializedParameterElement.cs	Sat Apr 28 18:48:09 2018 +0300
+++ b/Implab.ServiceHost/Unity/SerializedParameterElement.cs	Thu May 03 09:59:44 2018 +0300
@@ -21,7 +21,7 @@
             throw new Exception("No content found, expected XML document");
         }
 
-        public override void Visit(InjectionValueBuilder builder) {
+        public override void Visit(InjectionParameterBuilder builder) {
             var type = builder.ResolveInjectedValueType(TypeName);
 
             var serializer = new XmlSerializer(type);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Implab.ServiceHost/Unity/SpecializedTypeReference.cs	Thu May 03 09:59:44 2018 +0300
@@ -0,0 +1,52 @@
+using System;
+using System.Linq;
+using System.Text;
+
+namespace Implab.ServiceHost.Unity {
+    public class SpecializedTypeReference : TypeReference {
+        public override string Name {
+            get {
+                return GenericType.Name;
+            }
+        }
+
+        public override string Namespace {
+            get {
+                return GenericType.Namespace;
+            }
+        }
+
+        public override int GenericParametersCount {
+            get {
+                return GenericParameters.Length;
+            }
+        }
+
+        public TypeReference GenericType { get; private set; }
+
+        public TypeReference[] GenericParameters { get; private set; }
+
+        internal SpecializedTypeReference(TypeReference genericType, TypeReference[] genericParameters) {
+            GenericType = genericType;
+            GenericParameters = genericParameters;
+        }
+
+        internal override void Visit(TypeResolutionContext visitor) {
+            visitor.Visit(this);
+        }
+
+        internal override void WriteTypeName(StringBuilder builder) {
+            GenericType.WriteTypeName(builder);
+        }
+
+        internal override void WriteTypeParams(StringBuilder builder) {
+            builder.Append('{');
+            for (var i = 0; i < GenericParameters.Length; i++) {
+                if (i > 0)
+                    builder.Append(',');
+                builder.Append(GenericParameters[i]);
+            }
+            builder.Append('}');
+        }
+    }
+}
\ No newline at end of file
--- a/Implab.ServiceHost/Unity/TypeReference.cs	Sat Apr 28 18:48:09 2018 +0300
+++ b/Implab.ServiceHost/Unity/TypeReference.cs	Thu May 03 09:59:44 2018 +0300
@@ -3,56 +3,180 @@
 using System.Text;
 
 namespace Implab.ServiceHost.Unity {
-    public class TypeReference {
-        public string TypeName { get; set; }
-
-        public string Namespace { get; set; }
-
-        public TypeReference[] GenericParameters { get; set; }
-
-        public bool IsArray { get; set; }
+    /// <summary>
+    /// Ссылка на тип, является абстрактной записью имени CLR типа.
+    /// </summary>
+    /// <remarks>
+    /// Ссылка на тип содержит сокращенную информацию о типе и для ее интерпретации
+    /// требуется некоторый контекст, который позволит превратить ее в полноценный
+    /// <see cref="Type"/>. Ссылки на тип позволяют записать:
+    /// <list>
+    ///     <item><description>общие типы, их специализации</description></item>
+    ///     <item><description>вложенные типы</description></item>
+    ///     <item><description>массивы</description></item>
+    /// </list>
+    /// <para>
+    /// Для получения из ссылки на тип конкретного CLR типа используется <see cref="TypeResolver.Resolve(TypeReference, bool)"/>.
+    /// </para>
+    /// <para>
+    /// Ссылку на тип можно создать либо програмно при помощи методов <see cref="Create(string, string, int)"/>,
+    /// <see cref="Create(string, int)"/>, <see cref="MakeArrayType(int)"/>, <see cref="MakeGenericType(TypeReference[])"/>,
+    /// либо разобрав строку со спецификацией при помощи метода <see cref="Parse(string)"/>.
+    /// </para>
+    /// <para>
+    /// Спецификация ссыдки на тип имеет следующий вид <c>Name.Space.MyType+Nested{String}[][]</c>, где:
+    /// <list type="table">
+    ///     <item>
+    ///         <term><c>.</c></term>
+    ///         <description>Разделяет элементы пространства имен</description>
+    ///     <item>
+    ///     <item>
+    ///         <term><c>+</c></term>
+    ///         <description>Разделяет вложенные типы</description>
+    ///     <item>
+    ///     <item>
+    ///         <term><c>[]</c>, <c>[,,,]</c></term>
+    ///         <description>Указывает на то, что тип является массивом, также указывается его размерность</description>
+    ///     <item>
+    ///     <item>
+    ///         <term><c>{}</c>, <c>{,,}</c>, <c>{Int32,String}</c></term>
+    ///         <description>Указывает на то, что тип является общим, также 
+    ///         указывается количество параметров, либо конкретные типы для
+    ///         специализации</description>
+    ///     <item>
+    /// </list>
+    /// </para>
+    /// </remarks>
+    public abstract class TypeReference {
 
-        public bool IsOpenGeneric {
+        /// <summary>
+        /// Имя типа без дополнительных элементов, указывающих на то, что он общий или массив.
+        /// </summary>
+        /// <remarks>
+        /// Для массивов это имя его элементов.
+        /// </remarks>
+        public abstract string Name { get; }
+
+        /// <summary>
+        /// Пространство имен в котором нахожится тип.
+        /// </summary>
+        /// <remarks>
+        /// Для вложенных типов это пространтство имен типа самого верхнего уровня,
+        /// для массивов - пространство имен его элементов.
+        /// </remarks>
+        public abstract string Namespace { get; }
+
+        /// <summary>
+        /// Количество параметров общего типа.
+        /// </summary>
+        /// <remarks>
+        /// <para>
+        /// Вложенные типы неявно получают параметры от типов в которых они объявлены,
+        /// данное свойство это не учитывает, возвращается только количество собственных
+        /// параметров.
+        /// </para>
+        /// <para>
+        /// Данное свойство используется для получения CRL имени типа.
+        /// </para>
+        /// </remarks>
+        public abstract int GenericParametersCount { get; }
+
+        public virtual string ClrName {
             get {
-                return GenericParameters!=null && GenericParameters.Contains(null);
-            }
-        }
-
-        public bool IsGeneric {
-            get {
-                return GenericParameters != null && GenericParameters.Length > 0;
+                return GenericParametersCount != 0 ? $"{Name}`{GenericParametersCount}" : Name;
             }
         }
 
+        /// <summary>
+        /// Создает ссылку на специализацию текущего типа.
+        /// </summary>
+        /// <param name="genericParameters">Ссылки на типы, которые будут использоваться для специализации текущего типа.</param>
+        /// <returns>Специализация данного типа.</returns>
+        public virtual SpecializedTypeReference MakeGenericType(TypeReference[] genericParameters) {
+            if (GenericParametersCount == 0)
+                throw new InvalidOperationException("Can't specialize a non-geneic type");
+
+            if (genericParameters == null || GenericParametersCount != genericParameters.Length)
+                throw new InvalidOperationException("Generic parameters count mismatch");
+
+            return new SpecializedTypeReference(this, genericParameters);
+        }
+
+        /// <summary>
+        /// Создает ссылку на тип массива указанной размерности, элементами которого являются экземпаляры даннго типа.
+        /// </summary>
+        /// <param name="rank">Размерность, если размерность <c>1</c> создается вектор (<see cref="Type.MakeArrayType()"/>).</param>
+        /// <returns>Ссылка на тип массива</returns>
+        public ArrayTypeReference MakeArrayType(int rank) {
+            Safe.ArgumentInRange(rank > 0, nameof(rank));
+
+            return new ArrayTypeReference(this, rank);
+        }
+
+        /// <summary>
+        /// Создает ссылку на вложенный тип.
+        /// </summary>
+        /// <param name="name">Имя типа</param>
+        /// <param name="genericParameters">Количество параметров, если это общий тип, иначе 0.</param>
+        /// <returns>Ссылка на вложенный тип.</returns>
+        public TypeReference Create(string name, int genericParameters) {
+            Safe.ArgumentNotEmpty(name, nameof(name));
+            Safe.ArgumentInRange(genericParameters >= 0, nameof(genericParameters));
+
+            return new NestedTypeReference(this, name, genericParameters);
+        }
+
+        /// <summary>
+        /// Возвращает строковое представление ссылки на тип.
+        /// </summary>
+        /// <returns></returns>
         public override string ToString() {
             var builder = new StringBuilder();
-
-            if (!string.IsNullOrEmpty(Namespace)) {
-                builder.Append(Namespace);
-                builder.Append('.');
-            }
-
-            if (!string.IsNullOrEmpty(TypeName)) {
-                builder.Append(TypeName);
-            } else {
-                builder.Append("__unnamed__");
-            }
-
-            if (GenericParameters != null && GenericParameters.Length > 0) {
-                builder.Append('{');
-                for(var i = 0; i < GenericParameters.Length; i++) {
-                    if (i > 0)
-                        builder.Append(',');
-                    builder.Append(GenericParameters[i]);
-                }
-                builder.Append('}');
-            }
-
+            WriteTypeName(builder);
+            WriteTypeParams(builder);
             return builder.ToString();
         }
-        public static TypeReference Parse(string text) {
-            var parser = new TypeReferenceParser(text);
+
+        internal virtual void WriteTypeName(StringBuilder builder) {
+            if (!string.IsNullOrEmpty(Namespace))
+                builder
+                    .Append(Namespace)
+                    .Append('.');
+            builder.Append(Name);
+        }
+
+        internal virtual void WriteTypeParams(StringBuilder builder) {
+            if (GenericParametersCount > 0)
+                builder
+                    .Append('{')
+                    .Append(',', GenericParametersCount-1)
+                    .Append('}');
+        }
+
+        internal abstract void Visit(TypeResolutionContext visitor);
+
+        /// <summary>
+        /// Создает ссылку на тип.
+        /// </summary>
+        /// <param name="ns">Пространство имен, либо его фрагмент.</param>
+        /// <param name="name">Имя типа без указания на количество параметров, либо на то, что это массив.</param>
+        /// <param name="genericParameters">Количество параметров типа, если это общий тип, иначе 0.</param>
+        /// <returns>Ссылка на тип.</returns>
+        public static TypeReference Create(string ns, string name, int genericParameters) {
+            Safe.ArgumentNotEmpty(name, nameof(name));
+            Safe.ArgumentInRange(genericParameters >= 0, nameof(genericParameters));
+            return new RootTypeReference(ns, name, genericParameters);
+        }
+
+        /// <summary>
+        /// Разирает строковую запись ссылки на тип.
+        /// </summary>
+        /// <param name="typeSpec">Строковая запись ссылки на тип, например <c>Dictionary{String,String}</c></param>
+        /// <returns>Ссылка на тип.</returns>
+        public static TypeReference Parse(string typeSpec) {
+            var parser = new TypeReferenceParser(typeSpec);
             return parser.Parse();
         }
+
     }
 }
\ No newline at end of file
--- a/Implab.ServiceHost/Unity/TypeReferenceParser.cs	Sat Apr 28 18:48:09 2018 +0300
+++ b/Implab.ServiceHost/Unity/TypeReferenceParser.cs	Thu May 03 09:59:44 2018 +0300
@@ -1,5 +1,6 @@
 using System;
 using System.Collections.Generic;
+using System.Linq;
 using System.Text.RegularExpressions;
 
 namespace Implab.ServiceHost.Unity {
@@ -21,10 +22,12 @@
 
             CloseArray,
 
+            Plus,
+
             Eof
         }
 
-        readonly Regex _tokens = new Regex(@"([\w\+]+)|\s*([\.{},\[\]])\s*");
+        readonly Regex _tokens = new Regex(@"\G(?:([\w]+)|\s*([\+\.{},\[\]])\s*)", RegexOptions.Compiled);
 
         TokenType m_token;
 
@@ -83,6 +86,9 @@
                         case "]":
                             m_token = TokenType.CloseArray;
                             break;
+                        case "+":
+                            m_token = TokenType.Plus;
+                            break;
                     }
                 }
                 return true;
@@ -97,7 +103,7 @@
             return result;
         }
 
-        string[] ReadTypeName() {
+        string[] ReadQTypeName() {
             var parts = new List<string>();
 
             string current = null;
@@ -129,31 +135,95 @@
             return parts.ToArray();
         }
 
+        string ReadNQTypeName() {
+            ReadToken();
+            if (Token != TokenType.Word)
+                ThrowUnexpectedToken();
+            return TokenValue;
+        }
+
         TypeReference ReadTypeReference() {
 
-            var parts = ReadTypeName();
+            var parts = ReadQTypeName();
             if (parts == null)
                 return null;
 
-            var typeReference = new TypeReference {
-                Namespace = string.Join(".", parts, 0, parts.Length - 1),
-                TypeName = parts[parts.Length - 1]
-            };
+            var genericParameters = ReadGenericParams();
+
+            var typeReference = TypeReference.Create(
+                string.Join(".", parts, 0, parts.Length - 1),
+                parts[parts.Length - 1],
+                genericParameters.Length
+            );
+
+            if (genericParameters.Length > 0 && genericParameters.All(x => x != null))
+                typeReference = typeReference.MakeGenericType(genericParameters);
+
+            typeReference = ReadArraySpec(typeReference);
+
+            if(Token == TokenType.Plus)
+                return ReadNestedType(typeReference);
+
+            return typeReference;
+        }
+
+        TypeReference ReadNestedType(TypeReference declaringType) {
+            var name = ReadNQTypeName();
+            if(string.IsNullOrEmpty(name))
+                throw new FormatException("Nested type name can't be empty");
+            ReadToken();
+            
+            var genericParameters = ReadGenericParams();
+
+            var typeReference = declaringType.Create(
+                name,
+                genericParameters.Length
+            );
 
-            switch (Token) {
-                case TokenType.OpenList:
-                    typeReference.GenericParameters = ReadTypeReferenceList();
-                    if (Token != TokenType.CloseList)
-                        ThrowUnexpectedToken();
-                    ReadToken();
-                    break;
+            if (genericParameters.Length > 0 && genericParameters.All(x => x != null))
+                typeReference = typeReference.MakeGenericType(genericParameters);
+
+            typeReference = ReadArraySpec(typeReference);
+
+            if(Token == TokenType.Plus)
+                return ReadNestedType(typeReference);
+
+            return typeReference;
+        }
+
+        TypeReference[] ReadGenericParams() {
+            if (Token == TokenType.OpenList) {
+                var genericParameters = ReadTypeReferenceList();
+                if (Token != TokenType.CloseList)
+                    ThrowUnexpectedToken();
+                ReadToken();
+
+                return genericParameters;
+            }
+
+            return Array.Empty<TypeReference>();
+        }
+
+        TypeReference ReadArraySpec(TypeReference typeReference) {
+            while (Token == TokenType.OpenArray) {
+                var rank = CountRank();
+                if (Token != TokenType.CloseArray)
+                    ThrowUnexpectedToken();
+                
+                typeReference = typeReference.MakeArrayType(rank);
+                
+                ReadToken();
             }
 
             return typeReference;
         }
 
-        int CountDimentions() {
-            return 0;
+        int CountRank() {
+            int rank = 0;
+            do {
+                rank++;
+            } while(ReadToken() && Token == TokenType.Comma);
+            return rank;
         }
 
         TypeReference[] ReadTypeReferenceList() {
--- a/Implab.ServiceHost/Unity/TypeRegistrationBuilder.cs	Sat Apr 28 18:48:09 2018 +0300
+++ b/Implab.ServiceHost/Unity/TypeRegistrationBuilder.cs	Thu May 03 09:59:44 2018 +0300
@@ -37,7 +37,7 @@
 
             var parameters = constructorInjection.Parameters?
                 .Select(x => {
-                    var valueBuilder = new InjectionValueBuilder(m_resolver, null);
+                    var valueBuilder = new InjectionParameterBuilder(m_resolver, null);
                     x.Visit(valueBuilder);
                     return valueBuilder.Injection;
                 })
@@ -48,11 +48,9 @@
         }
 
         internal void Visit(MethodInjectionElement methodInjection) {
-            var valueContext = new InjectionValueBuilder(m_resolver, null);
-
             var parameters = methodInjection.Parameters?
                 .Select(x => {
-                    var valueBuilder = new InjectionValueBuilder(m_resolver, null);
+                    var valueBuilder = new InjectionParameterBuilder(m_resolver, null);
                     x.Visit(valueBuilder);
                     return valueBuilder.Injection;
                 })
@@ -66,8 +64,8 @@
             if (propertyInjection.Value == null)
                 throw new Exception($"A value value must be specified for the property '{propertyInjection.Name}'");
 
-            var propertyType = RegistrationType.GetProperty(propertyInjection.Name)?.PropertyType;
-            var valueContext = new InjectionValueBuilder(m_resolver, propertyType);
+            var propertyType = ImplementationType.GetProperty(propertyInjection.Name)?.PropertyType;
+            var valueContext = new InjectionParameterBuilder(m_resolver, propertyType);
 
             propertyInjection.Value.Visit(valueContext);
             var injection = new InjectionProperty(propertyInjection.Name, valueContext.Injection);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Implab.ServiceHost/Unity/TypeResolutionContext.cs	Thu May 03 09:59:44 2018 +0300
@@ -0,0 +1,75 @@
+using System;
+using System.Collections.Generic;
+using Implab.Diagnostics;
+
+namespace Implab.ServiceHost.Unity {
+    using static Trace<TypeResolver>;
+
+    /// <summary>
+    /// Позволяет обойти вложенные типы и собрать цеочку из типов и параметров генериков, которые они предлагают
+    /// </summary>
+    internal class TypeResolutionContext {
+        readonly TypeResolver m_resolver;
+
+
+        readonly List<Type> m_genericParameters = new List<Type>();
+
+        public IEnumerable<Type> GenericParameters { get { return m_genericParameters; } }
+
+        public Type ResolvedType { get; private set; }
+
+
+        public int ArrayRank { get; private set; }
+
+
+        public bool ThrowOnFail { get; private set; }
+
+        public TypeResolutionContext(TypeResolver resolver, bool throwOnFail) {
+            m_resolver = resolver;
+            ThrowOnFail = throwOnFail;
+        }
+
+        public Type MakeType() {
+            return m_genericParameters.Count > 0 ?
+                ResolvedType?.MakeGenericType(m_genericParameters.ToArray()) :
+                ResolvedType;
+        }
+
+        public void Visit(SpecializedTypeReference typeReference) {
+            typeReference.GenericType.Visit(this);
+
+            if (ResolvedType != null) {
+                foreach (var genericParamRef in typeReference.GenericParameters) {
+                    var context = new TypeResolutionContext(m_resolver, ThrowOnFail);
+                    genericParamRef.Visit(context);
+                    m_genericParameters.Add(context.MakeType());
+                }
+            }
+        }
+
+        public void Visit(NestedTypeReference typeReference) {
+            typeReference.DeclaringType.Visit(this);
+            if (ResolvedType != null)
+                ResolvedType = ResolvedType?.GetNestedType(typeReference.ClrName) ?? Failed(typeReference);
+        }
+
+        public void Visit(RootTypeReference typeReference) {
+            ResolvedType = m_resolver.Resolve(typeReference.Namespace, typeReference.ClrName) ?? Failed(typeReference);
+        }
+
+        public void Visit(ArrayTypeReference typeReference) {
+            var context = new TypeResolutionContext(m_resolver, ThrowOnFail);
+            typeReference.ItemsType.Visit(context);
+            ResolvedType = typeReference.Rank == 1 ?
+                context.MakeType()?.MakeArrayType() :
+                context.MakeType()?.MakeArrayType(typeReference.Rank);
+        }
+
+        Type Failed(TypeReference reference) {
+            Log($"Falied to resolve {reference}");
+            if (ThrowOnFail)
+                throw new Exception($"Failed to resolve {reference}");
+            return null;
+        }
+    }
+}
\ No newline at end of file
--- a/Implab.ServiceHost/Unity/TypeResolver.cs	Sat Apr 28 18:48:09 2018 +0300
+++ b/Implab.ServiceHost/Unity/TypeResolver.cs	Thu May 03 09:59:44 2018 +0300
@@ -6,6 +6,7 @@
 using Implab.Diagnostics;
 
 namespace Implab.ServiceHost.Unity {
+    using System.Diagnostics;
     using static Trace<TypeResolver>;
     public class TypeResolver {
         readonly Dictionary<string, Type> m_cache = new Dictionary<string, Type>();
@@ -13,12 +14,28 @@
         Regex _nsRx = new Regex(@"^\w+(\.\w+)*$", RegexOptions.Compiled);
         readonly LinkedList<string> m_namespases = new LinkedList<string>();
 
+        internal Type Resolve(string ns, string typeName) {
+            var fullName = string.IsNullOrEmpty(ns) ? typeName : $"{ns}.{typeName}";
+
+            return ProbeInNamespaces(fullName);
+        }
+
+        public Type Resolve(TypeReference typeReference, bool throwOnFail) {
+            var context = new TypeResolutionContext(this, throwOnFail);
+            typeReference.Visit(context);
+            return context.MakeType();
+        }
+
+        public Type Resolve(string typeSpec, bool throwOnFail) {
+            var typeReference = TypeReference.Parse(typeSpec);
+            return Resolve(typeReference, throwOnFail);
+        }
+
         LinkedListNode<string> m_insertAt;
 
         readonly TypeResolver m_parent;
 
         public TypeResolver() : this(null) {
-
         }
 
         public TypeResolver(TypeResolver parent) {
@@ -42,63 +59,31 @@
             m_cache[typeName] = type;
         }
 
-        public Type Resolve(TypeReference reference) {
-            var args = reference.IsGeneric && !reference.IsOpenGeneric ? reference.GenericParameters?.Select(Resolve).ToArray() : null;
-            var argc = reference.IsGeneric ? reference.GenericParameters.Length : 0;
+        Type ProbeInNamespaces(string localName) {
 
             Type resolved;
-            if (!m_cache.TryGetValue(reference.ToString(), out resolved)) {
-                resolved = ResolveInternal(reference, args, argc);
-                if (resolved == null)
-                    throw new Exception($"Failed to resolve {reference}");
-                m_cache[reference.ToString()] = resolved;
+            if (!m_cache.TryGetValue(localName, out resolved)) {
+                foreach (var ns in m_namespases) {
+                    var typeName = string.IsNullOrEmpty(ns) ? localName : $"{ns}.{localName}";
+                    resolved = Probe(typeName);
+                    if (resolved != null) {
+                        Log($"Probe '{localName}' -> '{resolved.FullName}'");
+                        break;
+                    }
+                }
+
+                if (resolved == null && m_parent != null)
+                    resolved = m_parent.ProbeInNamespaces(localName);
+
+                if(resolved == null)
+                    Log($"Probe '{localName}' failed");
+
+                m_cache[localName] = resolved;
             }
 
             return resolved;
         }
 
-        public Type Resolve(string typeSpec) {
-            return Resolve(TypeReference.Parse(typeSpec));
-        }
-
-        Type ResolveInternal(TypeReference reference, Type[] args, int argc) {
-            var resolved = ProbeInNamespaces(
-                String.Join(".", new[] { reference.Namespace, reference.TypeName }.Where(x => !string.IsNullOrEmpty(x))),
-                args,
-                argc,
-                reference.IsArray,
-                reference.ToString()
-            );
-
-            if (resolved == null && m_parent != null)
-                resolved = m_parent.ResolveInternal(reference, args, argc);
-
-            return resolved;
-        }
-
-        public Type ProbeInNamespaces(string localName, Type[] args, int argc, bool isArray, string referenceName) {
-            foreach (var ns in m_namespases) {
-                var typeName = FormatName(new[] { ns, localName }, argc);
-
-                var resolved = Probe(typeName);
-                if (resolved != null) {
-                    if (args != null && args.Length > 0) {
-                        resolved = resolved.MakeGenericType(args);
-                    }
-
-                    if (isArray)
-                        resolved = resolved.MakeArrayType();
-
-                    Log("Probe succeed {0} in '{1}': {2} -> {3}", referenceName, ns, typeName, resolved.AssemblyQualifiedName);
-                    return resolved;
-                } else {
-                    Log("Probe failed {0} in '{1}': {2}", referenceName, ns, typeName);
-                }
-            }
-
-            return null;
-        }
-
         Type Probe(string typeName) {
             var assemblies = AppDomain.CurrentDomain.GetAssemblies();
 
@@ -109,17 +94,5 @@
             }
             return null;
         }
-
-        string FormatName(string[] parts, int argc) {
-            var builder = new StringBuilder();
-
-            builder.Append(String.Join(".", parts.Where(x => !string.IsNullOrEmpty(x))));
-            if (argc > 0) {
-                builder.Append('`');
-                builder.Append(argc);
-            }
-
-            return builder.ToString();
-        }
     }
 }
\ No newline at end of file
--- a/Implab.ServiceHost/Unity/ValueParameterElement.cs	Sat Apr 28 18:48:09 2018 +0300
+++ b/Implab.ServiceHost/Unity/ValueParameterElement.cs	Thu May 03 09:59:44 2018 +0300
@@ -13,7 +13,7 @@
             return string.IsNullOrEmpty(Value) ? Text : Value;
         }
 
-        public override void Visit(InjectionValueBuilder builder) {
+        public override void Visit(InjectionParameterBuilder builder) {
             var type = builder.ResolveInjectedValueType(TypeName);
             builder.SetValue(type, TypeDescriptor.GetConverter(type).ConvertFromString(GetTextValue()));
         }
--- a/Implab/Xml/SerializationHelpers.cs	Sat Apr 28 18:48:09 2018 +0300
+++ b/Implab/Xml/SerializationHelpers.cs	Thu May 03 09:59:44 2018 +0300
@@ -12,17 +12,17 @@
 namespace Implab.Xml {
     public static class SerializationHelpers {
         public static string SerializeAsString<T>(T obj) {
-            return SerializersPool<T>.Instance.SerializeAsString(obj);
+            return XmlDefaultSerializer<T>.Instance.SerializeAsString(obj);
         }
 
         public static void Serialize<T>(XmlWriter writer, T obj) {
-            SerializersPool<T>.Instance.Serialize(writer, obj);
+            XmlDefaultSerializer<T>.Instance.Serialize(writer, obj);
         }
 
         public static XmlDocument SerializeAsXmlDocument<T>(T obj) {
             var doc = new XmlDocument();
             using (var writer = doc.CreateNavigator().AppendChild()) {
-                SerializersPool<T>.Instance.Serialize(writer, obj);
+                XmlDefaultSerializer<T>.Instance.Serialize(writer, obj);
             }
             return doc;
         }
@@ -30,38 +30,35 @@
         public static XDocument SerializeAsXDocument<T>(T obj) {
             var doc = new XDocument();
             using (var writer = doc.CreateWriter()) {
-                SerializersPool<T>.Instance.Serialize(writer, obj);
+                XmlDefaultSerializer<T>.Instance.Serialize(writer, obj);
             }
             return doc;
         }
 
         public static void SerializeToFile<T>(string file, T obj) {
-            using (var writer = File.CreateText(file))
-                SerializersPool<T>.Instance.Serialize(writer, obj);
+            XmlDefaultSerializer<T>.Instance.SerializeToFile(obj, file);
         }
 
         public static void SerializeToElementChild<T>(XmlElement element, T obj) {
-            using(var writer = element.CreateNavigator().AppendChild())
-                SerializersPool<T>.Instance.Serialize(writer, obj);
+            XmlDefaultSerializer<T>.Instance.Serialize(obj, element);
         }
 
         public static T Deserialize<T>(XmlReader reader) {
-            return SerializersPool<T>.Instance.Deserialize(reader);
+            return (T)XmlDefaultSerializer<T>.Instance.Deserialize(reader);
         }
 
         public static T DeserializeFromFile<T>(string file) {
-            using(var reader = XmlReader.Create(File.OpenText(file)))
-                return Deserialize<T>(reader);
+            return (T)XmlDefaultSerializer<T>.Instance.DeserializeFromFile(file);
         }
 
         public static T DeserializeFromString<T>(string data) {
-            return SerializersPool<T>.Instance.DeserializeFromString(data);
+            return (T)XmlDefaultSerializer<T>.Instance.DeserializeFromString(data);
         }
 
         public static T DeserializeFromXmlNode<T>(XmlNode node) {
             Safe.ArgumentNotNull(node, nameof(node));
             using (var reader = node.CreateNavigator().ReadSubtree())
-                return SerializersPool<T>.Instance.Deserialize(reader);
+                return (T)XmlDefaultSerializer<T>.Instance.Deserialize(reader);
         }
 
         public static T DeserializeJson<T>(TextReader textReader) {
@@ -71,12 +68,12 @@
                 FlattenArrays = true
             };
 
-            using(var reader = JsonXmlReader.CreateJsonXmlReader(textReader, options))
+            using (var reader = JsonXmlReader.CreateJsonXmlReader(textReader, options))
                 return Deserialize<T>(reader);
         }
 
         public static T DeserializeJsonFromString<T>(string data) {
-            using(var reader = new StringReader(data)) {
+            using (var reader = new StringReader(data)) {
                 return DeserializeJson<T>(reader);
             }
         }
@@ -87,7 +84,7 @@
         }
 
         public static string SerializeJsonAsString<T>(T obj) {
-            using(var writer = new StringWriter()) {
+            using (var writer = new StringWriter()) {
                 SerializeJson(writer, obj);
                 return writer.ToString();
             }
--- a/Implab/Xml/SerializersPool.cs	Sat Apr 28 18:48:09 2018 +0300
+++ b/Implab/Xml/SerializersPool.cs	Thu May 03 09:59:44 2018 +0300
@@ -9,6 +9,7 @@
 using System.Xml.Serialization;
 
 namespace Implab.Xml {
+    [Obsolete("this class will be removed, use XmlDefaultSerializer")]
     public class SerializersPool<T> : ObjectPool<XmlSerializer> {
 
         static readonly SerializersPool<T> _instance = new SerializersPool<T>();
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Implab/Xml/XmlDefaultSerializer.cs	Thu May 03 09:59:44 2018 +0300
@@ -0,0 +1,14 @@
+using System.Xml.Serialization;
+using Implab.Components;
+
+namespace Implab.Xml {
+    /// <summary>
+    /// This class used to get default serializer for the specified type <typeparamref name="T"/>.
+    /// </summary>
+    /// <typeparam name="T">The type used to create <see cref="XmlSerializer"/></typeparam>
+    public static class XmlDefaultSerializer<T> {
+        static readonly LazyAndWeak<XmlSerializer> m_instance = new LazyAndWeak<XmlSerializer>(() => new XmlSerializer(typeof(T)));
+
+        public static XmlSerializer Instance { get { return m_instance.Value; } }
+    }
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Implab/Xml/XmlSerializerExtensions.cs	Thu May 03 09:59:44 2018 +0300
@@ -0,0 +1,89 @@
+using System.IO;
+using System.Text;
+using System.Xml;
+using System.Xml.Linq;
+using System.Xml.Serialization;
+
+namespace Implab.Xml {
+    public static class XmlSerializerExtensions {
+
+        public static void Serialize(this XmlSerializer that, object obj, XmlElement element) {
+            Safe.ArgumentNotNull(that, nameof(that));
+            using (var writer = element.CreateNavigator().AppendChild())
+                that.Serialize(writer, obj);
+        }
+
+        public static void Serialize(this XmlSerializer that, object obj, XElement element) {
+            Safe.ArgumentNotNull(that, nameof(that));
+            using (var writer = element.CreateWriter())
+                that.Serialize(writer, obj);
+        }
+
+        public static XDocument SerializeAsXDocumnet(this XmlSerializer that, object obj) {
+            Safe.ArgumentNotNull(that, nameof(that));
+            var doc = new XDocument();
+            using (var writer = doc.CreateWriter()) {
+                that.Serialize(writer, obj);
+            }
+            return doc;
+        }
+
+        public static XmlDocument SerializeAsXmlDocument(this XmlSerializer that, object obj) {
+            Safe.ArgumentNotNull(that, nameof(that));
+            var doc = new XmlDocument();
+            using (var writer = doc.CreateNavigator().AppendChild()) {
+                that.Serialize(writer, obj);
+            }
+            return doc;
+        }
+        public static string SerializeAsString(this XmlSerializer that, object obj) {
+            Safe.ArgumentNotNull(that, nameof(that));
+            using (var writer = new StringWriter()) {
+                that.Serialize(writer, obj);
+                return writer.ToString();
+            }
+        }
+
+        public static void SerializeToFile(this XmlSerializer that, object obj, string file, Encoding encoding) {
+            Safe.ArgumentNotNull(that, nameof(that));
+            using (var writer = new StreamWriter(File.Create(file),encoding))
+                that.Serialize(writer, obj);
+        }
+
+        public static void SerializeToFile(this XmlSerializer that, object obj, string file) {
+            SerializeToFile(that, obj, file, Encoding.UTF8);
+        }
+
+        public static object Deserialize(this XmlSerializer that, XmlElement element) {
+            Safe.ArgumentNotNull(that, nameof(that));
+            Safe.ArgumentNotNull(element, nameof(element));
+
+            using (var reader = element.CreateNavigator().ReadSubtree())
+                return that.Deserialize(reader);
+        }
+
+        public static object Deserialize(this XmlSerializer that, XElement element) {
+            Safe.ArgumentNotNull(that, nameof(that));
+            Safe.ArgumentNotNull(element, nameof(element));
+
+            using (var reader = element.CreateReader())
+                return that.Deserialize(reader);
+        }
+
+        public static object DeserializeFromString(this XmlSerializer that, string text) {
+            Safe.ArgumentNotNull(that, nameof(that));
+
+            using(var reader = new StringReader(text))
+                return that.Deserialize(reader);
+        }
+
+        public static object DeserializeFromFile(this XmlSerializer that, string file) {
+            Safe.ArgumentNotNull(that, nameof(that));
+
+            using(var reader = File.OpenRead(file))
+                return that.Deserialize(reader);
+        }
+        
+
+    }
+}
\ No newline at end of file