# HG changeset patch # User cin # Date 2018-04-27 01:47:52 # Node ID 22629bf26121d959c790ef41a541f21a48c76ed7 # Parent 79110a16cab7c4b1cb503a2925b96021347870fa Unity xml configuration, alpha2 diff --git a/Implab.Playground/Program.cs b/Implab.Playground/Program.cs --- a/Implab.Playground/Program.cs +++ b/Implab.Playground/Program.cs @@ -50,7 +50,7 @@ namespace Implab.Playground { var stopwatch = new Stopwatch(); stopwatch.Start(); - var ctx = new ContainerContext(); + var ctx = new ContainerBuilder(); Console.WriteLine($"Created: {stopwatch.ElapsedMilliseconds}"); 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 @@ -38,7 +38,7 @@ - + Baaar diff --git a/Implab.ServiceHost/Unity/AbstractInjectionElement.cs b/Implab.ServiceHost/Unity/AbstractInjectionElement.cs --- a/Implab.ServiceHost/Unity/AbstractInjectionElement.cs +++ b/Implab.ServiceHost/Unity/AbstractInjectionElement.cs @@ -1,8 +1,10 @@ using System; -namespace Implab.ServiceHost.Unity -{ +namespace Implab.ServiceHost.Unity { + /// + /// Base class for injections, each injection is applied to the type registration context. + /// public abstract class AbstractInjectionElement { - internal abstract void Visit(TypeRegistrationContext context); + internal abstract void Visit(TypeRegistrationBuilder context); } } \ No newline at end of file diff --git a/Implab.ServiceHost/Unity/AbstractRegistration.cs b/Implab.ServiceHost/Unity/AbstractRegistration.cs --- a/Implab.ServiceHost/Unity/AbstractRegistration.cs +++ b/Implab.ServiceHost/Unity/AbstractRegistration.cs @@ -27,9 +27,5 @@ namespace Implab.ServiceHost.Unity [XmlAttribute("type")] public string RegistrationType { get; set; } - public virtual Type ResolveRegistrationType(ContainerContext ctx) { - return ctx.Resolve(RegistrationType); - } - } } \ No newline at end of file diff --git a/Implab.ServiceHost/Unity/AssemblyElement.cs b/Implab.ServiceHost/Unity/AssemblyElement.cs --- a/Implab.ServiceHost/Unity/AssemblyElement.cs +++ b/Implab.ServiceHost/Unity/AssemblyElement.cs @@ -7,7 +7,7 @@ namespace Implab.ServiceHost.Unity [XmlAttribute("name")] public string AssemblyName { get; set; } - public override void Visit(ContainerContext context) { + public override void Visit(ContainerBuilder context) { context.Visit(this); } } diff --git a/Implab.ServiceHost/Unity/ConstructorInjectionElement.cs b/Implab.ServiceHost/Unity/ConstructorInjectionElement.cs --- a/Implab.ServiceHost/Unity/ConstructorInjectionElement.cs +++ b/Implab.ServiceHost/Unity/ConstructorInjectionElement.cs @@ -9,7 +9,7 @@ namespace Implab.ServiceHost.Unity { [XmlElement("default", typeof(DefaultParameterElement))] public InjectionParameterElement[] Parameters { get; set; } - internal override void Visit(TypeRegistrationContext context) { + internal override void Visit(TypeRegistrationBuilder context) { context.Visit(this); } } diff --git a/Implab.ServiceHost/Unity/ContainerBuilder.cs b/Implab.ServiceHost/Unity/ContainerBuilder.cs new file mode 100644 --- /dev/null +++ b/Implab.ServiceHost/Unity/ContainerBuilder.cs @@ -0,0 +1,125 @@ +using System; +using System.Collections.Generic; +using System.Text.RegularExpressions; +using Implab.Diagnostics; + +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; + + public class ContainerBuilder { + + readonly TypeResolver m_resolver; + + readonly UnityContainer m_container; + + readonly ContainerConfigurationSchema m_schema; + + public UnityContainer Container { + get { + return m_container; + } + } + + public ContainerBuilder() : this(null, null) { + } + + public ContainerBuilder(UnityContainer container, ContainerConfigurationSchema schema) { + m_container = container ?? new UnityContainer(); + m_resolver = new TypeResolver(); + m_schema = schema ?? ContainerConfigurationSchema.Default; + } + + public Type ResolveType(string typeReference) { + return m_resolver.Resolve(typeReference); + } + + internal void Visit(RegisterElement registerElement) { + var registrationType = ResolveType(registerElement.RegistrationType); + var implementationType = string.IsNullOrEmpty(registerElement.MapToType) ? registrationType : ResolveType(registerElement.MapToType); + + var registrationContext = new TypeRegistrationBuilder( + m_resolver, + registrationType, + implementationType + ); + + if (registerElement.Injectors != null) { + foreach (var injector in registerElement.Injectors) { + injector.Visit(registrationContext); + } + } + + m_container.RegisterType( + registrationContext.RegistrationType, + registrationContext.ImplementationType, + registerElement.Name, + registerElement.Lifetime?.GetLifetimeManager(this), + registrationContext.Injections + ); + } + + internal void Visit(SerializedElement serializedElement) { + var registrationType = ResolveType(serializedElement.RegistrationType); + var valueBuilder = new InjectionValueBuilder(m_resolver, null); + + valueBuilder.Visit(serializedElement); + + m_container.RegisterInstance( + registrationType, + serializedElement.Name, + valueBuilder.Value, + serializedElement.Lifetime?.GetLifetimeManager(this) + ); + } + + internal void Visit(ValueElement valueElement) { + var registrationType = ResolveType(valueElement.RegistrationType); + var valueBuilder = new InjectionValueBuilder(m_resolver, null); + + valueBuilder.Visit(valueElement); + + m_container.RegisterInstance( + registrationType, + valueElement.Name, + valueBuilder.Value, + valueElement.Lifetime?.GetLifetimeManager(this) + ); + } + + 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 ContainerBuilder(m_container, m_schema); + includeContext.LoadConfig(file); + } + + public void LoadConfig(string file) { + var config = m_schema.LoadFile(file); + Visit(config); + } + + internal void Visit(ContainerElement containerElement) { + foreach (var item in containerElement.Items) + item.Visit(this); + } + + + + } +} \ No newline at end of file diff --git a/Implab.ServiceHost/Unity/ContainerConfigurationSchema.cs b/Implab.ServiceHost/Unity/ContainerConfigurationSchema.cs --- a/Implab.ServiceHost/Unity/ContainerConfigurationSchema.cs +++ b/Implab.ServiceHost/Unity/ContainerConfigurationSchema.cs @@ -55,6 +55,8 @@ namespace Implab.ServiceHost.Unity { var schema = new ContainerConfigurationSchema(); schema.RegisterContainerElement("register"); + schema.RegisterContainerElement("serialized"); + schema.RegisterContainerElement("value"); schema.RegisterContainerElement("include"); schema.RegisterContainerElement("assembly"); schema.RegisterContainerElement("namespace"); diff --git a/Implab.ServiceHost/Unity/ContainerContext.cs b/Implab.ServiceHost/Unity/ContainerContext.cs deleted file mode 100644 --- a/Implab.ServiceHost/Unity/ContainerContext.cs +++ /dev/null @@ -1,111 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Text.RegularExpressions; -using Implab.Diagnostics; - -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; - - public class ContainerContext { - - readonly TypeResolver m_resolver; - - readonly UnityContainer m_container; - - readonly ContainerConfigurationSchema m_schema; - - public UnityContainer Container { - get { - return m_container; - } - } - - public ContainerContext() : this(null, null) { - } - - public ContainerContext(UnityContainer container, ContainerConfigurationSchema schema) { - m_container = container ?? new UnityContainer(); - m_resolver = new TypeResolver(); - m_schema = schema ?? ContainerConfigurationSchema.Default; - } - - public Type Resolve(string typeReference) { - return m_resolver.Resolve(typeReference); - } - - internal void Visit(RegisterElement registerElement) { - var registrationContext = new TypeRegistrationContext( - m_resolver, - registerElement.ResolveRegistrationType(this), - registerElement.ResolveImplementationType(this) - ); - - if (registerElement.Injectors != null) { - foreach (var injector in registerElement.Injectors) { - injector.Visit(registrationContext); - } - } - - m_container.RegisterType( - registrationContext.RegistrationType, - registrationContext.ImplementationType, - registerElement.Name, - registerElement.Lifetime?.GetLifetimeManager(this), - registrationContext.Injections - ); - } - - internal void Visit(SerializedElement serializedElement) { - var registrationType = serializedElement.ResolveRegistrationType(this); - var instace = serializedElement.GetValue(this); - - - m_container.RegisterInstance( - registrationType, - serializedElement.Name, - instace, - serializedElement.Lifetime?.GetLifetimeManager(this) - ); - } - - internal void Visit(ValueElement valueElement) { - - } - - 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 ContainerContext(m_container, m_schema); - includeContext.LoadConfig(file); - } - - public void LoadConfig(string file) { - var config = m_schema.LoadFile(file); - Visit(config); - } - - internal void Visit(ContainerElement containerElement) { - foreach (var item in containerElement.Items) - item.Visit(this); - } - - - - } -} \ 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,9 +8,9 @@ namespace Implab.ServiceHost.Unity { [XmlRoot("container", Namespace = Schema.ContainerConfigurationNamespace)] public class ContainerElement : ContainerItemElement { - public List Items {get; set; } = new List(); + public List Items { get; set; } = new List(); - public override void Visit(ContainerContext context) { + public override void Visit(ContainerBuilder context) { context.Visit(this); } } diff --git a/Implab.ServiceHost/Unity/ContainerItemElement.cs b/Implab.ServiceHost/Unity/ContainerItemElement.cs --- a/Implab.ServiceHost/Unity/ContainerItemElement.cs +++ b/Implab.ServiceHost/Unity/ContainerItemElement.cs @@ -1,5 +1,5 @@ namespace Implab.ServiceHost.Unity { public abstract class ContainerItemElement { - public abstract void Visit(ContainerContext context); + public abstract void Visit(ContainerBuilder context); } } \ No newline at end of file diff --git a/Implab.ServiceHost/Unity/ContainerLifetimeElement.cs b/Implab.ServiceHost/Unity/ContainerLifetimeElement.cs --- a/Implab.ServiceHost/Unity/ContainerLifetimeElement.cs +++ b/Implab.ServiceHost/Unity/ContainerLifetimeElement.cs @@ -3,7 +3,7 @@ using Unity.Lifetime; namespace Implab.ServiceHost.Unity { public class ContainerLifetimeElement : LifetimeElement { - public override LifetimeManager GetLifetimeManager(ContainerContext ctx) { + public override LifetimeManager GetLifetimeManager(ContainerBuilder ctx) { return new ContainerControlledLifetimeManager(); } } diff --git a/Implab.ServiceHost/Unity/ContextLifetimeElement.cs b/Implab.ServiceHost/Unity/ContextLifetimeElement.cs --- a/Implab.ServiceHost/Unity/ContextLifetimeElement.cs +++ b/Implab.ServiceHost/Unity/ContextLifetimeElement.cs @@ -3,7 +3,7 @@ using Unity.Lifetime; namespace Implab.ServiceHost.Unity { public class ContextLifetimeElement : LifetimeElement { - public override LifetimeManager GetLifetimeManager(ContainerContext ctx) { + public override LifetimeManager GetLifetimeManager(ContainerBuilder ctx) { return new PerResolveLifetimeManager(); } } diff --git a/Implab.ServiceHost/Unity/DefaultParameterElement.cs b/Implab.ServiceHost/Unity/DefaultParameterElement.cs --- a/Implab.ServiceHost/Unity/DefaultParameterElement.cs +++ b/Implab.ServiceHost/Unity/DefaultParameterElement.cs @@ -1,9 +1,12 @@ namespace Implab.ServiceHost.Unity { - public class DefaultParameterElement : InjectionParameterElement { - internal override object Resolve(InjectionValueContext context) { - var type = context.ResolveType(TypeName); - return Safe.CreateDefaultValue(type); + public class DefaultParameterElement : InjectionParameterElement, ITextValue { + public string Value { + get { return null; } + } + + internal override void Visit(InjectionValueBuilder builder) { + builder.Visit(this); } } } \ No newline at end of file diff --git a/Implab.ServiceHost/Unity/DependencyParameterElement.cs b/Implab.ServiceHost/Unity/DependencyParameterElement.cs --- a/Implab.ServiceHost/Unity/DependencyParameterElement.cs +++ b/Implab.ServiceHost/Unity/DependencyParameterElement.cs @@ -1,12 +1,16 @@ using System.Xml.Serialization; namespace Implab.ServiceHost.Unity { - public class DependencyParameterElement : InjectionParameterElement { + public class DependencyParameterElement : InjectionParameterElement, IDependencyReference { [XmlAttribute("name")] public string DependencyName { get; set; } [XmlAttribute("optional")] public bool Optional { get; set; } + + internal override void Visit(InjectionValueBuilder builder) { + builder.Visit(this); + } } } \ No newline at end of file diff --git a/Implab.ServiceHost/Unity/FactoryInjectionElement.cs b/Implab.ServiceHost/Unity/FactoryInjectionElement.cs new file mode 100644 --- /dev/null +++ b/Implab.ServiceHost/Unity/FactoryInjectionElement.cs @@ -0,0 +1,7 @@ +namespace Implab.ServiceHost.Unity { + public class FactoryInjectionElement : AbstractInjectionElement { + internal override void Visit(TypeRegistrationBuilder context) { + + } + } +} \ No newline at end of file diff --git a/Implab.ServiceHost/Unity/HierarchicalLifetimeElement.cs b/Implab.ServiceHost/Unity/HierarchicalLifetimeElement.cs --- a/Implab.ServiceHost/Unity/HierarchicalLifetimeElement.cs +++ b/Implab.ServiceHost/Unity/HierarchicalLifetimeElement.cs @@ -3,7 +3,7 @@ using Unity.Lifetime; namespace Implab.ServiceHost.Unity { public class HierarchicalLifetimeElement : LifetimeElement { - public override LifetimeManager GetLifetimeManager(ContainerContext ctx) { + public override LifetimeManager GetLifetimeManager(ContainerBuilder ctx) { return new HierarchicalLifetimeManager(); } } diff --git a/Implab.ServiceHost/Unity/IDependencyReference.cs b/Implab.ServiceHost/Unity/IDependencyReference.cs --- a/Implab.ServiceHost/Unity/IDependencyReference.cs +++ b/Implab.ServiceHost/Unity/IDependencyReference.cs @@ -1,5 +1,8 @@ namespace Implab.ServiceHost.Unity { public interface IDependencyReference { - string Name { get; set; } + + string TypeName { get; set; } + + string DependencyName { get; set; } } } \ No newline at end of file diff --git a/Implab.ServiceHost/Unity/ISerializedValue.cs b/Implab.ServiceHost/Unity/ISerializedValue.cs --- a/Implab.ServiceHost/Unity/ISerializedValue.cs +++ b/Implab.ServiceHost/Unity/ISerializedValue.cs @@ -1,7 +1,11 @@ -namespace Implab.ServiceHost.Unity -{ - public class ISerializedValue - { - +using System.Xml; + +namespace Implab.ServiceHost.Unity { + public interface ISerializedValue { + + string TypeName { get; } + + XmlReader GetReader(); + } } \ No newline at end of file diff --git a/Implab.ServiceHost/Unity/ITextValue.cs b/Implab.ServiceHost/Unity/ITextValue.cs --- a/Implab.ServiceHost/Unity/ITextValue.cs +++ b/Implab.ServiceHost/Unity/ITextValue.cs @@ -1,5 +1,7 @@ namespace Implab.ServiceHost.Unity { public interface ITextValue { + string TypeName { get; } + string Value { get; } } diff --git a/Implab.ServiceHost/Unity/IncludeElement.cs b/Implab.ServiceHost/Unity/IncludeElement.cs --- a/Implab.ServiceHost/Unity/IncludeElement.cs +++ b/Implab.ServiceHost/Unity/IncludeElement.cs @@ -6,7 +6,7 @@ namespace Implab.ServiceHost.Unity { [XmlAttribute("href")] public string Href { get; set; } - public override void Visit(ContainerContext context) { + public override void Visit(ContainerBuilder context) { context.Visit(this); } } diff --git a/Implab.ServiceHost/Unity/InjectionParameterElement.cs b/Implab.ServiceHost/Unity/InjectionParameterElement.cs --- a/Implab.ServiceHost/Unity/InjectionParameterElement.cs +++ b/Implab.ServiceHost/Unity/InjectionParameterElement.cs @@ -7,10 +7,6 @@ namespace Implab.ServiceHost.Unity { [XmlAttribute("type")] public string TypeName { get; set; } - internal abstract object Resolve(InjectionValueContext context); - - public virtual Type ResolveParameterType(InjectionValueContext context) { - return context.ResolveType(TypeName); - } + internal abstract void Visit(InjectionValueBuilder builder); } } \ No newline at end of file diff --git a/Implab.ServiceHost/Unity/InjectionValueBuilder.cs b/Implab.ServiceHost/Unity/InjectionValueBuilder.cs new file mode 100644 --- /dev/null +++ b/Implab.ServiceHost/Unity/InjectionValueBuilder.cs @@ -0,0 +1,64 @@ +using System; +using System.ComponentModel; +using System.Xml.Serialization; +using Unity.Injection; + +namespace Implab.ServiceHost.Unity { + + public class InjectionValueBuilder { + + readonly TypeResolver m_resolver; + + public Type DefaultType { get; private set; } + + public Type ValueType { get; set; } + + public object Value { get; set; } + + public InjectionParameterValue Injection { + get { + if (Value != null) + return InjectionParameterValue.ToParameter(Value); + + return new InjectionParameter(ValueType, null); + } + } + + internal InjectionValueBuilder(TypeResolver resolver, Type acceptsType) { + m_resolver = resolver; + DefaultType = acceptsType; + } + + public Type ResolveType(string typeSpec) { + if (string.IsNullOrEmpty(typeSpec)) { + if (DefaultType == null) + throw new Exception("The type must be specified"); + return DefaultType; + } + return m_resolver.Resolve(typeSpec); + } + + public void Visit(ITextValue value) { + ValueType = ResolveType(value.TypeName); + + Value = string.IsNullOrEmpty(value.Value) ? + Safe.CreateDefaultValue(ValueType) : + TypeDescriptor.GetConverter(ValueType).ConvertFromString(value.Value); + } + + public void Visit(ISerializedValue value) { + ValueType = ResolveType(value.TypeName); + + var serializer = new XmlSerializer(ValueType); + + using (var reader = value.GetReader()) + Value = new InjectionParameter(ValueType, serializer.Deserialize(reader)); + } + + public void Visit(IDependencyReference value) { + ValueType = ResolveType(value.TypeName); + Value = new ResolvedParameter(ValueType, value.DependencyName); + } + + } +} \ No newline at end of file diff --git a/Implab.ServiceHost/Unity/InjectionValueContext.cs b/Implab.ServiceHost/Unity/InjectionValueContext.cs deleted file mode 100644 --- a/Implab.ServiceHost/Unity/InjectionValueContext.cs +++ /dev/null @@ -1,41 +0,0 @@ -using System; -using Unity.Injection; - -namespace Implab.ServiceHost.Unity { - - public class InjectionValueContext { - - readonly TypeResolver m_resolver; - - public Type AcceptsType { get; private set; } - - public object Value { get; set; } - - internal InjectionValueContext(TypeResolver resolver, Type acceptsType) { - m_resolver = resolver; - AcceptsType = acceptsType; - } - - public Type ResolveType(string typeSpec) { - if (string.IsNullOrEmpty(typeSpec)) { - if (AcceptsType == null) - throw new Exception("The type must be specified"); - return AcceptsType; - } - return m_resolver.Resolve(typeSpec); - } - - public void Visit(ITextValue value) { - - } - - public void Visit(ISerializedValue value) { - - } - - public void Visit(IDependencyReference value) { - Value = new ResolvedParameter() - } - - } -} \ No newline at end of file diff --git a/Implab.ServiceHost/Unity/InstanceRegistrationContext.cs b/Implab.ServiceHost/Unity/InstanceRegistrationContext.cs deleted file mode 100644 --- a/Implab.ServiceHost/Unity/InstanceRegistrationContext.cs +++ /dev/null @@ -1,16 +0,0 @@ -using System; - -namespace Implab.ServiceHost.Unity { - public class InstanceRegistrationContext : RegistrationContext { - - readonly TypeResolver m_typeResolver; - public override TypeResolver Resolver { get { return m_typeResolver; } } - - public InstanceRegistrationContext(TypeResolver resolver, Type registrationType) : base(registrationType) { - Safe.ArgumentNotNull(resolver, nameof(resolver)); - m_typeResolver = resolver; - } - - - } -} \ No newline at end of file diff --git a/Implab.ServiceHost/Unity/LifetimeElement.cs b/Implab.ServiceHost/Unity/LifetimeElement.cs --- a/Implab.ServiceHost/Unity/LifetimeElement.cs +++ b/Implab.ServiceHost/Unity/LifetimeElement.cs @@ -4,7 +4,7 @@ namespace Implab.ServiceHost.Unity { public abstract class LifetimeElement { - public abstract LifetimeManager GetLifetimeManager(ContainerContext ctx); + public abstract LifetimeManager GetLifetimeManager(ContainerBuilder ctx); } } \ No newline at end of file diff --git a/Implab.ServiceHost/Unity/MethodInjectionElement.cs b/Implab.ServiceHost/Unity/MethodInjectionElement.cs --- a/Implab.ServiceHost/Unity/MethodInjectionElement.cs +++ b/Implab.ServiceHost/Unity/MethodInjectionElement.cs @@ -12,7 +12,7 @@ namespace Implab.ServiceHost.Unity { [XmlElement("default", typeof(DefaultParameterElement))] public InjectionParameterElement[] Parameters { get; set; } - internal override void Visit(RegistrationContext context) { + internal override void Visit(TypeRegistrationBuilder context) { context.Visit(this); } } diff --git a/Implab.ServiceHost/Unity/NamespaceElement.cs b/Implab.ServiceHost/Unity/NamespaceElement.cs --- a/Implab.ServiceHost/Unity/NamespaceElement.cs +++ b/Implab.ServiceHost/Unity/NamespaceElement.cs @@ -8,7 +8,7 @@ namespace Implab.ServiceHost.Unity [XmlAttribute("name")] public string Name { get; set; } - public override void Visit(ContainerContext context) { + public override void Visit(ContainerBuilder context) { context.Visit(this); } } diff --git a/Implab.ServiceHost/Unity/PropertyInjectionElement.cs b/Implab.ServiceHost/Unity/PropertyInjectionElement.cs --- a/Implab.ServiceHost/Unity/PropertyInjectionElement.cs +++ b/Implab.ServiceHost/Unity/PropertyInjectionElement.cs @@ -12,7 +12,7 @@ namespace Implab.ServiceHost.Unity { [XmlElement("default", typeof(DefaultParameterElement))] public InjectionParameterElement Value { get; set; } - internal override void Visit(RegistrationContext context) { + internal override void Visit(TypeRegistrationBuilder context) { context.Visit(this); } } diff --git a/Implab.ServiceHost/Unity/RegisterElement.cs b/Implab.ServiceHost/Unity/RegisterElement.cs --- a/Implab.ServiceHost/Unity/RegisterElement.cs +++ b/Implab.ServiceHost/Unity/RegisterElement.cs @@ -20,15 +20,9 @@ namespace Implab.ServiceHost.Unity { [XmlElement("method", typeof(MethodInjectionElement))] public AbstractInjectionElement[] Injectors { get; set; } - public override void Visit(ContainerContext context) { + public override void Visit(ContainerBuilder context) { context.Visit(this); } - - public virtual Type ResolveImplementationType(ContainerContext ctx) { - return string.IsNullOrEmpty(MapToType) ? - ResolveRegistrationType(ctx) : - ctx.Resolve(MapToType); - } } } \ No newline at end of file diff --git a/Implab.ServiceHost/Unity/RegistrationBuilder.cs b/Implab.ServiceHost/Unity/RegistrationBuilder.cs new file mode 100644 --- /dev/null +++ b/Implab.ServiceHost/Unity/RegistrationBuilder.cs @@ -0,0 +1,21 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Linq; +using System.Xml.Serialization; +using Implab.Xml; +using Unity.Injection; +using Unity.Registration; + +namespace Implab.ServiceHost.Unity { + public abstract class RegistrationBuilder { + public Type RegistrationType { + get; + private set; + } + + protected RegistrationBuilder(Type registrationType) { + RegistrationType = registrationType; + } + } +} \ No newline at end of file diff --git a/Implab.ServiceHost/Unity/RegistrationContext.cs b/Implab.ServiceHost/Unity/RegistrationContext.cs deleted file mode 100644 --- a/Implab.ServiceHost/Unity/RegistrationContext.cs +++ /dev/null @@ -1,21 +0,0 @@ -using System; -using System.Collections.Generic; -using System.ComponentModel; -using System.Linq; -using System.Xml.Serialization; -using Implab.Xml; -using Unity.Injection; -using Unity.Registration; - -namespace Implab.ServiceHost.Unity { - public abstract class RegistrationContext { - public Type RegistrationType { - get; - private set; - } - - protected RegistrationContext(Type registrationType) { - RegistrationType = registrationType; - } - } -} \ No newline at end of file diff --git a/Implab.ServiceHost/Unity/SerializedElement.cs b/Implab.ServiceHost/Unity/SerializedElement.cs --- a/Implab.ServiceHost/Unity/SerializedElement.cs +++ b/Implab.ServiceHost/Unity/SerializedElement.cs @@ -4,7 +4,7 @@ using System.Xml.Serialization; namespace Implab.ServiceHost.Unity { - public class SerializedElement : AbstractRegistration { + public class SerializedElement : AbstractRegistration, ISerializedValue { [XmlAttribute("href")] public string Location { get; set; } @@ -14,25 +14,24 @@ namespace Implab.ServiceHost.Unity [XmlAnyElement] public XmlElement[] Content { get; set; } - - public override void Visit(ContainerContext context) { + + string ISerializedValue.TypeName { + get { + return string.IsNullOrEmpty(SerializedType) ? RegistrationType : SerializedType; + } + } + + public override void Visit(ContainerBuilder context) { context.Visit(this); } - public virtual Type ResolveSerializedType(ContainerContext context) { - if(string.IsNullOrEmpty(SerializedType)) - return ResolveRegistrationType(context); - return context.Resolve(SerializedType); - } + public XmlReader GetReader() { + if (!string.IsNullOrEmpty(Location)) + return XmlReader.Create(Location); + if (Content != null && Content.Length > 0) + return Content[0].CreateNavigator().ReadSubtree(); - public virtual object GetValue(ContainerContext context) { - var type = ResolveRegistrationType(context); - if (Content == null || Content.Length == 0) - return Safe.CreateDefaultValue(type); - - var serializer = new XmlSerializer(type); - using(var reader = Content[0].CreateNavigator().ReadSubtree()) - return serializer.Deserialize(reader); + throw new Exception("No content found, expected XML document"); } } } \ No newline at end of file diff --git a/Implab.ServiceHost/Unity/SerializedParameterElement.cs b/Implab.ServiceHost/Unity/SerializedParameterElement.cs --- a/Implab.ServiceHost/Unity/SerializedParameterElement.cs +++ b/Implab.ServiceHost/Unity/SerializedParameterElement.cs @@ -1,18 +1,28 @@ +using System; using System.Xml; using System.Xml.Schema; using System.Xml.Serialization; namespace Implab.ServiceHost.Unity { - public class SerializedParameterElement : InjectionParameterElement { + public class SerializedParameterElement : InjectionParameterElement, ISerializedValue { [XmlAttribute("href")] public string Location { get; set; } [XmlAnyElement] public XmlElement[] Content { get; set; } - internal override object Resolve(RegistrationContext context) { - return context.Resolve(this); + public XmlReader GetReader() { + if (!string.IsNullOrEmpty(Location)) + return XmlReader.Create(Location); + if (Content != null && Content.Length > 0) + return Content[0].CreateNavigator().ReadSubtree(); + + throw new Exception("No content found, expected XML document"); + } + + internal override void Visit(InjectionValueBuilder builder) { + builder.Visit(this); } } } \ No newline at end of file diff --git a/Implab.ServiceHost/Unity/SimgletonLifetimeElement.cs b/Implab.ServiceHost/Unity/SimgletonLifetimeElement.cs --- a/Implab.ServiceHost/Unity/SimgletonLifetimeElement.cs +++ b/Implab.ServiceHost/Unity/SimgletonLifetimeElement.cs @@ -3,7 +3,7 @@ using Unity.Lifetime; namespace Implab.ServiceHost.Unity { public class SimgletonLifetimeElement : LifetimeElement { - public override LifetimeManager GetLifetimeManager(ContainerContext ctx) { + public override LifetimeManager GetLifetimeManager(ContainerBuilder ctx) { return new SingletonLifetimeManager(); } } diff --git a/Implab.ServiceHost/Unity/TypeRegistrationBuilder.cs b/Implab.ServiceHost/Unity/TypeRegistrationBuilder.cs new file mode 100644 --- /dev/null +++ b/Implab.ServiceHost/Unity/TypeRegistrationBuilder.cs @@ -0,0 +1,77 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Unity.Injection; +using Unity.Registration; + +namespace Implab.ServiceHost.Unity { + public class TypeRegistrationBuilder : RegistrationBuilder { + + readonly TypeResolver m_resolver; + + readonly List m_injections = new List(); + + public InjectionMember[] Injections { get { return m_injections.ToArray(); } } + + public Type ImplementationType { + get; + private set; + } + + internal TypeRegistrationBuilder(TypeResolver resolver, Type registrationType, Type implementationType) : base(registrationType) { + ImplementationType = implementationType; + + // when registering a generic mapping, register all generic parameter names as local types + if (ImplementationType.IsGenericTypeDefinition) { + m_resolver = new TypeResolver(resolver); + + foreach (var p in ImplementationType.GetGenericArguments()) + m_resolver.AddMapping(p.Name, p); + } else { + m_resolver = resolver; + } + } + + internal void Visit(ConstructorInjectionElement constructorInjection) { + + + var parameters = constructorInjection.Parameters? + .Select(x => { + var valueBuilder = new InjectionValueBuilder(m_resolver, null); + x.Visit(valueBuilder); + return valueBuilder.Injection; + }) + .ToArray(); + + var injection = parameters != null ? new InjectionConstructor(parameters) : new InjectionConstructor(); + m_injections.Add(injection); + } + + 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); + x.Visit(valueBuilder); + return valueBuilder.Injection; + }) + .ToArray(); + + var injection = parameters != null ? new InjectionMethod(methodInjection.Name, parameters) : new InjectionMethod(methodInjection.Name); + m_injections.Add(injection); + } + + internal void Visit(PropertyInjectionElement propertyInjection) { + 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); + + propertyInjection.Value.Visit(valueContext); + var injection = new InjectionProperty(propertyInjection.Name, valueContext.Injection); + m_injections.Add(injection); + } + } +} \ No newline at end of file diff --git a/Implab.ServiceHost/Unity/TypeRegistrationContext.cs b/Implab.ServiceHost/Unity/TypeRegistrationContext.cs deleted file mode 100644 --- a/Implab.ServiceHost/Unity/TypeRegistrationContext.cs +++ /dev/null @@ -1,65 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using Unity.Injection; -using Unity.Registration; - -namespace Implab.ServiceHost.Unity { - public class TypeRegistrationContext : RegistrationContext { - - readonly TypeResolver m_resolver; - - readonly List m_injections = new List(); - - public InjectionMember[] Injections { get { return m_injections.ToArray(); } } - - public Type ImplementationType { - get; - private set; - } - - internal TypeRegistrationContext(TypeResolver resolver, Type registrationType, Type implementationType) : base(registrationType) { - ImplementationType = implementationType; - - // when registering a generic mapping, register all generic parameter names as local types - if (ImplementationType.IsGenericTypeDefinition) { - m_resolver = new TypeResolver(resolver); - - foreach (var p in ImplementationType.GetGenericArguments()) - m_resolver.AddMapping(p.Name, p); - } else { - m_resolver = resolver; - } - } - - internal void Visit(ConstructorInjectionElement constructorInjection) { - var valueContext = new InjectionValueContext(m_resolver, null); - - var parameters = constructorInjection.Parameters?.Select(x => x.Resolve(valueContext)).ToArray(); - - var injection = parameters != null ? new InjectionConstructor(parameters) : new InjectionConstructor(); - m_injections.Add(injection); - } - - internal void Visit(MethodInjectionElement methodInjection) { - var valueContext = new InjectionValueContext(m_resolver, null); - - var parameters = methodInjection.Parameters?.Select(x => x.Resolve(valueContext)).ToArray(); - - var injection = parameters != null ? new InjectionMethod(methodInjection.Name, parameters) : new InjectionMethod(methodInjection.Name); - m_injections.Add(injection); - } - - internal void Visit(PropertyInjectionElement propertyInjection) { - 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 InjectionValueContext(m_resolver, propertyType); - - var parameter = propertyInjection.Value.Resolve(valueContext); - var injection = new InjectionProperty(propertyInjection.Name, parameter); - m_injections.Add(injection); - } - } -} \ No newline at end of file diff --git a/Implab.ServiceHost/Unity/ValueElement.cs b/Implab.ServiceHost/Unity/ValueElement.cs --- a/Implab.ServiceHost/Unity/ValueElement.cs +++ b/Implab.ServiceHost/Unity/ValueElement.cs @@ -3,11 +3,25 @@ using System.Xml.Serialization; namespace Implab.ServiceHost.Unity { public class ValueElement : AbstractRegistration, ITextValue { - [XmlText] [XmlAttribute("value")] public string Value { get; set; } - public override void Visit(ContainerContext context) { + [XmlText] + public string Text { get; set; } + + string ITextValue.Value { + get { + return string.IsNullOrEmpty(Value) ? Text : Value; + } + } + + public string TypeName { + get { + return RegistrationType; + } + } + + public override void Visit(ContainerBuilder context) { context.Visit(this); } } diff --git a/Implab.ServiceHost/Unity/ValueParameterElement.cs b/Implab.ServiceHost/Unity/ValueParameterElement.cs --- a/Implab.ServiceHost/Unity/ValueParameterElement.cs +++ b/Implab.ServiceHost/Unity/ValueParameterElement.cs @@ -1,15 +1,13 @@ using System.Xml.Serialization; -namespace Implab.ServiceHost.Unity -{ - public class ValueParameterElement : InjectionParameterElement - { +namespace Implab.ServiceHost.Unity { + public class ValueParameterElement : InjectionParameterElement, ITextValue { [XmlText] [XmlAttribute("value")] public string Value { get; set; } - internal override object Resolve(RegistrationContext context) { - return context.Resolve(this); + internal override void Visit(InjectionValueBuilder builder) { + builder.Visit(this); } } } \ No newline at end of file