##// END OF EJS Templates
code cleanup and refactoring
cin -
r281:e0916ddc9950 v3
parent child
Show More
@@ -0,0 +1,12
1 using System;
2 using System.Xml.Serialization;
3
4 namespace Implab.ServiceHost.Unity {
5 public abstract class AbstractInjectionParameter : IInjectionParameter {
6
7 [XmlAttribute("type")]
8 public string TypeName { get; set; }
9
10 public abstract void Visit(InjectionParameterBuilder builder);
11 }
12 } No newline at end of file
@@ -0,0 +1,17
1 using System;
2 using System.Diagnostics;
3
4 namespace Implab.Diagnostics
5 {
6 public class ChannelAdvertisementEventArgs : EventArgs {
7 internal ChannelAdvertisementEventArgs(object channelId, TraceSource source) {
8 ChannelId = channelId;
9 Source = source;
10 }
11
12 public object ChannelId { get; private set; }
13
14 public TraceSource Source { get; private set; }
15
16 }
17 } No newline at end of file
@@ -1,16 +1,27
1 1 <Project Sdk="Microsoft.NET.Sdk">
2 2
3 3 <PropertyGroup>
4 4 <TargetFrameworks>netstandard2.0;net46</TargetFrameworks>
5 5 <FrameworkPathOverride Condition="'$(TargetFramework)'=='net46'">/usr/lib/mono/4.6-api/</FrameworkPathOverride>
6 <Authors>Sergey Smirnov</Authors>
7 <Title>Implab.SrviceHost library</Title>
8 <Description>Provides simple and flexible XML configuration for the Unity IoC</Description>
9 <Copyright>2018 Sergey Smirnov</Copyright>
10 <Version>1.0.0</Version>
11 <PackageLicenseUrl>https://hg.implab.org/pub/ImplabNet/file/tip/Implab/license.txt</PackageLicenseUrl>
12 <PackageProjectUrl>https://implab.org</PackageProjectUrl>
13 <RepositoryUrl>https://hg.implab.org/pub/ImplabNet/</RepositoryUrl>
14 <RepositoryType>mercurial</RepositoryType>
15 <PackageTags>IoC; Unity; Dependency Injection</PackageTags>
16 <TargetFrameworks>netstandard2.0;net46</TargetFrameworks>
6 17 </PropertyGroup>
7 18
8 19 <ItemGroup>
9 20 <PackageReference Include="Unity" Version="5.8.5" />
10 21 </ItemGroup>
11 22
12 23 <ItemGroup>
13 24 <ProjectReference Include="..\Implab\Implab.csproj" />
14 25 </ItemGroup>
15 26
16 27 </Project>
@@ -1,20 +1,20
1 1 using System.Xml.Serialization;
2 2
3 3 namespace Implab.ServiceHost.Unity
4 4 {
5 public class ArrayParameterElement : InjectionParameterElement {
5 public class ArrayParameterElement : AbstractInjectionParameter {
6 6
7 7 [XmlAttribute("itemsType")]
8 8 public string ItemsType { get; set; }
9 9
10 10 [XmlElement("dependency", typeof(DependencyParameterElement))]
11 11 [XmlElement("value", typeof(ValueParameterElement))]
12 12 [XmlElement("serialized", typeof(SerializedParameterElement))]
13 13 [XmlElement("default", typeof(DefaultParameterElement))]
14 public InjectionParameterElement[] Items { get; set; }
14 public AbstractInjectionParameter[] Items { get; set; }
15 15
16 16 public override void Visit(InjectionParameterBuilder builder) {
17 17 builder.Visit(this);
18 18 }
19 19 }
20 20 } No newline at end of file
@@ -1,17 +1,17
1 1 using System.Xml.Serialization;
2 2
3 3 namespace Implab.ServiceHost.Unity {
4 4 public class ConstructorInjectionElement : AbstractMemberInjection {
5 5
6 6 [XmlElement("dependency", typeof(DependencyParameterElement))]
7 7 [XmlElement("value", typeof(ValueParameterElement))]
8 8 [XmlElement("serialized", typeof(SerializedParameterElement))]
9 9 [XmlElement("default", typeof(DefaultParameterElement))]
10 10 [XmlElement("array", typeof(ArrayParameterElement))]
11 public InjectionParameterElement[] Parameters { get; set; }
11 public AbstractInjectionParameter[] Parameters { get; set; }
12 12
13 13 public override void Visit(TypeRegistrationBuilder builder) {
14 14 builder.Visit(this);
15 15 }
16 16 }
17 17 } No newline at end of file
@@ -1,13 +1,13
1 1 namespace Implab.ServiceHost.Unity
2 2 {
3 public class DefaultParameterElement : InjectionParameterElement {
3 public class DefaultParameterElement : AbstractInjectionParameter {
4 4 public string Value {
5 5 get { return null; }
6 6 }
7 7
8 8 public override void Visit(InjectionParameterBuilder builder) {
9 9 var type = builder.ResolveInjectedValueType(TypeName);
10 10 builder.SetValue(type, Safe.CreateDefaultValue(type));
11 11 }
12 12 }
13 13 } No newline at end of file
@@ -1,17 +1,17
1 1 using System.Xml.Serialization;
2 2
3 3 namespace Implab.ServiceHost.Unity {
4 public class DependencyParameterElement : InjectionParameterElement {
4 public class DependencyParameterElement : AbstractInjectionParameter {
5 5
6 6 [XmlAttribute("name")]
7 7 public string DependencyName { get; set; }
8 8
9 9 [XmlAttribute("optional")]
10 10 public bool Optional { get; set; }
11 11
12 12 public override void Visit(InjectionParameterBuilder builder) {
13 13 var type = builder.ResolveInjectedValueType(TypeName);
14 14 builder.SetDependency(type, DependencyName, Optional);
15 15 }
16 16 }
17 17 } No newline at end of file
@@ -1,72 +1,73
1 1 using System;
2 2 using System.Xml.Serialization;
3 3 using Implab.Components;
4 4
5 5 namespace Implab.ServiceHost.Unity {
6 6 /// <summary>
7 7 /// Расширяет стандартную регистрацию типа до фабрики, вместе с регистрацией
8 8 /// самой фабрики создаются регистрации сервисов, которые она предоставляет.
9 9 /// </summary>
10 10 public class FactoryElement : RegisterElement, ITypeRegistration {
11 11
12 12 /// <summary>
13 13 /// Записи о сервисах, которые создаются данной фабрикой.
14 14 /// </summary>
15 15 /// <remarks>
16 16 /// Сервисы, которые указаны в регистарциях они должны соответсвовать тому,
17 17 /// что фабрика возвращает, но это остается на откуп контейнера
18 18 /// </remarks>
19 19 [XmlElement("provides")]
20 20 public ProvidesElement[] Provides { get; set; }
21 21
22 22 /// <summary>
23 23 /// Переопределяет стандарное поведение регистрации типа в контейнере,
24 24 /// дополняя его регистрацией фабричных методов для получения типов.
25 25 /// </summary>
26 26 /// <param name="builder">Объект для конфигурирования контейнера.</param>
27 27 public override void Visit(ContainerBuilder builder) {
28 28 var factoryType = GetRegistrationType(builder.ResolveType);
29 29
30 30 base.Visit(builder);
31 31
32 32 if (Provides != null && Provides.Length > 0) {
33 33 // если регистрации явно заданы, используеися информация из них
34 34 foreach(var item in Provides) {
35 35 var activator = new FactoryActivator {
36 36 Name = item.RegistrationName,
37 37 RegistrationType = builder.ResolveType(item.RegistrationType),
38 38 FactoryName = Name,
39 FactoryType = factoryType
39 FactoryType = factoryType,
40 Lifetime = item.Lifetime.GetLifetime(builder)
40 41 };
41 42 builder.Visit(activator);
42 43 }
43 44 } else {
44 45 // если регистрация явно не задана, в качестве сервиса для регистрации
45 46 // используется тип создаваемый фабрикой, который будет добавлен в контейнер
46 47 // с темже именем, что и сама фабрика (разные типы могут иметь одно имя для регистрации)
47 48 var providedType = (
48 49 factoryType.IsGenericType && factoryType.GetGenericTypeDefinition() == typeof(IFactory<>) ?
49 50 factoryType :
50 51 factoryType.GetInterface(typeof(IFactory<>).FullName)
51 52 )?
52 53 .GetGenericArguments()[0];
53 54
54 55 // не удалось определеить тип
55 56 if (providedType == null)
56 57 throw new ArgumentException("Failed to determine a type provided by the factory");
57 58
58 59 if (providedType.IsGenericParameter)
59 60 throw new ArgumentException("Can't register a generic type paramter as a service");
60 61
61 62 var activator = new FactoryActivator {
62 63 Name = Name,
63 64 RegistrationType = providedType,
64 65 FactoryName = Name,
65 66 FactoryType = factoryType
66 67 };
67 68
68 69 builder.Visit(activator);
69 70 }
70 71 }
71 72 }
72 73 } No newline at end of file
@@ -1,137 +1,137
1 1 using System;
2 2 using System.Collections;
3 3 using System.Collections.Generic;
4 4 using System.ComponentModel;
5 5 using System.Linq;
6 6 using System.Xml.Serialization;
7 7 using Unity.Injection;
8 8
9 9 namespace Implab.ServiceHost.Unity {
10 10
11 11 public class InjectionParameterBuilder {
12 12
13 13 readonly TypeResolver m_resolver;
14 14
15 15 public Type DefaultType { get; private set; }
16 16
17 17 public Type ValueType { get; private set; }
18 18
19 19 object m_value;
20 20
21 21 public object Value {
22 22 get {
23 23 if (!ValueSpecified)
24 24 throw new InvalidOperationException("The regular value must be set (dependency or array are not situable in this context)");
25 25 return m_value;
26 26 }
27 27 }
28 28
29 29 public bool ValueSpecified { get; private set; }
30 30
31 31 InjectionParameterValue m_injection;
32 32
33 33 public InjectionParameterValue Injection {
34 34 get {
35 35 if (m_injection == null)
36 36 throw new InvalidOperationException("The injection parameter is not specified");
37 37 return m_injection;
38 38 }
39 39 }
40 40
41 41 public bool InjectionSpecified {
42 42 get { return m_injection != null; }
43 43 }
44 44
45 45 internal InjectionParameterBuilder(TypeResolver resolver, Type defaultType) {
46 46 m_resolver = resolver;
47 47 DefaultType = defaultType;
48 48 }
49 49
50 50 public Type ResolveInjectedValueType(string typeSpec) {
51 51 if (string.IsNullOrEmpty(typeSpec)) {
52 52 if (DefaultType == null)
53 53 throw new Exception("The type must be specified");
54 54 return DefaultType;
55 55 }
56 56 return m_resolver.Resolve(typeSpec, true);
57 57 }
58 58
59 59 public Type ResolveType(string typeSpec) {
60 60 return string.IsNullOrEmpty(typeSpec) ? null : m_resolver.Resolve(typeSpec, true);
61 61 }
62 62
63 63 public void SetValue(Type type, object value) {
64 64 Safe.ArgumentNotNull(type, nameof(type));
65 65
66 66 ValueType = type;
67 67 m_value = value;
68 68 ValueSpecified = true;
69 69
70 70 m_injection = new InjectionParameter(type, value);
71 71 }
72 72
73 73 public void SetDependency(Type type, string name, bool optional) {
74 74 Safe.ArgumentNotNull(type, nameof(type));
75 75
76 76 ValueType = type;
77 77 ValueSpecified = false;
78 78 m_value = null;
79 79
80 80 m_injection = optional ? (InjectionParameterValue)new OptionalParameter(type, name) : new ResolvedParameter(type, name);
81 81 }
82 82
83 83 internal void Visit(ArrayParameterElement arrayParameter) {
84 84 Type itemsType = null;
85 85 var arrayType = string.IsNullOrEmpty(arrayParameter.TypeName) ? null : ResolveType(arrayParameter.TypeName);
86 86
87 87 if (arrayType == null)
88 88 arrayType = DefaultType;
89 89
90 90
91 91 if (!string.IsNullOrEmpty(arrayParameter.ItemsType)) {
92 92 itemsType = ResolveType(arrayParameter.ItemsType);
93 93 arrayType = itemsType.MakeArrayType();
94 94 } else {
95 95 itemsType = GetItemsType(arrayType);
96 96 }
97 97
98 98 if (itemsType == null)
99 99 throw new Exception("Failed to determine array elements type");
100 100
101 InjectionParameterValue[] injections = (arrayParameter.Items ?? new InjectionParameterElement[0])
101 InjectionParameterValue[] injections = (arrayParameter.Items ?? new AbstractInjectionParameter[0])
102 102 .Select(x => {
103 103 var builder = new InjectionParameterBuilder(m_resolver, itemsType);
104 104 x.Visit(builder);
105 105 return builder.Injection;
106 106 })
107 107 .ToArray();
108 108
109 109 var array = itemsType.IsGenericParameter ?
110 110 (InjectionParameterValue)new GenericResolvedArrayParameter(itemsType.Name, injections) :
111 111 new ResolvedArrayParameter(itemsType, injections);
112 112
113 113 ValueType = arrayType;
114 114 m_value = null;
115 115 ValueSpecified = false;
116 116
117 117 m_injection = array;
118 118 }
119 119
120 120 Type GetItemsType(Type collectionType) {
121 121 if (collectionType == null)
122 122 return null;
123 123
124 124 Type itemsType = null;
125 125
126 126 if (collectionType.GetGenericTypeDefinition() == typeof(IEnumerable<>)) {
127 127 itemsType = collectionType.GetGenericArguments()[0];
128 128 } else if (collectionType == typeof(IEnumerable)) {
129 129 itemsType = typeof(object);
130 130 } else {
131 131 itemsType = collectionType.GetInterface(typeof(IEnumerable<>).FullName)?.GetGenericArguments()[0];
132 132 }
133 133
134 134 return itemsType;
135 135 }
136 136 }
137 137 } No newline at end of file
@@ -1,20 +1,20
1 1 using System.Xml.Serialization;
2 2
3 3 namespace Implab.ServiceHost.Unity {
4 4 public class MethodInjectionElement : AbstractMemberInjection {
5 5
6 6 [XmlAttribute("name")]
7 7 public string Name { get; set; }
8 8
9 9 [XmlElement("dependency", typeof(DependencyParameterElement))]
10 10 [XmlElement("value", typeof(ValueParameterElement))]
11 11 [XmlElement("serialized", typeof(SerializedParameterElement))]
12 12 [XmlElement("default", typeof(DefaultParameterElement))]
13 13 [XmlElement("array", typeof(ArrayParameterElement))]
14 public InjectionParameterElement[] Parameters { get; set; }
14 public AbstractInjectionParameter[] Parameters { get; set; }
15 15
16 16 public override void Visit(TypeRegistrationBuilder context) {
17 17 context.Visit(this);
18 18 }
19 19 }
20 20 } No newline at end of file
@@ -1,20 +1,20
1 1 using System.Xml.Serialization;
2 2
3 3 namespace Implab.ServiceHost.Unity {
4 4 public class PropertyInjectionElement : AbstractMemberInjection {
5 5
6 6 [XmlAttribute("name")]
7 7 public string Name { get; set; }
8 8
9 9 [XmlElement("dependency", typeof(DependencyParameterElement))]
10 10 [XmlElement("value", typeof(ValueParameterElement))]
11 11 [XmlElement("serialized", typeof(SerializedParameterElement))]
12 12 [XmlElement("default", typeof(DefaultParameterElement))]
13 13 [XmlElement("array", typeof(ArrayParameterElement))]
14 public InjectionParameterElement Value { get; set; }
14 public AbstractInjectionParameter Value { get; set; }
15 15
16 16 public override void Visit(TypeRegistrationBuilder context) {
17 17 context.Visit(this);
18 18 }
19 19 }
20 20 } No newline at end of file
@@ -1,11 +1,17
1 1 using System.Xml.Serialization;
2 2
3 3 namespace Implab.ServiceHost.Unity {
4 4 public class ProvidesElement {
5 5 [XmlAttribute("type")]
6 6 public string RegistrationType { get; set; }
7 7
8 8 [XmlAttribute("name")]
9 9 public string RegistrationName { get; set; }
10
11 [XmlElement("signleton", typeof(SingletonLifetimeElement))]
12 [XmlElement("context", typeof(ContextLifetimeElement))]
13 [XmlElement("container", typeof(ContainerLifetimeElement))]
14 [XmlElement("hierarchy", typeof(HierarchicalLifetimeElement))]
15 public LifetimeElement Lifetime {get; set;}
10 16 }
11 17 } No newline at end of file
@@ -1,33 +1,33
1 1 using System;
2 2 using System.Xml;
3 3 using System.Xml.Schema;
4 4 using System.Xml.Serialization;
5 5
6 6 namespace Implab.ServiceHost.Unity
7 7 {
8 public class SerializedParameterElement : InjectionParameterElement {
8 public class SerializedParameterElement : AbstractInjectionParameter {
9 9 [XmlAttribute("href")]
10 10 public string Location { get; set; }
11 11
12 12 [XmlAnyElement]
13 13 public XmlElement[] Content { get; set; }
14 14
15 15 public XmlReader GetReader() {
16 16 if (!string.IsNullOrEmpty(Location))
17 17 return XmlReader.Create(Location);
18 18 if (Content != null && Content.Length > 0)
19 19 return Content[0].CreateNavigator().ReadSubtree();
20 20
21 21 throw new Exception("No content found, expected XML document");
22 22 }
23 23
24 24 public override void Visit(InjectionParameterBuilder builder) {
25 25 var type = builder.ResolveInjectedValueType(TypeName);
26 26
27 27 var serializer = new XmlSerializer(type);
28 28 using(var reader = GetReader())
29 29 builder.SetValue(type, serializer.Deserialize(reader));
30 30
31 31 }
32 32 }
33 33 } No newline at end of file
@@ -1,21 +1,21
1 1 using System.ComponentModel;
2 2 using System.Xml.Serialization;
3 3
4 4 namespace Implab.ServiceHost.Unity {
5 public class ValueParameterElement : InjectionParameterElement {
5 public class ValueParameterElement : AbstractInjectionParameter {
6 6 [XmlAttribute("value")]
7 7 public string Value { get; set; }
8 8
9 9 [XmlText]
10 10 public string Text { get; set; }
11 11
12 12 string GetTextValue() {
13 13 return string.IsNullOrEmpty(Value) ? Text : Value;
14 14 }
15 15
16 16 public override void Visit(InjectionParameterBuilder builder) {
17 17 var type = builder.ResolveInjectedValueType(TypeName);
18 18 builder.SetValue(type, TypeDescriptor.GetConverter(type).ConvertFromString(GetTextValue()));
19 19 }
20 20 }
21 21 } No newline at end of file
@@ -1,100 +1,113
1 1 # XML Конфигурация IoC контейнера
2 2
3 Данная библиоетка создавалась для загрузки и применения конфигурации к IoC контейнеру, она не предназначена для конфигурирования
3 Библиоетка создавалась для загрузки и применения конфигурации к IoC контейнеру, она не предназначена для конфигурирования
4 4 контейнера во время выполнения, большинство контейнеров уже обладают данным функционалом.
5 5
6 6 На данный момент поддерживается единственный вид контейнера - [Unity Container](https://unitycontainer.github.io/)
7 7
8 Unity уже обладает средствами загрузки конфигурации из XML, данная библиотека позволяет решать следующие задачи
8 Unity уже обладает средствами загрузки конфигурации из XML, данная библиотека реализует аналогичный функционал, кроме того, позволяет решать следующие задачи:
9 9
10 10 - Конфигурация является простым Xml документом, который можно получить из любого источика и не ограничивается `.config` файлами приложения
11 11 - Включение существующе конфигурации `<include href='config.xml'/>` в текущую
12 12 - Поддержка сериализованных объектов в качестве регистраций сервисов и параметров
13 - Описание зависимостей может быть расширено собсвтенными элементами с произвольной структурой
14 - Поддержка специфиакции генериков любой вложенности `Dictionary{Foo,Bar{Int32}}`
13 - Поддержка специфиакции генериков любой вложенности, например `Dictionary{Foo,Bar{Int32}}`
14 - Поддержка фабрик в XML конфигурации
15 - Расширение схемы XML конфигурации собственными элементами
15 16
16 17 ## Общая архитектура
17 18
18 `Implab.ServiceHost.Unity` содержит в себе классы для загрузки и применения XML конфигурации к IoC контейнеру, в частности к Unity.
19 Пространство имен `Implab.ServiceHost.Unity` содержит в себе классы для загрузки и применения XML конфигурации к IoC контейнеру.
20
21 Применение конфигурации к контейнеру состоит из следующих основных шагов:
19 22
20 1. Настраивается схема `ContainerConfigurationSchema`
23 1. Настраивается схема `ContainerConfigurationSchema` XML конфигурации контейнера
21 24 2. Загружается документ и десереализуется в виде `ContainerElement`
22 3. Создается `ContainerBuilder` при помощи которого применяются настройки из `ContainerElement`
25 3. Создается `ContainerBuilder` при помощи которого применяются настройки из `ContainerElement` к контейнеру
23 26
24 `ContainerConfigurationSchema` - определяет элементы которые могут быть использованы в конфигурации контейнера, предоставляет настроенный `XmlSerializer`.
27 Схема `ContainerConfigurationSchema` определяет элементы документа, которые могут быть использованы в конфигурации контейнера, позволяет создать `XmlSerializer`, который используется для загрузки конфигурации.
25 28
26 `ContainerBuilder` - основной класс, который используется для применения конфигурации к контейнеру, добавляет записи регистрации сервисов.
29 `ContainerBuilder` - основной класс, который используется для применения конфигурации к контейнеру, он добавляет записи регистрации сервисов из конфигурации в контейнер.
27 30
28 `ContainerElement` - Корневой элемент конфигурации, который загружается из документа.
31 `ContainerElement` - Конфигурация контейнера, которая загружается из документа, состоит из директив для `ContainerBuilder`, а также из записей регистрации сервисов.
29 32
30 Классы заканчивающиеся словом `Builder` используются для применения конфигурации к контейнеру,
31 классы заканчивающиеся на `Element` содержат информацию о конфигурации и десериализуются из исходного документа.
33 В библиотеки приняты следующие правила именования классов:
34
35 - `***Builder` используются для применения конфигурации к контейнеру,
36 - `***Element` содержат информацию о конфигурации и десериализуются из исходного документа.
32 37
33 38 ## Структура конфигурации контейнера
34 39
35 Элемент верхнего уровня всегда `ContainerElemnt`, он используется для хранения набора элеметов, которые распознаются и выполняются `ContainerBuilder`.
40 Элемент верхнего уровня всегда `container`, он используется для хранения набора элеметов, которые распознаются и выполняются `ContainerBuilder`.
36 41
37 42 Все элементы, входящие в контейнер наследуются от абстрактного класса `ContainerItemElement`,
38 43 который позволяет получить текущий `ContainerBuilder` и выполнить над ним какие-либо действия.
39 44
40 Примерами элементов контейнера могут быть
45 Основные элементы конфигурации контенейра
41 46
42 47 - `<include href='config.xml'/>` - включение конфигурации из указанного места
43 48 - `<namespace name='My.App'/>` - добавление пространства имен для поиска типов
44 49 - `<register type='MyGenericType{}'/>` - добавление в контейнер регистрации типа ``My.App.MyGenericType`1``
50 - `<factory type='IFactory{Foo}' mapTo ='MyFactory'/>` - фабрика, регистрирует свой тип, а также тип `Foo`
51 - `<serialized />` - сериализованный экземпляр объекта, использует `XmlSerializer` для десериализации
52 - `<value />` - значение объекта в виде строки, используется для простых типов
45 53
46 54 Полный набор элементов, доступных для использования в контейнере определяет схема `ContainerConfigurationSchema`,
47 55 разработчик может расширить контейнер совими собственными элементами зарегистрировав их в схеме.
48 56
57 ### register
58
59 О
60
61
49 62 Например, мы используем компоненту `MyHttpClient` для загрузки данных
50 63
51 64 ```xml
52 65 <register type="IClient" mapTo="MyHttpClient">
53 66 <property name="proxy">
54 67 <value>socks5://proxy1.my.company</value>
55 68 </property>
56 69 </register>
57 70 ```
58 71
59 72 При частом использовании можно сделать описание конфигурации несколько проще,
60 73 описав новый эелемент конфигурации
61 74
62 75 ```csharp
63 76 public class MyHttpClientElement : ContainerItemElement {
64 77
65 78 public string Proxy { get; set; }
66 79
67 80 public override void Visit(ContainerBuilder builder) {
68 81 // создаем описание элемента
69 82 var registration = new RegistrationElement {
70 83 RegistrationType = "IClient",
71 84 ImplementationType = "My.App.MyHttpClient",
72 85 Injectors = new [] {
73 86 new PropertyInjectionElement {
74 87 Name = "Proxy",
75 88 Value = ValueParameterElement {
76 89 Value = Proxy
77 90 }
78 91 }
79 92 }
80 93 };
81 94
82 95 // применяем созданное описание к контейнеру
83 96 builder.Visit(registration)
84 97 }
85 98 }
86 99 ```
87 100
88 101 Регистрируем новый элемент в схеме
89 102
90 103 ```csharp
91 104 schema.RegisterContainerElement<MyHttpClientElement>("http");
92 105 ```
93 106
94 107 Используем новый элемент в конфигурации
95 108
96 109 ```xml
97 110 <http>
98 111 <proxy>socks5://proxy1.my.company</propxy>
99 112 </http>
100 113 ``` No newline at end of file
@@ -1,144 +1,161
1 using System;
1 // enable System.Diagnostics trace methods
2 #define TRACE
3
4 using System;
2 5 using System.Collections.Generic;
3 6 using System.Diagnostics;
4 7 using System.Linq;
5 8 using System.Text;
6 9 using System.Threading;
7 10 using System.Threading.Tasks;
8 11
9 12 namespace Implab.Diagnostics {
10 13 public static class Trace<T> {
11 14
12 public static TraceSource TraceSource { get; } = new TraceSource(typeof(T).Name);
15 static Lazy<TraceSource> _traceSource = new Lazy<TraceSource>(CreateChannel, LazyThreadSafetyMode.ExecutionAndPublication);
16
17 static int _nextId;
18
19 static TraceSource CreateChannel() {
20 var id = Interlocked.Increment(ref _nextId);
21 return new TraceSource(typeof(T).Name);
22 }
23
24 public static TraceSource TraceSource { get { return _traceSource.Value; } }
25
26 public static IDisposable Subscribe() {
27
28 throw new NotImplementedException();
29 }
13 30
14 31 #if NETFX_TRACE_BUG
15 32 readonly static AsyncLocal<object> m_currentOperation = new AsyncLocal<object>();
16 33 #endif
17 34
18 35 /// <summary>
19 36 /// Starts the logical operation nested to the current operation nested to the current one.
20 37 /// </summary>
21 38 public static void StartLogicalOperation() {
22 39 Trace.CorrelationManager.StartLogicalOperation();
23 40
24 41 }
25 42
26 43 /// <summary>
27 44 /// Starts the logical operation with the specified name, this name is usefull in logs.
28 45 /// </summary>
29 46 /// <param name="name">Name.</param>
30 47 #if NETFX_TRACE_BUG
31 48 public static void StartLogicalOperation(object name) {
32 49 m_currentOperation.Value = name;
33 50 Trace.CorrelationManager.StartLogicalOperation(name);
34 51 }
35 52 #else
36 53 public static void StartLogicalOperation(object name) {
37 54 Trace.CorrelationManager.StartLogicalOperation(name);
38 55 }
39 56 #endif
40 57
41 58 /// <summary>
42 59 /// Ends the logical operation and restores the previous one.
43 60 /// </summary>
44 61 public static void StopLogicalOperation() {
45 62 Trace.CorrelationManager.StopLogicalOperation();
46 63 }
47 64
48 65 /// <summary>
49 66 /// Writes a debug message.
50 67 /// </summary>
51 68 /// <param name="format">Format.</param>
52 69 /// <param name="arguments">Arguments.</param>
53 70 [Conditional("DEBUG")]
54 71 public static void Debug(string format, params object[] arguments) {
55 72
56 73 }
57 74
58 75 /// <summary>
59 76 /// Writes an informational message.
60 77 /// </summary>
61 78 /// <param name="format">Format.</param>
62 79 /// <param name="arguments">Arguments.</param>
63 80 [Conditional("TRACE")]
64 81 public static void Log(string format, params object[] arguments) {
65 82 TraceSource.TraceEvent(TraceEventType.Information, 0, format, arguments);
66 83 }
67 84
68 85 /// <summary>
69 86 /// Writes a warning message.
70 87 /// </summary>
71 88 /// <param name="format">Format.</param>
72 89 /// <param name="arguments">Arguments.</param>
73 90 public static void Warn(string format, params object[] arguments) {
74 91 TraceSource.TraceEvent(TraceEventType.Warning, 0, format, arguments);
75 92 }
76 93
77 94 /// <summary>
78 95 /// Writes a error message.
79 96 /// </summary>
80 97 /// <param name="format">Format.</param>
81 98 /// <param name="arguments">Arguments.</param>
82 99 public static void Error(string format, params object[] arguments) {
83 100 TraceSource.TraceEvent(TraceEventType.Error, 0, format, arguments);
84 101 }
85 102
86 103 public static void Error(Exception err) {
87 104 TraceSource.TraceData(TraceEventType.Error, 0, err);
88 105 }
89 106
90 107 /// <summary>
91 108 /// This method save the current activity, and transfers to the specified activity,
92 109 /// emits <see cref="TraceEventType.Start"/> and returns a scope of the new
93 110 /// activity.
94 111 /// </summary>
95 112 /// <param name="activityName">The name of the new activity/</param>
96 113 /// <param name="activityId">The identifier of the activity to which
97 114 /// the control will be transferred</param>
98 115 /// <returns>A scope of the new activity, dispose it to transfer
99 116 /// the control back to the original activity.</returns>
100 117 public static ActivityScope TransferActivity(string activityName, Guid activityId) {
101 118 var prev = Trace.CorrelationManager.ActivityId;
102 119
103 120 TraceSource.TraceTransfer(0, "Transfer", activityId);
104 121 Trace.CorrelationManager.ActivityId = activityId;
105 122 TraceSource.TraceEvent(TraceEventType.Start, 0, activityName);
106 123
107 124 return new ActivityScope(TraceSource, prev, 0, activityName);
108 125 }
109 126
110 127 /// <summary>
111 128 /// Emits <see cref="TraceEventType.Start"/> and returns a scope of the
112 129 /// activity.
113 130 /// </summary>
114 131 /// <param name="activityName">The name of the activity to start</param>
115 132 /// <returns>A scope of the new activity, dispose it to emit
116 133 /// <see cref="TraceEventType.Stop"/> for the current activity.</returns>
117 134 public static ActivityScope StartActivity(string activityName) {
118 135 if (Trace.CorrelationManager.ActivityId == Guid.Empty)
119 136 Trace.CorrelationManager.ActivityId = Guid.NewGuid();
120 137
121 138 var prev = Trace.CorrelationManager.ActivityId;
122 139
123 140 TraceSource.TraceEvent(TraceEventType.Start, 0, activityName);
124 141 return new ActivityScope(TraceSource, prev, 0, activityName);
125 142 }
126 143
127 144 /// <summary>
128 145 /// Creates new <see cref="LogicalOperation(string)"/> and calls
129 146 /// to <see cref="CorrelationManager.StartLogicalOperation(object)"/>
130 147 /// passing the created operation as identity. Calls
131 148 /// <see cref="TraceSource.TraceData(TraceEventType, int, object)"/>
132 149 /// to notify listeners on operation start.
133 150 /// </summary>
134 151 /// <param name="name">The name of the logical operation.</param>
135 152 /// <returns>Logical operation scope, disposing it will stop
136 153 /// logical operation and notify trace listeners.</returns>
137 154 public static LogicalOperationScope LogicalOperation(string name) {
138 155 var operation = new LogicalOperation(name);
139 156 TraceSource.TraceData(TraceEventType.Information, TraceEventCodes.StartLogicalOperation, operation);
140 157 StartLogicalOperation(operation);
141 158 return new LogicalOperationScope(TraceSource, operation);
142 159 }
143 160 }
144 161 }
@@ -1,26 +1,26
1 1 <Project Sdk="Microsoft.NET.Sdk">
2 2
3 3 <PropertyGroup>
4 4 <Authors>Sergey Smirnov</Authors>
5 5 <Title>Implab library</Title>
6 6 <Description>Provides some helper clesses like XML serialization helpers, JSON XML reader,
7 7 JSON pull-parser, ECMA-style promises, lightweight synchonization routines Signal
8 8 and SharedLock, Trace helpers on top of System.Diagnostics, ObjectPool etc.
9 9 </Description>
10 10 <Copyright>2012-2018 Sergey Smirnov</Copyright>
11 <Version>3.0.10</Version>
11 <Version>3.0.12</Version>
12 12 <PackageLicenseUrl>https://hg.implab.org/pub/ImplabNet/file/tip/Implab/license.txt</PackageLicenseUrl>
13 13 <PackageProjectUrl>https://implab.org</PackageProjectUrl>
14 14 <RepositoryUrl>https://hg.implab.org/pub/ImplabNet/</RepositoryUrl>
15 15 <RepositoryType>mercurial</RepositoryType>
16 16 <PackageTags>IMPLAB;Json pull-parser;Json Xml;async;diagnostics;serialization;</PackageTags>
17 17 <TargetFrameworks>netstandard2.0;net46</TargetFrameworks>
18 18 <FrameworkPathOverride Condition="'$(TargetFramework)'=='net46' and '$(OSTYPE)'=='linux'">/usr/lib/mono/4.5/</FrameworkPathOverride>
19 19 <DefineConstants Condition="'$(TargetFramework)'=='net46'">NETFX_TRACE_BUG;$(DefineConstants)</DefineConstants>
20 20 </PropertyGroup>
21 21
22 22 <ItemGroup>
23 23 <EmbeddedResource Include="Xml\json.xsl"/>
24 24 </ItemGroup>
25 25
26 26 </Project>
1 NO CONTENT: file was removed
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