# HG changeset patch # User cin # Date 2018-04-23 22:46:02 # Node ID ff581cff700324d0f69372982cb6d171ea0898ed # Parent 0be8a6ae83078a558dfef2376da8854c927a2d54 Working on Unity container xml configuration diff --git a/Implab.Playground/Program.cs b/Implab.Playground/Program.cs --- a/Implab.Playground/Program.cs +++ b/Implab.Playground/Program.cs @@ -9,6 +9,11 @@ using Unity.Injection; namespace Implab.Playground { public class Foo { + + public class Bar { + + } + public int IntValue { get; set; } public string StringValue { get; set; } @@ -32,20 +37,10 @@ namespace Implab.Playground { static void Main(string[] args) { var container = new UnityContainer(); - var listener = new SimpleTraceListener(Console.Out); - Trace.TraceSource.Switch.Level = SourceLevels.All; - Trace.TraceSource.Listeners.Add(listener); - - var c = new Container(); + var conf = SerializationHelpers.DeserializeFromFile("data/sample.xml"); - var cts = new ConfigurationContext(); - cts.AddNamespace("System"); - cts.AddNamespace("System.Collections.Generic"); - cts.AddNamespace("Implab.Playground"); + Console.WriteLine($"Registrations: {conf.Registrations.Count}"); - Console.WriteLine(c.GetType().FullName); - - cts.Resolve("Container{Int32}"); } diff --git a/Implab.Playground/data/sample.xml b/Implab.Playground/data/sample.xml --- a/Implab.Playground/data/sample.xml +++ b/Implab.Playground/data/sample.xml @@ -1,10 +1,10 @@ - + - + \ No newline at end of file diff --git a/Implab.ServiceHost/Unity/AbstractInjectorElement.cs b/Implab.ServiceHost/Unity/AbstractInjectorElement.cs new file mode 100644 --- /dev/null +++ b/Implab.ServiceHost/Unity/AbstractInjectorElement.cs @@ -0,0 +1,7 @@ +namespace Implab.ServiceHost.Unity +{ + public abstract class AbstractInjectorElement + { + + } +} \ No newline at end of file diff --git a/Implab.ServiceHost/Unity/AbstractRegistration.cs b/Implab.ServiceHost/Unity/AbstractRegistration.cs new file mode 100644 --- /dev/null +++ b/Implab.ServiceHost/Unity/AbstractRegistration.cs @@ -0,0 +1,22 @@ +using System; +using System.Xml.Serialization; +using Unity.Lifetime; +using Unity.Registration; + +namespace Implab.ServiceHost.Unity +{ + public abstract class AbstractRegistration : IConfigurationElement { + + /// + /// An optional name for a registration in the container + /// + [XmlAttribute("name")] + public string Name { + get; set; + } + + public void Visit(ConfigurationContext context) { + context.Visist(this); + } + } +} \ No newline at end of file diff --git a/Implab.ServiceHost/Unity/AssemblyElement.cs b/Implab.ServiceHost/Unity/AssemblyElement.cs new file mode 100644 --- /dev/null +++ b/Implab.ServiceHost/Unity/AssemblyElement.cs @@ -0,0 +1,14 @@ +using System.Xml.Serialization; + +namespace Implab.ServiceHost.Unity +{ + [XmlRoot("assembly", Namespace = Schema.ContainerConfigurationNamespace)] + public class AssemblyElement : IConfigurationElement { + [XmlAttribute("name")] + public string AssemblyName { get; set; } + + public void Visit(ConfigurationContext context) { + throw new System.NotImplementedException(); + } + } +} \ No newline at end of file diff --git a/Implab.ServiceHost/Unity/ConfigurationContext.cs b/Implab.ServiceHost/Unity/ConfigurationContext.cs --- a/Implab.ServiceHost/Unity/ConfigurationContext.cs +++ b/Implab.ServiceHost/Unity/ConfigurationContext.cs @@ -5,7 +5,9 @@ using Implab.Diagnostics; namespace Implab.ServiceHost.Unity { using System.Linq; + using System.Reflection; using System.Text; + using global::Unity; using static Trace; public class ConfigurationContext { @@ -14,7 +16,10 @@ namespace Implab.ServiceHost.Unity { LinkedListNode m_insertAt; - public ConfigurationContext() { + readonly UnityContainer m_container; + + public ConfigurationContext(UnityContainer container) { + m_container = container ?? new UnityContainer(); m_insertAt = new LinkedListNode(string.Empty); m_namespases.AddFirst(m_insertAt); } @@ -36,9 +41,9 @@ namespace Implab.ServiceHost.Unity { foreach (var ns in m_namespases) { var typeName = FormatName(new [] { ns, reference.Namespace, reference.TypeName}, argc, args, reference.IsArray); - var resolved = Type.GetType(typeName, false); + var resolved = ProbeType(typeName); if (resolved != null) { - Log("Probe succeed {0} in '{1}': {2} -> {3}", reference, ns, typeName, resolved.FullName); + 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); @@ -48,6 +53,17 @@ namespace Implab.ServiceHost.Unity { throw new Exception($"Failed to resolve: {reference}"); } + 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(); @@ -59,7 +75,7 @@ namespace Implab.ServiceHost.Unity { if (args!= null && args.Length > 0) { builder.Append('['); - builder.Append(string.Join(",", args.Select(x => x.FullName))); + builder.Append(string.Join(",", args.Select(x => $"[{x.AssemblyQualifiedName}]"))); builder.Append(']'); } @@ -73,7 +89,11 @@ namespace Implab.ServiceHost.Unity { return Resolve(TypeReference.Parse(typeReference)); } - public void Register(ServiceElement descriptor) { + public void Visist(AbstractRegistration descriptor) { + + } + + public void Include(string file) { } diff --git a/Implab.ServiceHost/Unity/ConfigurationSchema.cs b/Implab.ServiceHost/Unity/ConfigurationSchema.cs new file mode 100644 --- /dev/null +++ b/Implab.ServiceHost/Unity/ConfigurationSchema.cs @@ -0,0 +1,47 @@ +using System; +using System.Collections.Generic; +using System.Reflection; +using System.Xml; +using System.Xml.Serialization; +using Implab.Components; + +namespace Implab.ServiceHost.Unity { + public class ConfigurationSchema { + + public static ConfigurationSchema Default { get; private set; } = CreateDefault(); + + readonly Dictionary, LazyAndWeak> m_mappings = new Dictionary, LazyAndWeak>(); + + public void DefineMapping(string name, string ns, Type type) { + Safe.ArgumentNotEmpty(name, nameof(name)); + Safe.ArgumentNotNull(type, nameof(type)); + ns = ns ?? string.Empty; + m_mappings[Tuple.Create(name, ns)] = new LazyAndWeak(() => new XmlSerializer(type), true); + } + + public void DefineMapping() { + var xmlRoot = typeof(T).GetCustomAttribute(); + var ns = xmlRoot?.Namespace; + var root = xmlRoot?.ElementName ?? typeof(T).Name; + DefineMapping(root, ns, typeof(T)); + } + + public T Deserialize(XmlReader reader) { + reader.MoveToContent(); + var name = reader.Name; + var ns = reader.NamespaceURI; + + return (T)m_mappings[Tuple.Create(name, ns)].Value.Deserialize(reader); + } + + static ConfigurationSchema CreateDefault() { + var schema = new ConfigurationSchema(); + + schema.DefineMapping(); + + return schema; + } + + + } +} \ No newline at end of file diff --git a/Implab.ServiceHost/Unity/ConstructorInjectorElement.cs b/Implab.ServiceHost/Unity/ConstructorInjectorElement.cs new file mode 100644 --- /dev/null +++ b/Implab.ServiceHost/Unity/ConstructorInjectorElement.cs @@ -0,0 +1,5 @@ +namespace Implab.ServiceHost.Unity { + public class ConstructorInjectorElement : AbstractInjectorElement { + + } +} \ No newline at end of file diff --git a/Implab.ServiceHost/Unity/ContainerElement.cs b/Implab.ServiceHost/Unity/ContainerElement.cs --- a/Implab.ServiceHost/Unity/ContainerElement.cs +++ b/Implab.ServiceHost/Unity/ContainerElement.cs @@ -8,7 +8,7 @@ namespace Implab.ServiceHost.Unity { [XmlRoot("container", Namespace = Schema.ContainerConfigurationNamespace)] public class ContainerElement : IXmlSerializable { - public List Registrations {get; set; } = new List(); + public List Registrations {get; set; } = new List(); public XmlSchema GetSchema() { return null; @@ -16,7 +16,7 @@ namespace Implab.ServiceHost.Unity { public void ReadXml(XmlReader reader) { while(reader.Read() && reader.NodeType != XmlNodeType.EndElement) { - var registration = SerializationHelpers.Deserialize(reader); + var registration = ConfigurationSchema.Default.Deserialize(reader); Registrations.Add(registration); } } diff --git a/Implab.ServiceHost/Unity/ContainerLifetimeElement.cs b/Implab.ServiceHost/Unity/ContainerLifetimeElement.cs new file mode 100644 --- /dev/null +++ b/Implab.ServiceHost/Unity/ContainerLifetimeElement.cs @@ -0,0 +1,10 @@ +using Unity.Lifetime; + +namespace Implab.ServiceHost.Unity +{ + public class ContainerLifetimeElement : LifetimeElement { + public override LifetimeManager GetLifetimeManager(ConfigurationContext ctx) { + return new ContainerControlledLifetimeManager(); + } + } +} \ No newline at end of file diff --git a/Implab.ServiceHost/Unity/ContextLifetimeElement.cs b/Implab.ServiceHost/Unity/ContextLifetimeElement.cs new file mode 100644 --- /dev/null +++ b/Implab.ServiceHost/Unity/ContextLifetimeElement.cs @@ -0,0 +1,10 @@ +using Unity.Lifetime; + +namespace Implab.ServiceHost.Unity +{ + public class ContextLifetimeElement : LifetimeElement { + public override LifetimeManager GetLifetimeManager(ConfigurationContext ctx) { + return new PerResolveLifetimeManager(); + } + } +} \ No newline at end of file diff --git a/Implab.ServiceHost/Unity/HierarchicalLifetimeElement.cs b/Implab.ServiceHost/Unity/HierarchicalLifetimeElement.cs new file mode 100644 --- /dev/null +++ b/Implab.ServiceHost/Unity/HierarchicalLifetimeElement.cs @@ -0,0 +1,10 @@ +using Unity.Lifetime; + +namespace Implab.ServiceHost.Unity +{ + public class HierarchicalLifetimeElement : LifetimeElement { + public override LifetimeManager GetLifetimeManager(ConfigurationContext ctx) { + return new HierarchicalLifetimeManager(); + } + } +} \ No newline at end of file diff --git a/Implab.ServiceHost/Unity/IConfigurationElement.cs b/Implab.ServiceHost/Unity/IConfigurationElement.cs new file mode 100644 --- /dev/null +++ b/Implab.ServiceHost/Unity/IConfigurationElement.cs @@ -0,0 +1,5 @@ +namespace Implab.ServiceHost.Unity { + public interface IConfigurationElement { + void Visit(ConfigurationContext context); + } +} \ No newline at end of file diff --git a/Implab.ServiceHost/Unity/IncludeElement.cs b/Implab.ServiceHost/Unity/IncludeElement.cs new file mode 100644 --- /dev/null +++ b/Implab.ServiceHost/Unity/IncludeElement.cs @@ -0,0 +1,13 @@ +using System.Xml.Serialization; + +namespace Implab.ServiceHost.Unity { + [XmlRoot("include", Namespace = Schema.ContainerConfigurationNamespace)] + public class IncludeElement : IConfigurationElement { + [XmlAttribute("href")] + public string Href { get; set; } + + public void Visit(ConfigurationContext context) { + context.Include(Href); + } + } +} \ No newline at end of file diff --git a/Implab.ServiceHost/Unity/LifetimeElement.cs b/Implab.ServiceHost/Unity/LifetimeElement.cs new file mode 100644 --- /dev/null +++ b/Implab.ServiceHost/Unity/LifetimeElement.cs @@ -0,0 +1,10 @@ +using Unity.Lifetime; + +namespace Implab.ServiceHost.Unity +{ + public abstract class LifetimeElement + { + public abstract LifetimeManager GetLifetimeManager(ConfigurationContext ctx); + + } +} \ No newline at end of file diff --git a/Implab.ServiceHost/Unity/MethodInjectorElement.cs b/Implab.ServiceHost/Unity/MethodInjectorElement.cs new file mode 100644 --- /dev/null +++ b/Implab.ServiceHost/Unity/MethodInjectorElement.cs @@ -0,0 +1,13 @@ +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 diff --git a/Implab.ServiceHost/Unity/MethodInjectorParameter.cs b/Implab.ServiceHost/Unity/MethodInjectorParameter.cs new file mode 100644 --- /dev/null +++ b/Implab.ServiceHost/Unity/MethodInjectorParameter.cs @@ -0,0 +1,7 @@ +namespace Implab.ServiceHost.Unity +{ + public class MethodInjectorParameter + { + + } +} \ No newline at end of file diff --git a/Implab.ServiceHost/Unity/NamespaceElement.cs b/Implab.ServiceHost/Unity/NamespaceElement.cs new file mode 100644 --- /dev/null +++ b/Implab.ServiceHost/Unity/NamespaceElement.cs @@ -0,0 +1,15 @@ +using System.Xml.Serialization; + +namespace Implab.ServiceHost.Unity +{ + [XmlRoot("namespace", Namespace = Schema.ContainerConfigurationNamespace)] + public class NamespaceElement : IConfigurationElement { + + [XmlAttribute("name")] + public string Name { get; set; } + + public void Visit(ConfigurationContext context) { + throw new System.NotImplementedException(); + } + } +} \ No newline at end of file diff --git a/Implab.ServiceHost/Unity/PropertyInjectorElement.cs b/Implab.ServiceHost/Unity/PropertyInjectorElement.cs new file mode 100644 --- /dev/null +++ b/Implab.ServiceHost/Unity/PropertyInjectorElement.cs @@ -0,0 +1,6 @@ +namespace Implab.ServiceHost.Unity { + public class PropertyInjectorElement : AbstractInjectorElement { + + + } +} \ No newline at end of file diff --git a/Implab.ServiceHost/Unity/RegisterElement.cs b/Implab.ServiceHost/Unity/RegisterElement.cs new file mode 100644 --- /dev/null +++ b/Implab.ServiceHost/Unity/RegisterElement.cs @@ -0,0 +1,36 @@ +using System; +using System.Xml.Serialization; +using Unity.Lifetime; +using Unity.Registration; + +namespace Implab.ServiceHost.Unity { + + [XmlRoot("register", Namespace = Schema.ContainerConfigurationNamespace)] + public class RegisterElement : AbstractRegistration { + + /// + /// An optional type specification for the service registration, + /// must be assignable from the type specified by + /// + [XmlAttribute("provides")] + public string ProvidesType { get; set; } + + /// + /// The type which is registered as a service in the container. + /// + [XmlAttribute("type")] + public string ImplementedType { get; set; } + + [XmlElement("signleton", typeof(SimgletonLifetimeElement))] + [XmlElement("context", typeof(ContextLifetimeElement))] + [XmlElement("container", typeof(ContainerLifetimeElement))] + [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; } + } + +} \ No newline at end of file diff --git a/Implab.ServiceHost/Unity/ServiceElement.cs b/Implab.ServiceHost/Unity/ServiceElement.cs deleted file mode 100644 --- a/Implab.ServiceHost/Unity/ServiceElement.cs +++ /dev/null @@ -1,28 +0,0 @@ -using System; -using System.Xml.Serialization; - -namespace Implab.ServiceHost.Unity { - - [XmlRoot("register", Namespace = Schema.ContainerConfigurationNamespace)] - public class ServiceElement { - /// - /// An optional name for a registration in the container - /// - [XmlAttribute("name")] - public string Name { get; set; } - - /// - /// An optional type specification for the service registration, - /// must be assignable from the type specified by - /// - [XmlAttribute("provides")] - public string ProvidesType { get; set; } - - /// - /// The type which is registered as a service in the container. - /// - [XmlAttribute("type")] - public string ImplementedType { get; set; } - } - -} \ No newline at end of file diff --git a/Implab.ServiceHost/Unity/SimgletonLifetimeElement.cs b/Implab.ServiceHost/Unity/SimgletonLifetimeElement.cs new file mode 100644 --- /dev/null +++ b/Implab.ServiceHost/Unity/SimgletonLifetimeElement.cs @@ -0,0 +1,10 @@ +using Unity.Lifetime; + +namespace Implab.ServiceHost.Unity +{ + public class SimgletonLifetimeElement : LifetimeElement { + public override LifetimeManager GetLifetimeManager(ConfigurationContext ctx) { + return new SingletonLifetimeManager(); + } + } +} \ No newline at end of file diff --git a/Implab.ServiceHost/Unity/TypeReferenceParser.cs b/Implab.ServiceHost/Unity/TypeReferenceParser.cs --- a/Implab.ServiceHost/Unity/TypeReferenceParser.cs +++ b/Implab.ServiceHost/Unity/TypeReferenceParser.cs @@ -20,7 +20,7 @@ namespace Implab.ServiceHost.Unity { Eof } - readonly Regex _tokens = new Regex(@"(\w+)|\s*([\.{},\+])\s*"); + readonly Regex _tokens = new Regex(@"([\w\+]+)|\s*([\.{},])\s*"); TokenType m_token; @@ -68,7 +68,6 @@ namespace Implab.ServiceHost.Unity { m_token = TokenType.CloseList; break; case ".": - case "+": m_token = TokenType.Dot; break; case ",":