##// END OF EJS Templates
preview version of Unity xml configuration
cin -
r272:9d1cca834b05 v3
parent child
Show More
@@ -0,0 +1,119
1 using System;
2 using System.Collections.Generic;
3 using System.ComponentModel;
4 using System.Linq;
5 using System.Xml.Serialization;
6 using Implab.Xml;
7 using Unity.Injection;
8 using Unity.Registration;
9
10 namespace Implab.ServiceHost.Unity {
11 class RegistrationContext {
12 readonly TypeResolver m_resolver;
13
14 List<InjectionMember> m_injections = new List<InjectionMember>();
15
16 Type m_defaultType;
17
18 public Type RegistrationType {
19 get;
20 private set;
21 }
22
23 public Type ImplementationType {
24 get;
25 private set;
26 }
27
28 public RegistrationContext(TypeResolver resolver, string typeSpec, string implSpec) {
29 RegistrationType = resolver.Resolve(string.IsNullOrEmpty(typeSpec) ? implSpec : typeSpec);
30
31
32 ImplementationType = string.IsNullOrEmpty(implSpec) ? RegistrationType : resolver.Resolve(implSpec);
33
34 if (RegistrationType.IsGenericTypeDefinition) {
35 m_resolver = new TypeResolver(resolver);
36
37 foreach (var p in ImplementationType.GetGenericArguments())
38 m_resolver.AddMapping(p.Name, p);
39 } else {
40 m_resolver = resolver;
41 }
42
43
44 }
45
46 public InjectionMember[] Injections {
47 get {
48 return m_injections.ToArray();
49 }
50 }
51
52 public void Visit(ConstructorInjectionElement constructorInjection) {
53 var parameters = constructorInjection.Parameters?.Select(x => x.Resolve(this)).ToArray();
54
55 var injection = parameters != null ? new InjectionConstructor(parameters) : new InjectionConstructor();
56 m_injections.Add(injection);
57 }
58
59 public void Visit(MethodInjectionElement methodInjection) {
60 var parameters = methodInjection.Parameters?.Select(x => x.Resolve(this)).ToArray();
61
62 var injection = parameters != null ? new InjectionMethod(methodInjection.Name, parameters) : new InjectionMethod(methodInjection.Name);
63 m_injections.Add(injection);
64 }
65
66 public void Visit(PropertyInjectionElement propertyInjection) {
67 if (propertyInjection.Value == null)
68 throw new Exception($"A value value must be specified for the property '{propertyInjection.Name}'");
69
70 try {
71 m_defaultType = RegistrationType.GetProperty(propertyInjection.Name)?.PropertyType;
72
73 var parameter = propertyInjection.Value.Resolve(this);
74 var injection = new InjectionProperty(propertyInjection.Name, parameter);
75 m_injections.Add(injection);
76
77 } finally {
78 m_defaultType = null;
79 }
80
81 }
82
83 Type ResolveParameterType(InjectionParameterElement injectionParameter) {
84 if (string.IsNullOrEmpty(injectionParameter.TypeName)) {
85 if (m_defaultType == null)
86 throw new Exception($"A type must be specified for the parameter {injectionParameter}");
87 return m_defaultType;
88 }
89 return m_resolver.Resolve(injectionParameter.TypeName);
90 }
91
92 public object Resolve(DefaultParameterElement defaultParameter) {
93 var type = ResolveParameterType(defaultParameter);
94
95 return Safe.CreateDefaultValue(type);
96 }
97
98 public object Resolve(ValueParameterElement valueParameter) {
99 var type = ResolveParameterType(valueParameter);
100
101 return TypeDescriptor.GetConverter(type).ConvertFromString(valueParameter.Value);
102 }
103
104 public object Resolve(SerializedParameterElement serializedParameter) {
105 var type = ResolveParameterType(serializedParameter);
106 if (serializedParameter.Content == null || serializedParameter.Content.Length == 0)
107 return Safe.CreateDefaultValue(type);
108
109 var serializer = new XmlSerializer(type);
110 using (var reader = serializedParameter.Content[0].CreateNavigator().ReadSubtree())
111 return serializer.Deserialize(reader);
112 }
113
114 public InjectionParameterValue Resolve(DependencyParameterElement dependencyParameter) {
115 var type = ResolveParameterType(dependencyParameter);
116 return new ResolvedParameter(type, dependencyParameter.DependencyName);
117 }
118 }
119 } No newline at end of file
@@ -1,10 +1,12
1 1 using System;
2 2 using System.Diagnostics;
3 using System.Linq;
3 4 using Implab.Diagnostics;
4 5 using Implab.ServiceHost.Unity;
5 6 using Implab.Xml;
6 7 using Unity;
7 8 using Unity.Injection;
9 using Unity.Registration;
8 10
9 11 namespace Implab.Playground {
10 12
@@ -22,7 +24,11 namespace Implab.Playground {
22 24
23 25 }
24 26
25 public class Container<T> {
27 public interface IContainer<T> {
28 T Instance { get; set; }
29 }
30
31 public class Container<T> : IContainer<T> {
26 32 public Container() {
27 33
28 34 }
@@ -49,8 +55,30 namespace Implab.Playground {
49 55
50 56 ctx.Visit(conf);
51 57
52 Console.WriteLine($"Registrations: {conf.Items.Count}");
58 DisplayContainerRegistrations(container);
59
60 var instace1 = container.Resolve<IContainer<string>>();
61 var instace2 = container.Resolve<IContainer<Foo>>();
62
63 }
53 64
65 static void DisplayContainerRegistrations(IUnityContainer theContainer) {
66 string regName, regType, mapTo, lifetime;
67 Console.WriteLine("Container has {0} Registrations:",
68 theContainer.Registrations.Count());
69 foreach (ContainerRegistration item in theContainer.Registrations) {
70 regType = item.RegisteredType.FullName;
71 mapTo = item.MappedToType.FullName;
72 regName = item.Name ?? "[default]";
73 lifetime = item.LifetimeManager.LifetimeType.Name;
74 if (mapTo != regType) {
75 mapTo = " -> " + mapTo;
76 } else {
77 mapTo = string.Empty;
78 }
79 lifetime = lifetime.Substring(0, lifetime.Length - "LifetimeManager".Length);
80 Console.WriteLine("+ {0}{1} '{2}' {3}", regType, mapTo, regName, lifetime);
81 }
54 82 }
55 83
56 84
@@ -1,7 +1,8
1 1 <?xml version="1.0" encoding="UTF-8"?>
2 2 <container xmlns="http://implab.org/schemas/servicehost/unity.v1.xsd">
3 <namespace name="System"/>
3 4 <namespace name="Implab.Playground"/>
4
5
5 6 <!-- foo1 -->
6 7 <register name="foo1" type="Foo">
7 8 <property name="Name">
@@ -22,17 +23,18
22 23 <register type="Foo">
23 24 </register>
24 25
25 <register type="Container{}">
26 <register provides="IContainer{}" type="Container{}">
26 27 <constructor/>
27 28 <method name="SetInstance">
28 29 <dependency type="T"/>
29 30 </method>
30 31 </register>
31 32
32 <register type="Container{String}">
33 <property name="Instance">
34 <value>Hello!</value>
35 </property>
33 <register provides="IContainer{String}" type="Container{String}">
34 <constructor/>
35 <method name="SetInstance">
36 <value type="String">Hello!</value>
37 </method>
36 38 </register>
37 39
38 40 </container> No newline at end of file
@@ -1,7 +1,8
1 using System;
2
1 3 namespace Implab.ServiceHost.Unity
2 4 {
3 public abstract class AbstractInjectionElement
4 {
5
5 public abstract class AbstractInjectionElement {
6 internal abstract void Visit(RegistrationContext context);
6 7 }
7 8 } No newline at end of file
@@ -27,8 +27,6 namespace Implab.ServiceHost.Unity
27 27 [XmlAttribute("provides")]
28 28 public string ProvidesType { get; set; }
29 29
30 public void Visit(ConfigurationContext context) {
31 context.Visit(this);
32 }
30 public abstract void Visit(ConfigurationContext context);
33 31 }
34 32 } No newline at end of file
@@ -8,6 +8,7 namespace Implab.ServiceHost.Unity {
8 8 using System.Reflection;
9 9 using System.Text;
10 10 using global::Unity;
11 using global::Unity.Registration;
11 12 using Implab.Xml;
12 13 using static Trace<ConfigurationContext>;
13 14
@@ -15,10 +16,8 namespace Implab.ServiceHost.Unity {
15 16
16 17 readonly TypeResolver m_resolver;
17 18
18
19 readonly UnityContainer m_container;
19 20
20 readonly UnityContainer m_container;
21
22 21 public ConfigurationContext(UnityContainer container) {
23 22 m_container = container ?? new UnityContainer();
24 23 m_resolver = new TypeResolver();
@@ -29,8 +28,23 namespace Implab.ServiceHost.Unity {
29 28 return m_resolver.Resolve(TypeReference.Parse(typeReference));
30 29 }
31 30
32 internal void Visit(AbstractRegistration descriptor) {
33
31 internal void Visit(RegisterElement descriptor) {
32 var registrationContext = new RegistrationContext(m_resolver, descriptor.ProvidesType, descriptor.ImplementationType);
33
34 if (descriptor.Injectors != null) {
35 foreach (var injector in descriptor.Injectors) {
36 injector.Visit(registrationContext);
37 }
38 }
39
40 m_container.RegisterType(
41 registrationContext.RegistrationType,
42 registrationContext.ImplementationType,
43 descriptor.Name,
44 descriptor.Lifetime?.GetLifetimeManager(this),
45 registrationContext.Injections
46 );
47
34 48 }
35 49
36 50 internal void Visit(NamespaceElement namespaceElement) {
@@ -8,5 +8,9 namespace Implab.ServiceHost.Unity {
8 8 [XmlElement("serialized", typeof(SerializedParameterElement))]
9 9 [XmlElement("default", typeof(DefaultParameterElement))]
10 10 public InjectionParameterElement[] Parameters { get; set; }
11
12 internal override void Visit(RegistrationContext context) {
13 context.Visit(this);
14 }
11 15 }
12 16 } No newline at end of file
@@ -1,7 +1,8
1 1 namespace Implab.ServiceHost.Unity
2 2 {
3 public class DefaultParameterElement : InjectionParameterElement
4 {
5
3 public class DefaultParameterElement : InjectionParameterElement {
4 internal override object Resolve(RegistrationContext context) {
5 return context.Resolve(this);
6 }
6 7 }
7 8 } No newline at end of file
@@ -1,7 +1,16
1 namespace Implab.ServiceHost.Unity
2 {
3 public class DependencyParameterElement : InjectionParameterElement
4 {
5
1 using System.Xml.Serialization;
2
3 namespace Implab.ServiceHost.Unity {
4 public class DependencyParameterElement : InjectionParameterElement {
5
6 [XmlAttribute("name")]
7 public string DependencyName { get; set; }
8
9 [XmlAttribute("optional")]
10 public bool Optional { get; set; }
11
12 internal override object Resolve(RegistrationContext context) {
13 return context.Resolve(this);
14 }
6 15 }
7 16 } No newline at end of file
@@ -1,9 +1,11
1 1 using System.Xml.Serialization;
2 2
3 3 namespace Implab.ServiceHost.Unity {
4 public class InjectionParameterElement {
4 public abstract class InjectionParameterElement {
5 5
6 6 [XmlAttribute("type")]
7 7 public string TypeName { get; set; }
8
9 internal abstract object Resolve(RegistrationContext context);
8 10 }
9 11 } No newline at end of file
@@ -12,5 +12,8 namespace Implab.ServiceHost.Unity {
12 12 [XmlElement("default", typeof(DefaultParameterElement))]
13 13 public InjectionParameterElement[] Parameters { get; set; }
14 14
15 internal override void Visit(RegistrationContext context) {
16 context.Visit(this);
17 }
15 18 }
16 19 } No newline at end of file
@@ -3,10 +3,17 using System.Xml.Serialization;
3 3 namespace Implab.ServiceHost.Unity {
4 4 public class PropertyInjectionElement : AbstractInjectionElement {
5 5
6 [XmlAttribute("name")]
7 public string Name { get; set; }
8
6 9 [XmlElement("dependency", typeof(DependencyParameterElement))]
7 10 [XmlElement("value", typeof(ValueParameterElement))]
8 11 [XmlElement("serialized", typeof(SerializedParameterElement))]
9 12 [XmlElement("default", typeof(DefaultParameterElement))]
10 13 public InjectionParameterElement Value { get; set; }
14
15 internal override void Visit(RegistrationContext context) {
16 context.Visit(this);
17 }
11 18 }
12 19 } No newline at end of file
@@ -12,13 +12,17 namespace Implab.ServiceHost.Unity {
12 12 /// An optional type which is registered as a service in the container, must be assignable to <see cref="ProvidesType">.
13 13 /// </summary>
14 14 [XmlAttribute("type")]
15 public string ImplementedType { get; set; }
15 public string ImplementationType { get; set; }
16 16
17 17
18 18 [XmlElement("constructor", typeof(ConstructorInjectionElement))]
19 19 [XmlElement("property", typeof(PropertyInjectionElement))]
20 20 [XmlElement("method", typeof(MethodInjectionElement))]
21 21 public AbstractInjectionElement[] Injectors { get; set; }
22
23 public override void Visit(ConfigurationContext context) {
24 context.Visit(this);
25 }
22 26 }
23 27
24 28 } No newline at end of file
@@ -8,5 +8,9 namespace Implab.ServiceHost.Unity
8 8
9 9 [XmlAnyElement]
10 10 public XmlElement[] Content { get; set; }
11
12 internal override object Resolve(RegistrationContext context) {
13 return context.Resolve(this);
14 }
11 15 }
12 16 } No newline at end of file
@@ -24,6 +24,7 namespace Implab.ServiceHost.Unity
24 24 }
25 25
26 26 public TypeResolver(TypeResolver parent) {
27 m_parent = parent;
27 28 m_insertAt = new LinkedListNode<string>(string.Empty);
28 29 m_namespases.AddFirst(m_insertAt);
29 30 }
@@ -58,6 +59,10 namespace Implab.ServiceHost.Unity
58 59 return resolved;
59 60 }
60 61
62 public Type Resolve(string typeSpec) {
63 return Resolve(TypeReference.Parse(typeSpec));
64 }
65
61 66 Type ResolveInternal(TypeReference reference, Type[] args, int argc) {
62 67 var resolved = ProbeInNamespaces(
63 68 String.Join(".", new [] { reference.Namespace, reference.TypeName }.Where(x => !string.IsNullOrEmpty(x)) ),
@@ -1,7 +1,14
1 using System.Xml.Serialization;
2
1 3 namespace Implab.ServiceHost.Unity
2 4 {
3 5 public class ValueParameterElement : InjectionParameterElement
4 6 {
5
7 [XmlText]
8 public string Value { get; set; }
9
10 internal override object Resolve(RegistrationContext context) {
11 return context.Resolve(this);
12 }
6 13 }
7 14 } No newline at end of file
@@ -55,6 +55,13 namespace Implab
55 55 throw new ArgumentOutOfRangeException(paramName);
56 56 }
57 57
58 public static object CreateDefaultValue(Type type) {
59 if (type.IsValueType)
60 return Activator.CreateInstance(type);
61
62 return null;
63 }
64
58 65 [MethodImpl(MethodImplOptions.AggressiveInlining)]
59 66 public static void ArgumentInRange(bool condition, string paramName) {
60 67 if (!condition)
General Comments 3
Under Review
author

Auto status change to "Under Review"

Approved
author

ok, latest stable version should be in default

You need to be logged in to leave comments. Login now