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