changeset 270:ade80d94dfb5 v3

Working on Unity container xml configuration
author cin
date Wed, 25 Apr 2018 04:44:40 +0300
parents ff581cff7003
children d4d437ec4483
files Implab.Playground/Program.cs Implab.Playground/data/sample.xml Implab.ServiceHost/Unity/AbstractInjectionElement.cs Implab.ServiceHost/Unity/AbstractInjectorElement.cs Implab.ServiceHost/Unity/AbstractRegistration.cs Implab.ServiceHost/Unity/AssemblyElement.cs Implab.ServiceHost/Unity/ConfigurationContext.cs Implab.ServiceHost/Unity/ConstructorInjectionElement.cs Implab.ServiceHost/Unity/ConstructorInjectorElement.cs Implab.ServiceHost/Unity/ContainerElement.cs Implab.ServiceHost/Unity/DefaultParameterElement.cs Implab.ServiceHost/Unity/DependencyParameterElement.cs Implab.ServiceHost/Unity/IncludeElement.cs Implab.ServiceHost/Unity/InjectionParameterElement.cs Implab.ServiceHost/Unity/MethodInjectionElement.cs Implab.ServiceHost/Unity/MethodInjectorElement.cs Implab.ServiceHost/Unity/MethodInjectorParameter.cs Implab.ServiceHost/Unity/NamespaceElement.cs Implab.ServiceHost/Unity/PropertyInjectionElement.cs Implab.ServiceHost/Unity/PropertyInjectorElement.cs Implab.ServiceHost/Unity/RegisterElement.cs Implab.ServiceHost/Unity/SerializedParameterElement.cs Implab.ServiceHost/Unity/TypeResolver.cs Implab.ServiceHost/Unity/ValueParameterElement.cs
diffstat 24 files changed, 285 insertions(+), 118 deletions(-) [+]
line wrap: on
line diff
--- a/Implab.Playground/Program.cs	Tue Apr 24 01:46:02 2018 +0300
+++ b/Implab.Playground/Program.cs	Wed Apr 25 04:44:40 2018 +0300
@@ -14,6 +14,8 @@
 
         }
 
+        public string Name { get; set; }
+
         public int IntValue { get; set; }
 
         public string StringValue { get; set; }
@@ -30,6 +32,10 @@
         }
 
         public T Instance { get; set; }
+
+        public void SetInstance(T value) {
+            Instance = value;
+        }
     }
 
     public class Program {
@@ -39,7 +45,7 @@
 
             var conf = SerializationHelpers.DeserializeFromFile<ContainerElement>("data/sample.xml");
 
-            Console.WriteLine($"Registrations: {conf.Registrations.Count}");
+            Console.WriteLine($"Registrations: {conf.Items.Count}");
 
         }
 
--- a/Implab.Playground/data/sample.xml	Tue Apr 24 01:46:02 2018 +0300
+++ b/Implab.Playground/data/sample.xml	Wed Apr 25 04:44:40 2018 +0300
@@ -1,10 +1,38 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <container xmlns="http://implab.org/schemas/servicehost/unity.v1.xsd">
+    <namespace name="Implab.Playground"/>
+
     <!-- foo1 -->
     <register name="foo1" type="Foo">
+        <property name="Name">
+            <value>FOO!</value>
+        </property>
     </register>
 
     <!-- foo2 -->
     <register name="foo2" type="Foo">
+        <property name="Name"> 
+            <value>GOOD</value>
+        </property>
+        <property name="IntValue">
+            <value>2</value>
+        </property>
     </register>
+
+    <register type="Foo">
+    </register>
+
+    <register type="Container{}">
+        <constructor/>
+        <method name="SetInstance">
+            <dependency type="T"/>
+        </method>
+    </register>
+
+    <register type="Container{String}">
+        <property name="Instance">
+            <value>Hello!</value>
+        </property>
+    </register>
+
 </container>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Implab.ServiceHost/Unity/AbstractInjectionElement.cs	Wed Apr 25 04:44:40 2018 +0300
@@ -0,0 +1,7 @@
+namespace Implab.ServiceHost.Unity
+{
+    public abstract class AbstractInjectionElement
+    {
+        
+    }
+}
\ No newline at end of file
--- a/Implab.ServiceHost/Unity/AbstractInjectorElement.cs	Tue Apr 24 01:46:02 2018 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,7 +0,0 @@
-namespace Implab.ServiceHost.Unity
-{
-    public abstract class AbstractInjectorElement
-    {
-        
-    }
-}
\ No newline at end of file
--- a/Implab.ServiceHost/Unity/AbstractRegistration.cs	Tue Apr 24 01:46:02 2018 +0300
+++ b/Implab.ServiceHost/Unity/AbstractRegistration.cs	Wed Apr 25 04:44:40 2018 +0300
@@ -16,7 +16,7 @@
         }
 
         public void Visit(ConfigurationContext context) {
-            context.Visist(this);
+            context.Visit(this);
         }
     }
 }
\ No newline at end of file
--- a/Implab.ServiceHost/Unity/AssemblyElement.cs	Tue Apr 24 01:46:02 2018 +0300
+++ b/Implab.ServiceHost/Unity/AssemblyElement.cs	Wed Apr 25 04:44:40 2018 +0300
@@ -8,7 +8,7 @@
         public string AssemblyName { get; set; }
         
         public void Visit(ConfigurationContext context) {
-            throw new System.NotImplementedException();
+            context.Visit(this);
         }
     }
 }
\ No newline at end of file
--- a/Implab.ServiceHost/Unity/ConfigurationContext.cs	Tue Apr 24 01:46:02 2018 +0300
+++ b/Implab.ServiceHost/Unity/ConfigurationContext.cs	Wed Apr 25 04:44:40 2018 +0300
@@ -8,93 +8,56 @@
     using System.Reflection;
     using System.Text;
     using global::Unity;
+    using Implab.Xml;
     using static Trace<ConfigurationContext>;
 
     public class ConfigurationContext {
-        Regex _nsRx = new Regex(@"^\w+(\.\w+)*$", RegexOptions.Compiled);
-        readonly LinkedList<string> m_namespases = new LinkedList<string>();
 
-        LinkedListNode<string> m_insertAt;
+        readonly TypeResolver m_resolver;
+
+        
 
         readonly UnityContainer m_container;
-
+        
         public ConfigurationContext(UnityContainer container) {
             m_container = container ?? new UnityContainer();
-            m_insertAt = new LinkedListNode<string>(string.Empty);
-            m_namespases.AddFirst(m_insertAt);
-        }
-
-        public void AddNamespace(string ns) {
-            Safe.ArgumentMatch(ns, nameof(ns), _nsRx);
-            if (m_insertAt != null)
-                m_namespases.AddAfter(m_insertAt, ns);
-            else
-                m_namespases.AddFirst(ns);
+            m_resolver = new TypeResolver();
         }
 
-        public Type Resolve(TypeReference reference) {
-            Safe.ArgumentNotNull(reference, nameof(reference));
 
-            var args = reference.IsGeneric && !reference.IsOpenGeneric ? reference.GenericParameters?.Select(Resolve).ToArray() : null;
-            var argc = reference.IsGeneric ? reference.GenericParameters.Length : 0;
-
-            foreach (var ns in m_namespases) {
-                var typeName = FormatName(new [] { ns, reference.Namespace, reference.TypeName}, argc, args, reference.IsArray);
-
-                var resolved = ProbeType(typeName);
-                if (resolved != null) {
-                    Log("Probe succeed {0} in '{1}': {2} -> {3}", reference, ns, typeName, resolved.AssemblyQualifiedName);
-                    return resolved;
-                } else {
-                    Log("Probe failed {0} in '{1}': {2}", reference, ns, typeName);
-                }
-            }
-
-            throw new Exception($"Failed to resolve: {reference}");
+        public Type Resolve(string typeReference) {
+            return m_resolver.Resolve(TypeReference.Parse(typeReference));
         }
 
-        Type ProbeType(string typeName) {
-            var assemblies = AppDomain.CurrentDomain.GetAssemblies();
-
-            foreach(var assembly in assemblies) {
-                var type = assembly.GetType(typeName);
-                if (type != null)
-                    return type;
-            }
-            return null;
-        }
-
-        string FormatName(string[] parts, int argc, Type[] args, bool isArray) {
-            var builder = new StringBuilder();
-            
-            builder.Append(String.Join(".", parts.Where(x => !string.IsNullOrEmpty(x))));
-            if (argc > 0) {
-                builder.Append('`');
-                builder.Append(argc);
-            }
-
-            if (args!= null && args.Length > 0) {
-                builder.Append('[');
-                builder.Append(string.Join(",", args.Select(x => $"[{x.AssemblyQualifiedName}]")));
-                builder.Append(']');
-            }
-
-            if(isArray)
-                builder.Append("[]");
-
-                return builder.ToString();
-        }
-
-        public Type Resolve(string typeReference) {
-            return Resolve(TypeReference.Parse(typeReference));
-        }
-
-        public void Visist(AbstractRegistration descriptor) {
+        internal void Visit(AbstractRegistration descriptor) {
             
         }
 
+        internal void Visit(NamespaceElement namespaceElement) {
+            m_resolver.AddNamespace(namespaceElement.Name);
+        }
+
+        internal void Visit(AssemblyElement assemblyElement) {
+            Assembly.Load(assemblyElement.AssemblyName);
+        }
+
+        internal void Visit(IncludeElement includeElement) {
+            Include(includeElement.Href);
+        }
+
         public void Include(string file) {
+            var includeContext = new ConfigurationContext(m_container);
+            includeContext.LoadConfig(file);
+        }
 
+        public void LoadConfig(string file) {
+            var config = SerializationHelpers.DeserializeFromFile<ContainerElement>(file);
+            Visit(config);
+        }
+
+        public void Visit(ContainerElement containerElement) {
+            foreach (var item in containerElement.Items)
+                item.Visit(this);
         }
 
     }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Implab.ServiceHost/Unity/ConstructorInjectionElement.cs	Wed Apr 25 04:44:40 2018 +0300
@@ -0,0 +1,12 @@
+using System.Xml.Serialization;
+
+namespace Implab.ServiceHost.Unity {
+    public class ConstructorInjectionElement : AbstractInjectionElement {
+        
+        [XmlElement("dependency", typeof(DependencyParameterElement))]
+        [XmlElement("value", typeof(ValueParameterElement))]
+        [XmlElement("serialized", typeof(SerializedParameterElement))]
+        [XmlElement("default", typeof(DefaultParameterElement))]
+        public InjectionParameterElement[] Parameters { get; set; }
+    }
+}
\ No newline at end of file
--- a/Implab.ServiceHost/Unity/ConstructorInjectorElement.cs	Tue Apr 24 01:46:02 2018 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,5 +0,0 @@
-namespace Implab.ServiceHost.Unity {
-    public class ConstructorInjectorElement : AbstractInjectorElement {
-
-    }
-}
\ No newline at end of file
--- a/Implab.ServiceHost/Unity/ContainerElement.cs	Tue Apr 24 01:46:02 2018 +0300
+++ b/Implab.ServiceHost/Unity/ContainerElement.cs	Wed Apr 25 04:44:40 2018 +0300
@@ -8,7 +8,7 @@
     [XmlRoot("container", Namespace = Schema.ContainerConfigurationNamespace)]
     public class ContainerElement : IXmlSerializable {
 
-        public List<IConfigurationElement> Registrations {get; set; } = new List<IConfigurationElement>();
+        public List<IConfigurationElement> Items {get; set; } = new List<IConfigurationElement>();
 
         public XmlSchema GetSchema() {
             return null;
@@ -17,7 +17,7 @@
         public void ReadXml(XmlReader reader) {
             while(reader.Read() && reader.NodeType != XmlNodeType.EndElement) {
                 var registration = ConfigurationSchema.Default.Deserialize<IConfigurationElement>(reader);
-                Registrations.Add(registration);
+                Items.Add(registration);
             }
         }
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Implab.ServiceHost/Unity/DefaultParameterElement.cs	Wed Apr 25 04:44:40 2018 +0300
@@ -0,0 +1,7 @@
+namespace Implab.ServiceHost.Unity
+{
+    public class DefaultParameterElement : InjectionParameterElement
+    {
+        
+    }
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Implab.ServiceHost/Unity/DependencyParameterElement.cs	Wed Apr 25 04:44:40 2018 +0300
@@ -0,0 +1,7 @@
+namespace Implab.ServiceHost.Unity
+{
+    public class DependencyParameterElement : InjectionParameterElement
+    {
+        
+    }
+}
\ No newline at end of file
--- a/Implab.ServiceHost/Unity/IncludeElement.cs	Tue Apr 24 01:46:02 2018 +0300
+++ b/Implab.ServiceHost/Unity/IncludeElement.cs	Wed Apr 25 04:44:40 2018 +0300
@@ -7,7 +7,7 @@
         public string Href { get; set; }
 
         public void Visit(ConfigurationContext context) {
-            context.Include(Href);
+            context.Visit(this);
         }
     }
 }
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Implab.ServiceHost/Unity/InjectionParameterElement.cs	Wed Apr 25 04:44:40 2018 +0300
@@ -0,0 +1,9 @@
+using System.Xml.Serialization;
+
+namespace Implab.ServiceHost.Unity {
+    public class InjectionParameterElement {
+        
+        [XmlAttribute("type")]
+        public string TypeName { get; set; }
+    }
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Implab.ServiceHost/Unity/MethodInjectionElement.cs	Wed Apr 25 04:44:40 2018 +0300
@@ -0,0 +1,16 @@
+using System.Xml.Serialization;
+
+namespace Implab.ServiceHost.Unity {
+    public class MethodInjectionElement : AbstractInjectionElement {
+
+        [XmlAttribute("name")]
+        public string Name { get; set; }
+
+        [XmlElement("dependency", typeof(DependencyParameterElement))]
+        [XmlElement("value", typeof(ValueParameterElement))]
+        [XmlElement("serialized", typeof(SerializedParameterElement))]
+        [XmlElement("default", typeof(DefaultParameterElement))]
+        public InjectionParameterElement[] Parameters { get; set; }
+
+    }
+}
\ No newline at end of file
--- a/Implab.ServiceHost/Unity/MethodInjectorElement.cs	Tue Apr 24 01:46:02 2018 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,13 +0,0 @@
-using System.Xml.Serialization;
-
-namespace Implab.ServiceHost.Unity {
-    public class MethodInjectorElement : AbstractInjectorElement {
-
-        [XmlAttribute("name")]
-        public string Name { get; set; }
-
-        [XmlElement("params")]
-        public MethodInjectorParameter[] Parameters { get; set; }
-
-    }
-}
\ No newline at end of file
--- a/Implab.ServiceHost/Unity/MethodInjectorParameter.cs	Tue Apr 24 01:46:02 2018 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,7 +0,0 @@
-namespace Implab.ServiceHost.Unity
-{
-    public class MethodInjectorParameter
-    {
-        
-    }
-}
\ No newline at end of file
--- a/Implab.ServiceHost/Unity/NamespaceElement.cs	Tue Apr 24 01:46:02 2018 +0300
+++ b/Implab.ServiceHost/Unity/NamespaceElement.cs	Wed Apr 25 04:44:40 2018 +0300
@@ -9,7 +9,7 @@
         public string Name { get; set; }
 
         public void Visit(ConfigurationContext context) {
-            throw new System.NotImplementedException();
+            context.Visit(this);
         }
     }
 }
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Implab.ServiceHost/Unity/PropertyInjectionElement.cs	Wed Apr 25 04:44:40 2018 +0300
@@ -0,0 +1,12 @@
+using System.Xml.Serialization;
+
+namespace Implab.ServiceHost.Unity {
+    public class PropertyInjectionElement : AbstractInjectionElement {
+
+        [XmlElement("dependency", typeof(DependencyParameterElement))]
+        [XmlElement("value", typeof(ValueParameterElement))]
+        [XmlElement("serialized", typeof(SerializedParameterElement))]
+        [XmlElement("default", typeof(DefaultParameterElement))]
+        public InjectionParameterElement Value { get; set; }
+    }
+}
\ No newline at end of file
--- a/Implab.ServiceHost/Unity/PropertyInjectorElement.cs	Tue Apr 24 01:46:02 2018 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,6 +0,0 @@
-namespace Implab.ServiceHost.Unity {
-    public class PropertyInjectorElement : AbstractInjectorElement {
-
-
-    }
-}
\ No newline at end of file
--- a/Implab.ServiceHost/Unity/RegisterElement.cs	Tue Apr 24 01:46:02 2018 +0300
+++ b/Implab.ServiceHost/Unity/RegisterElement.cs	Wed Apr 25 04:44:40 2018 +0300
@@ -27,10 +27,10 @@
         [XmlElement("hierarchy", typeof(HierarchicalLifetimeElement))]
         public LifetimeElement Lifetime {get; set;}
 
-        [XmlElement("constructor", typeof(ConstructorInjectorElement))]
-        [XmlElement("property", typeof(PropertyInjectorElement))]
-        [XmlElement("method", typeof(MethodInjectorElement))]
-        public AbstractInjectorElement[] Injectors { get; set; }
+        [XmlElement("constructor", typeof(ConstructorInjectionElement))]
+        [XmlElement("property", typeof(PropertyInjectionElement))]
+        [XmlElement("method", typeof(MethodInjectionElement))]
+        public AbstractInjectionElement[] Injectors { get; set; }
     }
     
 }
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Implab.ServiceHost/Unity/SerializedParameterElement.cs	Wed Apr 25 04:44:40 2018 +0300
@@ -0,0 +1,7 @@
+namespace Implab.ServiceHost.Unity
+{
+    public class SerializedParameterElement : InjectionParameterElement
+    {
+        
+    }
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Implab.ServiceHost/Unity/TypeResolver.cs	Wed Apr 25 04:44:40 2018 +0300
@@ -0,0 +1,124 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Text.RegularExpressions;
+using Implab.Diagnostics;
+
+namespace Implab.ServiceHost.Unity
+{
+    using static Trace<TypeResolver>;
+    public class TypeResolver
+    {
+        readonly Dictionary<string, Type> m_cache = new Dictionary<string, Type>();
+
+        Regex _nsRx = new Regex(@"^\w+(\.\w+)*$", RegexOptions.Compiled);
+        readonly LinkedList<string> m_namespases = new LinkedList<string>();
+
+        LinkedListNode<string> m_insertAt;
+
+        readonly TypeResolver m_parent;
+
+        public TypeResolver() : this(null) {
+
+        }
+
+        public TypeResolver(TypeResolver parent) {
+            m_insertAt = new LinkedListNode<string>(string.Empty);
+            m_namespases.AddFirst(m_insertAt);
+        }
+
+        public void AddNamespace(string ns) {
+            Safe.ArgumentMatch(ns, nameof(ns), _nsRx);
+            if (m_insertAt != null)
+                m_namespases.AddAfter(m_insertAt, ns);
+            else
+                m_namespases.AddFirst(ns);
+        }
+
+        public void AddMapping(string typeName, Type type) {
+            Safe.ArgumentNotEmpty(typeName, nameof(typeName));
+            Safe.ArgumentNotNull(type, nameof(type));
+
+            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 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;
+            }
+
+            return resolved;
+        }
+
+        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.Resolve(reference);
+            
+            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, args, isArray);
+
+                var resolved = Probe(typeName);
+                if (resolved != null) {
+                    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();
+
+            foreach(var assembly in assemblies) {
+                var type = assembly.GetType(typeName);
+                if (type != null)
+                    return type;
+            }
+            return null;
+        }
+
+        string FormatName(string[] parts, int argc, Type[] args, bool isArray) {
+            var builder = new StringBuilder();
+            
+            builder.Append(String.Join(".", parts.Where(x => !string.IsNullOrEmpty(x))));
+            if (argc > 0) {
+                builder.Append('`');
+                builder.Append(argc);
+            }
+
+            if (args!= null && args.Length > 0) {
+                builder.Append('[');
+                builder.Append(string.Join(",", args.Select(x => $"[{x.AssemblyQualifiedName}]")));
+                builder.Append(']');
+            }
+
+            if(isArray)
+                builder.Append("[]");
+
+                return builder.ToString();
+        }
+    }
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Implab.ServiceHost/Unity/ValueParameterElement.cs	Wed Apr 25 04:44:40 2018 +0300
@@ -0,0 +1,7 @@
+namespace Implab.ServiceHost.Unity
+{
+    public class ValueParameterElement : InjectionParameterElement
+    {
+        
+    }
+}
\ No newline at end of file