##// END OF EJS Templates
Working on Unity container xml configuration
cin -
r269:ff581cff7003 v3
parent child
Show More
@@ -0,0 +1,7
1 namespace Implab.ServiceHost.Unity
2 {
3 public abstract class AbstractInjectorElement
4 {
5
6 }
7 } No newline at end of file
@@ -0,0 +1,22
1 using System;
2 using System.Xml.Serialization;
3 using Unity.Lifetime;
4 using Unity.Registration;
5
6 namespace Implab.ServiceHost.Unity
7 {
8 public abstract class AbstractRegistration : IConfigurationElement {
9
10 /// <summary>
11 /// An optional name for a registration in the container
12 /// </summary>
13 [XmlAttribute("name")]
14 public string Name {
15 get; set;
16 }
17
18 public void Visit(ConfigurationContext context) {
19 context.Visist(this);
20 }
21 }
22 } No newline at end of file
@@ -0,0 +1,14
1 using System.Xml.Serialization;
2
3 namespace Implab.ServiceHost.Unity
4 {
5 [XmlRoot("assembly", Namespace = Schema.ContainerConfigurationNamespace)]
6 public class AssemblyElement : IConfigurationElement {
7 [XmlAttribute("name")]
8 public string AssemblyName { get; set; }
9
10 public void Visit(ConfigurationContext context) {
11 throw new System.NotImplementedException();
12 }
13 }
14 } No newline at end of file
@@ -0,0 +1,47
1 using System;
2 using System.Collections.Generic;
3 using System.Reflection;
4 using System.Xml;
5 using System.Xml.Serialization;
6 using Implab.Components;
7
8 namespace Implab.ServiceHost.Unity {
9 public class ConfigurationSchema {
10
11 public static ConfigurationSchema Default { get; private set; } = CreateDefault();
12
13 readonly Dictionary<Tuple<string,string>, LazyAndWeak<XmlSerializer>> m_mappings = new Dictionary<Tuple<string, string>, LazyAndWeak<XmlSerializer>>();
14
15 public void DefineMapping(string name, string ns, Type type) {
16 Safe.ArgumentNotEmpty(name, nameof(name));
17 Safe.ArgumentNotNull(type, nameof(type));
18 ns = ns ?? string.Empty;
19 m_mappings[Tuple.Create(name, ns)] = new LazyAndWeak<XmlSerializer>(() => new XmlSerializer(type), true);
20 }
21
22 public void DefineMapping<T>() {
23 var xmlRoot = typeof(T).GetCustomAttribute<XmlRootAttribute>();
24 var ns = xmlRoot?.Namespace;
25 var root = xmlRoot?.ElementName ?? typeof(T).Name;
26 DefineMapping(root, ns, typeof(T));
27 }
28
29 public T Deserialize<T>(XmlReader reader) {
30 reader.MoveToContent();
31 var name = reader.Name;
32 var ns = reader.NamespaceURI;
33
34 return (T)m_mappings[Tuple.Create(name, ns)].Value.Deserialize(reader);
35 }
36
37 static ConfigurationSchema CreateDefault() {
38 var schema = new ConfigurationSchema();
39
40 schema.DefineMapping<RegisterElement>();
41
42 return schema;
43 }
44
45
46 }
47 } No newline at end of file
@@ -0,0 +1,5
1 namespace Implab.ServiceHost.Unity {
2 public class ConstructorInjectorElement : AbstractInjectorElement {
3
4 }
5 } No newline at end of file
@@ -0,0 +1,10
1 using Unity.Lifetime;
2
3 namespace Implab.ServiceHost.Unity
4 {
5 public class ContainerLifetimeElement : LifetimeElement {
6 public override LifetimeManager GetLifetimeManager(ConfigurationContext ctx) {
7 return new ContainerControlledLifetimeManager();
8 }
9 }
10 } No newline at end of file
@@ -0,0 +1,10
1 using Unity.Lifetime;
2
3 namespace Implab.ServiceHost.Unity
4 {
5 public class ContextLifetimeElement : LifetimeElement {
6 public override LifetimeManager GetLifetimeManager(ConfigurationContext ctx) {
7 return new PerResolveLifetimeManager();
8 }
9 }
10 } No newline at end of file
@@ -0,0 +1,10
1 using Unity.Lifetime;
2
3 namespace Implab.ServiceHost.Unity
4 {
5 public class HierarchicalLifetimeElement : LifetimeElement {
6 public override LifetimeManager GetLifetimeManager(ConfigurationContext ctx) {
7 return new HierarchicalLifetimeManager();
8 }
9 }
10 } No newline at end of file
@@ -0,0 +1,5
1 namespace Implab.ServiceHost.Unity {
2 public interface IConfigurationElement {
3 void Visit(ConfigurationContext context);
4 }
5 } No newline at end of file
@@ -0,0 +1,13
1 using System.Xml.Serialization;
2
3 namespace Implab.ServiceHost.Unity {
4 [XmlRoot("include", Namespace = Schema.ContainerConfigurationNamespace)]
5 public class IncludeElement : IConfigurationElement {
6 [XmlAttribute("href")]
7 public string Href { get; set; }
8
9 public void Visit(ConfigurationContext context) {
10 context.Include(Href);
11 }
12 }
13 } No newline at end of file
@@ -0,0 +1,10
1 using Unity.Lifetime;
2
3 namespace Implab.ServiceHost.Unity
4 {
5 public abstract class LifetimeElement
6 {
7 public abstract LifetimeManager GetLifetimeManager(ConfigurationContext ctx);
8
9 }
10 } No newline at end of file
@@ -0,0 +1,13
1 using System.Xml.Serialization;
2
3 namespace Implab.ServiceHost.Unity {
4 public class MethodInjectorElement : AbstractInjectorElement {
5
6 [XmlAttribute("name")]
7 public string Name { get; set; }
8
9 [XmlElement("params")]
10 public MethodInjectorParameter[] Parameters { get; set; }
11
12 }
13 } No newline at end of file
@@ -0,0 +1,7
1 namespace Implab.ServiceHost.Unity
2 {
3 public class MethodInjectorParameter
4 {
5
6 }
7 } No newline at end of file
@@ -0,0 +1,15
1 using System.Xml.Serialization;
2
3 namespace Implab.ServiceHost.Unity
4 {
5 [XmlRoot("namespace", Namespace = Schema.ContainerConfigurationNamespace)]
6 public class NamespaceElement : IConfigurationElement {
7
8 [XmlAttribute("name")]
9 public string Name { get; set; }
10
11 public void Visit(ConfigurationContext context) {
12 throw new System.NotImplementedException();
13 }
14 }
15 } No newline at end of file
@@ -0,0 +1,6
1 namespace Implab.ServiceHost.Unity {
2 public class PropertyInjectorElement : AbstractInjectorElement {
3
4
5 }
6 } No newline at end of file
@@ -0,0 +1,36
1 using System;
2 using System.Xml.Serialization;
3 using Unity.Lifetime;
4 using Unity.Registration;
5
6 namespace Implab.ServiceHost.Unity {
7
8 [XmlRoot("register", Namespace = Schema.ContainerConfigurationNamespace)]
9 public class RegisterElement : AbstractRegistration {
10
11 /// <summary>
12 /// An optional type specification for the service registration,
13 /// must be assignable from the type specified by <see cref="ImplementedType"/>
14 /// </summary>
15 [XmlAttribute("provides")]
16 public string ProvidesType { get; set; }
17
18 /// <summary>
19 /// The type which is registered as a service in the container.
20 /// </summary>
21 [XmlAttribute("type")]
22 public string ImplementedType { get; set; }
23
24 [XmlElement("signleton", typeof(SimgletonLifetimeElement))]
25 [XmlElement("context", typeof(ContextLifetimeElement))]
26 [XmlElement("container", typeof(ContainerLifetimeElement))]
27 [XmlElement("hierarchy", typeof(HierarchicalLifetimeElement))]
28 public LifetimeElement Lifetime {get; set;}
29
30 [XmlElement("constructor", typeof(ConstructorInjectorElement))]
31 [XmlElement("property", typeof(PropertyInjectorElement))]
32 [XmlElement("method", typeof(MethodInjectorElement))]
33 public AbstractInjectorElement[] Injectors { get; set; }
34 }
35
36 } No newline at end of file
@@ -0,0 +1,10
1 using Unity.Lifetime;
2
3 namespace Implab.ServiceHost.Unity
4 {
5 public class SimgletonLifetimeElement : LifetimeElement {
6 public override LifetimeManager GetLifetimeManager(ConfigurationContext ctx) {
7 return new SingletonLifetimeManager();
8 }
9 }
10 } No newline at end of file
@@ -1,53 +1,48
1 1 using System;
2 2 using System.Diagnostics;
3 3 using Implab.Diagnostics;
4 4 using Implab.ServiceHost.Unity;
5 5 using Implab.Xml;
6 6 using Unity;
7 7 using Unity.Injection;
8 8
9 9 namespace Implab.Playground {
10 10
11 11 public class Foo {
12
13 public class Bar {
14
15 }
16
12 17 public int IntValue { get; set; }
13 18
14 19 public string StringValue { get; set; }
15 20
16 21 }
17 22
18 23 public class Container<T> {
19 24 public Container() {
20 25
21 26 }
22 27
23 28 public Container(T instance) {
24 29 Instance = instance;
25 30 }
26 31
27 32 public T Instance { get; set; }
28 33 }
29 34
30 35 public class Program {
31 36
32 37 static void Main(string[] args) {
33 38 var container = new UnityContainer();
34 39
35 var listener = new SimpleTraceListener(Console.Out);
36 Trace<ConfigurationContext>.TraceSource.Switch.Level = SourceLevels.All;
37 Trace<ConfigurationContext>.TraceSource.Listeners.Add(listener);
38
39 var c = new Container<int>();
40 var conf = SerializationHelpers.DeserializeFromFile<ContainerElement>("data/sample.xml");
40 41
41 var cts = new ConfigurationContext();
42 cts.AddNamespace("System");
43 cts.AddNamespace("System.Collections.Generic");
44 cts.AddNamespace("Implab.Playground");
42 Console.WriteLine($"Registrations: {conf.Registrations.Count}");
45 43
46 Console.WriteLine(c.GetType().FullName);
47
48 cts.Resolve("Container{Int32}");
49 44 }
50 45
51 46
52 47 }
53 48 }
@@ -1,10 +1,10
1 1 <?xml version="1.0" encoding="UTF-8"?>
2 2 <container xmlns="http://implab.org/schemas/servicehost/unity.v1.xsd">
3 3 <!-- foo1 -->
4 <register name="foo1" provides="IFoo" type="Foo">
4 <register name="foo1" type="Foo">
5 5 </register>
6 6
7 7 <!-- foo2 -->
8 <register name="foo2" provides="IFoo" type="Foo">
8 <register name="foo2" type="Foo">
9 9 </register>
10 10 </container> No newline at end of file
@@ -1,81 +1,101
1 1 using System;
2 2 using System.Collections.Generic;
3 3 using System.Text.RegularExpressions;
4 4 using Implab.Diagnostics;
5 5
6 6 namespace Implab.ServiceHost.Unity {
7 7 using System.Linq;
8 using System.Reflection;
8 9 using System.Text;
10 using global::Unity;
9 11 using static Trace<ConfigurationContext>;
10 12
11 13 public class ConfigurationContext {
12 14 Regex _nsRx = new Regex(@"^\w+(\.\w+)*$", RegexOptions.Compiled);
13 15 readonly LinkedList<string> m_namespases = new LinkedList<string>();
14 16
15 17 LinkedListNode<string> m_insertAt;
16 18
17 public ConfigurationContext() {
19 readonly UnityContainer m_container;
20
21 public ConfigurationContext(UnityContainer container) {
22 m_container = container ?? new UnityContainer();
18 23 m_insertAt = new LinkedListNode<string>(string.Empty);
19 24 m_namespases.AddFirst(m_insertAt);
20 25 }
21 26
22 27 public void AddNamespace(string ns) {
23 28 Safe.ArgumentMatch(ns, nameof(ns), _nsRx);
24 29 if (m_insertAt != null)
25 30 m_namespases.AddAfter(m_insertAt, ns);
26 31 else
27 32 m_namespases.AddFirst(ns);
28 33 }
29 34
30 35 public Type Resolve(TypeReference reference) {
31 36 Safe.ArgumentNotNull(reference, nameof(reference));
32 37
33 38 var args = reference.IsGeneric && !reference.IsOpenGeneric ? reference.GenericParameters?.Select(Resolve).ToArray() : null;
34 39 var argc = reference.IsGeneric ? reference.GenericParameters.Length : 0;
35 40
36 41 foreach (var ns in m_namespases) {
37 42 var typeName = FormatName(new [] { ns, reference.Namespace, reference.TypeName}, argc, args, reference.IsArray);
38 43
39 var resolved = Type.GetType(typeName, false);
44 var resolved = ProbeType(typeName);
40 45 if (resolved != null) {
41 Log("Probe succeed {0} in '{1}': {2} -> {3}", reference, ns, typeName, resolved.FullName);
46 Log("Probe succeed {0} in '{1}': {2} -> {3}", reference, ns, typeName, resolved.AssemblyQualifiedName);
42 47 return resolved;
43 48 } else {
44 49 Log("Probe failed {0} in '{1}': {2}", reference, ns, typeName);
45 50 }
46 51 }
47 52
48 53 throw new Exception($"Failed to resolve: {reference}");
49 54 }
50 55
56 Type ProbeType(string typeName) {
57 var assemblies = AppDomain.CurrentDomain.GetAssemblies();
58
59 foreach(var assembly in assemblies) {
60 var type = assembly.GetType(typeName);
61 if (type != null)
62 return type;
63 }
64 return null;
65 }
66
51 67 string FormatName(string[] parts, int argc, Type[] args, bool isArray) {
52 68 var builder = new StringBuilder();
53 69
54 70 builder.Append(String.Join(".", parts.Where(x => !string.IsNullOrEmpty(x))));
55 71 if (argc > 0) {
56 72 builder.Append('`');
57 73 builder.Append(argc);
58 74 }
59 75
60 76 if (args!= null && args.Length > 0) {
61 77 builder.Append('[');
62 builder.Append(string.Join(",", args.Select(x => x.FullName)));
78 builder.Append(string.Join(",", args.Select(x => $"[{x.AssemblyQualifiedName}]")));
63 79 builder.Append(']');
64 80 }
65 81
66 82 if(isArray)
67 83 builder.Append("[]");
68 84
69 85 return builder.ToString();
70 86 }
71 87
72 88 public Type Resolve(string typeReference) {
73 89 return Resolve(TypeReference.Parse(typeReference));
74 90 }
75 91
76 public void Register(ServiceElement descriptor) {
92 public void Visist(AbstractRegistration descriptor) {
93
94 }
95
96 public void Include(string file) {
77 97
78 98 }
79 99
80 100 }
81 101 } No newline at end of file
@@ -1,28 +1,28
1 1 using Implab.Xml;
2 2 using System.Collections.Generic;
3 3 using System.Xml;
4 4 using System.Xml.Schema;
5 5 using System.Xml.Serialization;
6 6
7 7 namespace Implab.ServiceHost.Unity {
8 8 [XmlRoot("container", Namespace = Schema.ContainerConfigurationNamespace)]
9 9 public class ContainerElement : IXmlSerializable {
10 10
11 public List<ServiceElement> Registrations {get; set; } = new List<ServiceElement>();
11 public List<IConfigurationElement> Registrations {get; set; } = new List<IConfigurationElement>();
12 12
13 13 public XmlSchema GetSchema() {
14 14 return null;
15 15 }
16 16
17 17 public void ReadXml(XmlReader reader) {
18 18 while(reader.Read() && reader.NodeType != XmlNodeType.EndElement) {
19 var registration = SerializationHelpers.Deserialize<ServiceElement>(reader);
19 var registration = ConfigurationSchema.Default.Deserialize<IConfigurationElement>(reader);
20 20 Registrations.Add(registration);
21 21 }
22 22 }
23 23
24 24 public void WriteXml(XmlWriter writer) {
25 25 throw new System.NotImplementedException();
26 26 }
27 27 }
28 28 } No newline at end of file
@@ -1,162 +1,161
1 1 using System;
2 2 using System.Collections.Generic;
3 3 using System.Text.RegularExpressions;
4 4
5 5 namespace Implab.ServiceHost.Unity {
6 6 internal class TypeReferenceParser {
7 7 enum TokenType {
8 8 None,
9 9
10 10 Word,
11 11
12 12 Dot,
13 13
14 14 Comma,
15 15
16 16 OpenList,
17 17
18 18 CloseList,
19 19
20 20 Eof
21 21 }
22 22
23 readonly Regex _tokens = new Regex(@"(\w+)|\s*([\.{},\+])\s*");
23 readonly Regex _tokens = new Regex(@"([\w\+]+)|\s*([\.{},])\s*");
24 24
25 25 TokenType m_token;
26 26
27 27 string m_tokenValue;
28 28
29 29 int m_pos;
30 30
31 31 int m_tokenPos;
32 32
33 33 readonly string m_text;
34 34
35 35 TokenType Token { get { return m_token; } }
36 36
37 37 string TokenValue { get { return m_tokenValue; } }
38 38
39 39 int TokenPos { get { return m_tokenPos; } }
40 40
41 41 public TypeReferenceParser(string text) {
42 42 Safe.ArgumentNotEmpty(text, nameof(text));
43 43 m_text = text;
44 44 }
45 45
46 46 bool ReadToken() {
47 47 if (m_pos >= m_text.Length) {
48 48 m_token = TokenType.Eof;
49 49 m_tokenValue = null;
50 50 return false;
51 51 }
52 52
53 53 var m = _tokens.Match(m_text, m_pos);
54 54
55 55 if (m.Success) {
56 56 m_tokenPos = m_pos;
57 57 m_pos += m.Length;
58 58 if (m.Groups[1].Success) {
59 59 m_token = TokenType.Word;
60 60 m_tokenValue = m.Groups[1].Value;
61 61 } else if (m.Groups[2].Success) {
62 62 m_tokenValue = null;
63 63 switch (m.Groups[2].Value) {
64 64 case "{":
65 65 m_token = TokenType.OpenList;
66 66 break;
67 67 case "}":
68 68 m_token = TokenType.CloseList;
69 69 break;
70 70 case ".":
71 case "+":
72 71 m_token = TokenType.Dot;
73 72 break;
74 73 case ",":
75 74 m_token = TokenType.Comma;
76 75 break;
77 76 }
78 77 }
79 78 return true;
80 79 }
81 80 throw new FormatException($"Failed to parse '{m_text}' at pos {m_pos}");
82 81 }
83 82
84 83 public TypeReference Parse() {
85 84 var result = ReadTypeReference();
86 85 if (ReadToken())
87 86 ThrowUnexpectedToken();
88 87 return result;
89 88 }
90 89
91 90 string[] ReadTypeName() {
92 91 var parts = new List<string>();
93 92
94 93 string current = null;
95 94 bool stop = false;
96 95 while ((!stop) && ReadToken()) {
97 96 switch (Token) {
98 97 case TokenType.Word:
99 98 if (current != null)
100 99 ThrowUnexpectedToken();
101 100 current = TokenValue;
102 101 break;
103 102 case TokenType.Dot:
104 103 if (current == null)
105 104 ThrowUnexpectedToken();
106 105 parts.Add(current);
107 106 current = null;
108 107 break;
109 108 default:
110 109 stop = true;
111 110 break;
112 111 }
113 112 }
114 113 if (current != null)
115 114 parts.Add(current);
116 115
117 116 if (parts.Count == 0)
118 117 return null;
119 118
120 119 return parts.ToArray();
121 120 }
122 121
123 122 TypeReference ReadTypeReference() {
124 123
125 124 var parts = ReadTypeName();
126 125 if (parts == null)
127 126 return null;
128 127
129 128 var typeReference = new TypeReference {
130 129 Namespace = string.Join(".", parts, 0, parts.Length - 1),
131 130 TypeName = parts[parts.Length - 1]
132 131 };
133 132
134 133 switch (Token) {
135 134 case TokenType.OpenList:
136 135 typeReference.GenericParameters = ReadTypeReferenceList();
137 136 if (Token != TokenType.CloseList)
138 137 ThrowUnexpectedToken();
139 138 ReadToken();
140 139 break;
141 140 }
142 141
143 142 return typeReference;
144 143 }
145 144
146 145 TypeReference[] ReadTypeReferenceList() {
147 146 var list = new List<TypeReference>();
148 147
149 148 do {
150 149 var typeReference = ReadTypeReference();
151 150 list.Add(typeReference);
152 151 } while (Token == TokenType.Comma);
153 152
154 153 return list.ToArray();
155 154 }
156 155
157 156 void ThrowUnexpectedToken() {
158 157 throw new FormatException($"Unexpected '{Token}' at pos {TokenPos}: -->{m_text.Substring(TokenPos, Math.Min(m_text.Length - TokenPos, 10))}");
159 158 }
160 159
161 160 }
162 161 } No newline at end of file
1 NO CONTENT: file was removed
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