Config配置文件自动配置组件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/// <summary>
/// 配置上下文接口
/// </summary>
public interface IConfigurationContext
{
/// <summary>
/// 重载
/// </summary>
void Reload();
/// <summary>
/// 持久化
/// </summary>
void Persistent();
/// <summary>
/// 获取持久化路径
/// </summary>
/// <returns>持久化路径</returns>
string GetPersistentPath();
}
1
2
3
4
5
6
7
8
/// <summary>
/// 配置转换器接口
/// </summary>
public interface IConfigurationConverter
{
object Read(string value);
string Write(object value);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
/// <summary>
/// 配置加密器接口
/// </summary>
public interface IConfigurationEncipher
{
/// <summary>
/// 加密
/// </summary>
/// <param name="plaintext">明文</param>
/// <returns>密文</returns>
string Encrypt(string plaintext);
/// <summary>
/// 解密
/// </summary>
/// <param name="ciphertext">密文</param>
/// <returns>明文</returns>
string Decrypt(string ciphertext);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
/// <summary>
/// 配置上下文基类
/// </summary>
public abstract class ConfigurationContextBase : IConfigurationContext, IDisposable
{
private ConfigurationFileSystemWatcher? _watcher;
protected ConfigurationContextBase()
{
this.Reload();
InitWatcher();
}
/// <summary>
/// 获取持久化路径
/// </summary>
/// <returns>持久化路径</returns>
public abstract string GetPersistentPath();
/// <summary>
/// 持久化
/// </summary>
public void Persistent()
{
System.Configuration.Configuration configuration = GetConfiguration();
PropertyInfo[] propertyInfos = this.GetType().GetProperties();
foreach (var prop in propertyInfos)
{
InjectItem(configuration, prop);
}
configuration.Save(ConfigurationSaveMode.Modified);
}
/// <summary>
/// 重载
/// </summary>
public void Reload()
{
System.Configuration.Configuration configuration = GetConfiguration();
PropertyInfo[] propertyInfos = this.GetType().GetProperties();
foreach (var prop in propertyInfos)
{
ExtractItem(configuration, prop);
}
}

private void InitWatcher()
{
Type type = this.GetType();
ConfigurationContextAttribute? configurationContextAttribute = type.GetCustomAttribute<ConfigurationContextAttribute>();
if (configurationContextAttribute == null)
{
return;
}
bool isHotload = configurationContextAttribute.IsHotload;
if (isHotload)
{
_watcher = new ConfigurationFileSystemWatcher(this);
}
}
private System.Configuration.Configuration GetConfiguration()
{
string persistentPath = this.GetPersistentPath();
string? persistentDirectoryPath = Path.GetDirectoryName(persistentPath);
if (persistentDirectoryPath == null)
{
throw new NotSupportedException($"非法路径:{persistentPath}");
}
if (!Directory.Exists(persistentDirectoryPath))
{
Directory.CreateDirectory(persistentDirectoryPath);
}
ExeConfigurationFileMap configurationFileMap = new ExeConfigurationFileMap();
configurationFileMap.ExeConfigFilename = persistentPath;
System.Configuration.Configuration configObject = ConfigurationManager
.OpenMappedExeConfiguration(configurationFileMap, ConfigurationUserLevel.None);
return configObject;
}
private void InjectItem(System.Configuration.Configuration configuration, PropertyInfo prop)
{
ConfigurationItemAttribute? configurationItemAttribute =
prop.GetCustomAttribute<ConfigurationItemAttribute>();
if (configurationItemAttribute == null)
{
return;
}
object value = prop.GetValue(this) ?? string.Empty;
string key = configurationItemAttribute.Name ?? prop.Name;
if (configurationItemAttribute.Encipher != null)
{
value = configurationItemAttribute
.Encipher
.Encrypt(value.ToString());
}
if (configurationItemAttribute.Converter != null)
{
value = configurationItemAttribute
.Converter
.Write(value);
}
if (configuration.AppSettings.Settings.AllKeys.Contains(key))
{
configuration.AppSettings.Settings[key].Value = value.ToString();
}
else
{
configuration.AppSettings.Settings.Add(key, value.ToString());
}

}
private void ExtractItem(System.Configuration.Configuration configuration, PropertyInfo prop)
{
ConfigurationItemAttribute? configurationItemAttribute =
prop.GetCustomAttribute<ConfigurationItemAttribute>();
if (configurationItemAttribute == null)
{
return;
}
string key = configurationItemAttribute.Name ?? prop.Name;
object? value = configuration.AppSettings.Settings[key]?.Value;
if (configurationItemAttribute.Converter != null)
{
value = configurationItemAttribute
.Converter
.Read(value.ToString());
}
if (value == null)
{
return;
}
if (configurationItemAttribute.Encipher != null)
{
value = configurationItemAttribute.Encipher.Decrypt(value.ToString());
}
object convertedValue = value;
prop.SetValue(this, convertedValue);
}
public void Dispose()
{
_watcher?.Dispose();
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
/// <summary>
/// 配置项特性
/// </summary>
public class ConfigurationItemAttribute : Attribute
{
private string? _name;
private IConfigurationEncipher? _encipher;
private IConfigurationConverter? _converter;
/// <summary>
/// 键值
/// </summary>
public string? Name { get => _name; }
/// <summary>
/// 加密器
/// </summary>
public IConfigurationConverter? Converter { get => _converter; }
/// <summary>
/// 转换器
/// </summary>
public IConfigurationEncipher? Encipher { get => _encipher; }

/// <summary>
/// 配置项特性
/// </summary>
public ConfigurationItemAttribute() { }
/// <summary>
/// 配置项特性
/// </summary>
/// <param name="name">键值</param>
public ConfigurationItemAttribute(string name)
{
_name = name;
}
/// <summary>
/// 配置项特性
/// </summary>
/// <param name="configurationEncipherType">加密器</param>
public ConfigurationItemAttribute(Type? configurationEncipherType = null, Type? configurationConverterType = null)
{
if (configurationEncipherType != null)
{
_encipher = Activator.CreateInstance(configurationEncipherType) as IConfigurationEncipher;
}
if (configurationConverterType != null)
{
_converter = Activator.CreateInstance(configurationConverterType) as IConfigurationConverter;
}
}
/// <summary>
/// 配置项特性
/// </summary>
/// <param name="name">键值</param>
/// <param name="configurationEncipherType">加密器</param>
/// <param name="configurationConverterType">转换器</param>
public ConfigurationItemAttribute(string name, Type configurationEncipherType, Type configurationConverterType)
{
_name = name;
if (configurationEncipherType != null)
{
_encipher = Activator.CreateInstance(configurationEncipherType) as IConfigurationEncipher;
}
if (configurationConverterType != null)
{
_converter = Activator.CreateInstance(configurationConverterType) as IConfigurationConverter;
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
/// <summary>
/// 配置上下文特性
/// </summary>
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = true)]
public class ConfigurationContextAttribute : Attribute
{
private bool _isHotLoad;
public bool IsHotload
{
get { return _isHotLoad; }
set { _isHotLoad = value; }
}
/// <summary>
/// 配置上下文特性
/// </summary>
public ConfigurationContextAttribute() { }
/// <summary>
/// 配置上下文特性
/// </summary>
/// <param name="isHotLoad">是否热重载</param>
public ConfigurationContextAttribute(bool isHotLoad)
{
_isHotLoad = isHotLoad;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
/// <summary>
/// 配置文件监视器
/// </summary>
internal class ConfigurationFileSystemWatcher : FileSystemWatcher
{
private IConfigurationContext _configurationContext;

public ConfigurationFileSystemWatcher(IConfigurationContext configurationContext)
{
if (configurationContext == null)
{
throw new ArgumentNullException(nameof(configurationContext));
}
//if (!File.Exists(configurationContext.GetPersistentPath()))
//{
// throw new FileNotFoundException(configurationContext.GetPersistentPath());
//}
_configurationContext = configurationContext;
string confPath = configurationContext.GetPersistentPath();
string? confFolder = System.IO.Path.GetDirectoryName(confPath);
string confFileName = System.IO.Path.GetFileName(confPath);
if (!string.IsNullOrEmpty(confFolder))
{
this.Path = confFolder;
}
this.Filter = confFileName;
this.NotifyFilter = NotifyFilters.Attributes
| NotifyFilters.CreationTime
| NotifyFilters.LastAccess
| NotifyFilters.LastWrite
| NotifyFilters.Size;
this.Changed += OnChanged;
this.Error += OnError;
this.EnableRaisingEvents = true;
}

private static void OnChanged(object sender, FileSystemEventArgs e)
{
if (e.ChangeType != WatcherChangeTypes.Changed)
{
return;
}
ConfigurationFileSystemWatcher? configurationFileSystemWatcher = sender as ConfigurationFileSystemWatcher;
if (configurationFileSystemWatcher == null)
{
return;
}
Task.Run(async () =>
{
bool isSuccess = false;
int retryNumber = 0;
while (retryNumber < 10 && !isSuccess)
{
try
{
await Task.Delay(500);
configurationFileSystemWatcher._configurationContext.Reload();
isSuccess = true;
}
catch(Exception ex)
{
retryNumber++;
}
}
});
}

private static void OnError(object sender, ErrorEventArgs e)
{
throw e.GetException();
}
}