# 配置管理 (13_Config)
最后更新: 2024-09-20
# 📚 概述
DarkM 框架的配置管理模块提供了统一的配置存储、读取和变更通知机制。支持多种存储提供器(内存、缓存、Redis),并采用依赖注入方式管理所有配置类。
源代码位置: DarkM/src/Framework/Config
# 🏗️ 模块架构
# 项目结构
Config/
├── Config.Abstractions/ # 抽象层(接口、基类)
│ ├── IConfig.cs # 配置接口
│ ├── IConfigProvider.cs # 配置提供器接口
│ ├── IConfigStorageProvider.cs # 配置存储接口
│ ├── IConfigChangeEvent.cs # 配置变更事件接口
│ ├── ConfigDescriptor.cs # 配置描述符
│ ├── ConfigCollection.cs # 配置集合
│ ├── ConfigConfig.cs # 配置的配置
│ ├── ConfigEnumProvider.cs # 配置提供器枚举
│ ├── ConfigType.cs # 配置类型枚举
│ ├── ServiceCollectionExtensions.cs # DI 扩展
│ └── Impl/ # 内置配置实现
│ ├── SystemConfig.cs # 系统配置
│ ├── ComponentConfig.cs # 组件配置
│ └── PathConfig.cs # 路径配置
│
├── Config.Core/ # 核心实现
│ ├── ConfigProvider.cs # 配置提供器
│ └── MemoryConfigStorageProvider.cs # 内存存储提供器
│
├── Config.Cache/ # 缓存实现
│ └── ConfigProvider.cs # 基于缓存的配置提供器
│
└── Config.Redis/ # Redis 实现
└── ConfigProvider.cs # 基于 Redis 的配置提供器
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
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
# 🔧 核心概念
# 1. 配置接口 (IConfig)
所有配置类都必须实现 IConfig 接口:
namespace DarkM.Lib.Config.Abstractions
{
/// <summary>
/// 配置接口,所有配置类都要继承该接口
/// </summary>
public interface IConfig
{
}
}
1
2
3
4
5
6
7
8
9
2
3
4
5
6
7
8
9
示例配置类:
/// <summary>
/// 系统配置
/// </summary>
public class SystemConfig : IConfig
{
/// <summary>
/// 编号
/// </summary>
public string Code { get; set; }
/// <summary>
/// 系统标题
/// </summary>
public string Title { get; set; }
/// <summary>
/// 系统域名
/// </summary>
public string Domain { get; set; }
/// <summary>
/// Logo 文件路径
/// </summary>
public string Logo { get; set; }
/// <summary>
/// 版权声明
/// </summary>
public string Copyright { get; set; }
/// <summary>
/// 用户页 (前端页面路由名称)
/// </summary>
public string UserPage { get; set; }
}
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
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
# 2. 配置类型 (ConfigType)
public enum ConfigType
{
/// <summary>
/// 库配置(框架核心库)
/// </summary>
Library = 0,
/// <summary>
/// 模块配置(业务模块)
/// </summary>
Module = 1
}
1
2
3
4
5
6
7
8
9
10
11
12
2
3
4
5
6
7
8
9
10
11
12
# 3. 配置提供器 (ConfigEnumProvider)
[Description("配置配置器")]
public enum ConfigEnumProvider
{
/// <summary>
/// 默认配置器(内存存储)
/// </summary>
Core,
/// <summary>
/// 使用缓存作为配置存储(与 Cache 配置一致)
/// </summary>
Cache,
/// <summary>
/// 强制使用 Redis 作为配置存储
/// </summary>
Redis
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# 4. 配置描述符 (ConfigDescriptor)
public class ConfigDescriptor
{
/// <summary>
/// 类型(Library/Module)
/// </summary>
public ConfigType Type { get; set; }
/// <summary>
/// 实现类型
/// </summary>
public Type ImplementType { get; set; }
/// <summary>
/// 编码(配置类名去掉 Config 后缀)
/// </summary>
public string Code { get; set; }
/// <summary>
/// 变更事件列表
/// </summary>
public List<Type> ChangeEvents { get; set; } = new List<Type>();
/// <summary>
/// 实例(运行时填充)
/// </summary>
[JsonIgnore]
public IConfig Instance { get; set; }
}
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
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
# 🎯 核心接口
# IConfigProvider(配置提供器)
public interface IConfigProvider
{
/// <summary>
/// 获取指定实现类的实例
/// </summary>
IConfig Get(Type implementType);
/// <summary>
/// 获取配置实例
/// </summary>
/// <param name="code">编码</param>
/// <param name="type">类型</param>
IConfig Get(string code, ConfigType type);
/// <summary>
/// 获取配置实例(泛型)
/// </summary>
TConfig Get<TConfig>() where TConfig : IConfig, new();
/// <summary>
/// 设置配置类
/// </summary>
/// <param name="type">类型</param>
/// <param name="code">编码</param>
/// <param name="json">JSON 数据</param>
bool Set(ConfigType type, string code, string json);
}
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
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
# IConfigStorageProvider(配置存储提供器)
public interface IConfigStorageProvider
{
/// <summary>
/// 获取配置 Json 值
/// </summary>
Task<string> GetJson(ConfigType type, string code);
/// <summary>
/// 保存配置 Json 值
/// </summary>
Task<bool> SaveJson(ConfigType type, string code, string json);
}
1
2
3
4
5
6
7
8
9
10
11
12
2
3
4
5
6
7
8
9
10
11
12
# IConfigChangeEvent(配置变更事件)
public interface IConfigChangeEvent<TConfig> where TConfig : IConfig
{
/// <summary>
/// 配置变更时触发
/// </summary>
Task OnChange(TConfig oldConfig, TConfig newConfig);
}
1
2
3
4
5
6
7
2
3
4
5
6
7
# 🏗️ 依赖注入
# 自动注册机制
框架会自动扫描所有实现 IConfig 的类并注册到 DI 容器:
// ServiceCollectionExtensions.cs
public static class ServiceCollectionExtensions
{
/// <summary>
/// 添加配置项核心服务
/// </summary>
public static IServiceCollection AddConfigCore(this IServiceCollection services)
{
if (services.All(m => m.ServiceType != typeof(IConfigCollection)))
{
services.AddImplementTypes();
}
return services;
}
private static void AddImplementTypes(this IServiceCollection services)
{
var configs = new ConfigCollection();
var assemblies = AssemblyHelper.Load();
// 扫描所有程序集
foreach (var assembly in assemblies)
{
// 查找所有实现 IConfig 的类
var types = assembly.GetTypes()
.Where(m => typeof(IConfig).IsImplementType(m) && typeof(IConfig) != m);
foreach (var implType in types)
{
if (implType.FullName.NotNull())
{
var descriptor = new ConfigDescriptor
{
Type = implType.FullName.Contains(".Lib.")
? ConfigType.Library
: ConfigType.Module,
Code = implType.Name.Replace("Config", ""),
ImplementType = implType
};
configs.Add(descriptor);
}
}
}
// 注入变更事件
services.AddChangedEvent(assemblies, configs);
// 注册配置集合
services.AddSingleton<IConfigCollection>(configs);
}
}
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
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
# 💡 使用示例
# 1. 定义配置类
using DarkM.Lib.Config.Abstractions;
namespace YourModule.Config
{
/// <summary>
/// 邮件配置
/// </summary>
public class EmailConfig : IConfig
{
/// <summary>
/// SMTP 服务器
/// </summary>
public string SmtpServer { get; set; }
/// <summary>
/// SMTP 端口
/// </summary>
public int SmtpPort { get; set; } = 25;
/// <summary>
/// 发件人邮箱
/// </summary>
public string FromEmail { get; set; }
/// <summary>
/// 发件人密码
/// </summary>
public string Password { get; set; }
/// <summary>
/// 是否启用 SSL
/// </summary>
public bool EnableSsl { get; set; } = false;
}
}
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
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
# 2. 监听配置变更
using DarkM.Lib.Config.Abstractions;
public class EmailConfigChangeEvent : IConfigChangeEvent<EmailConfig>
{
private readonly ILogger<EmailConfigChangeEvent> _logger;
public EmailConfigChangeEvent(ILogger<EmailConfigChangeEvent> logger)
{
_logger = logger;
}
public Task OnChange(EmailConfig oldConfig, EmailConfig newConfig)
{
_logger.LogInformation(
"邮件配置已更新:{OldSmtp} -> {NewSmtp}",
oldConfig?.SmtpServer,
newConfig.SmtpServer);
// 重新初始化邮件客户端
// ReinitializeSmtpClient(newConfig);
return Task.CompletedTask;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# 3. 读取配置
public class EmailService
{
private readonly IConfigProvider _configProvider;
private EmailConfig _emailConfig;
public EmailService(IConfigProvider configProvider)
{
_configProvider = configProvider;
_emailConfig = _configProvider.Get<EmailConfig>();
}
public async Task SendEmail(string to, string subject, string body)
{
// 使用配置
using var client = new SmtpClient(_emailConfig.SmtpServer, _emailConfig.SmtpPort)
{
Credentials = new NetworkCredential(_emailConfig.FromEmail, _emailConfig.Password),
EnableSsl = _emailConfig.EnableSsl
};
// 发送邮件...
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# 4. 更新配置
public class ConfigController : ModuleController
{
private readonly IConfigProvider _configProvider;
public ConfigController(IConfigProvider configProvider)
{
_configProvider = configProvider;
}
[HttpPost("update-email")]
public async Task<IResultModel> UpdateEmailConfig([FromBody] EmailConfig config)
{
var json = JsonConvert.SerializeObject(config);
var success = _configProvider.Set(
ConfigType.Module,
"Email",
json);
return success
? ResultModel.Success("配置已更新")
: ResultModel.Error("配置更新失败");
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# 🔧 配置存储提供器
# MemoryConfigStorageProvider(内存存储)
// Config.Core/MemoryConfigStorageProvider.cs
public class MemoryConfigStorageProvider : IConfigStorageProvider
{
private readonly ConcurrentDictionary<string, string> _storage
= new ConcurrentDictionary<string, string>();
public Task<string> GetJson(ConfigType type, string code)
{
var key = $"{type}:{code}";
_storage.TryGetValue(key, out var json);
return Task.FromResult(json);
}
public Task<bool> SaveJson(ConfigType type, string code, string json)
{
var key = $"{type}:{code}";
_storage.AddOrUpdate(key, json, (_, _) => json);
return Task.FromResult(true);
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# Config.Cache(缓存存储)
使用框架的缓存模块作为配置存储,支持分布式缓存。
# Config.Redis(Redis 存储)
强制使用 Redis 作为配置存储,适用于需要持久化的场景。
# 📋 内置配置类
# SystemConfig(系统配置)
public class SystemConfig : IConfig
{
public string Code { get; set; } // 编号
public string Title { get; set; } // 系统标题
public string Domain { get; set; } // 系统域名
public string Logo { get; set; } // Logo 文件路径
public string Copyright { get; set; } // 版权声明
public string UserPage { get; set; } // 用户页路由名称
}
1
2
3
4
5
6
7
8
9
2
3
4
5
6
7
8
9
# ComponentConfig(组件配置)
public class ComponentConfig : IConfig
{
public string Code { get; set; }
public string Name { get; set; }
public string Version { get; set; }
public bool Enabled { get; set; }
public string ConfigJson { get; set; }
}
1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
# PathConfig(路径配置)
public class PathConfig : IConfig
{
public string Code { get; set; }
public string RootPath { get; set; }
public string UploadPath { get; set; }
public string TempPath { get; set; }
public string LogPath { get; set; }
}
1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
# 💡 最佳实践
# 1. 配置类命名规范
// ✅ 推荐:*Config 后缀
public class EmailConfig : IConfig { }
public class SmsConfig : IConfig { }
public class PaymentConfig : IConfig { }
// ❌ 避免:其他命名
public class EmailSettings { }
public class SmsOptions { }
1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
# 2. 配置变更处理
// ✅ 推荐:实现变更事件
public class EmailConfigChangeEvent : IConfigChangeEvent<EmailConfig>
{
public Task OnChange(EmailConfig oldConfig, EmailConfig newConfig)
{
// 1. 记录日志
// 2. 重新初始化相关服务
// 3. 通知其他组件
return Task.CompletedTask;
}
}
// ❌ 避免:轮询检查配置变化
1
2
3
4
5
6
7
8
9
10
11
12
13
2
3
4
5
6
7
8
9
10
11
12
13
# 3. 配置验证
public class EmailConfigChangeEvent : IConfigChangeEvent<EmailConfig>
{
public Task OnChange(EmailConfig oldConfig, EmailConfig newConfig)
{
// 验证新配置
if (newConfig.SmtpPort < 1 || newConfig.SmtpPort > 65535)
{
throw new ArgumentException("SMTP 端口必须在 1-65535 之间");
}
if (string.IsNullOrEmpty(newConfig.FromEmail))
{
throw new ArgumentException("发件人邮箱不能为空");
}
// 验证通过后应用配置
ApplyConfig(newConfig);
return Task.CompletedTask;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# 4. 配置存储选择
| 场景 | 推荐存储 | 说明 |
|---|---|---|
| 开发环境 | Core(内存) | 快速、无需外部依赖 |
| 单机部署 | Cache(内存缓存) | 与框架缓存一致 |
| 集群部署 | Redis | 分布式配置共享 |
| 需要持久化 | Redis | 配置数据持久化 |
# 🔍 常见问题
# Q1: 配置类未被识别?
检查清单:
- ✅ 配置类是否实现了
IConfig接口? - ✅ 配置类所在的程序集是否被加载?
- ✅ 配置类是否有无参构造函数?
- ✅ 配置类属性是否有 getter/setter?
# Q2: 配置变更事件未触发?
检查清单:
- ✅ 变更事件类是否实现了
IConfigChangeEvent<TConfig>? - ✅ 变更事件类是否注册到 DI 容器?
- ✅ 配置更新是否使用
IConfigProvider.Set()方法?
# Q3: 如何选择合适的存储提供器?
// appsettings.json
{
"Config": {
"Provider": "Redis" // Core/Cache/Redis
}
}
1
2
3
4
5
6
2
3
4
5
6
| Provider | 适用场景 | 优点 | 缺点 |
|---|---|---|---|
| Core | 开发环境、单机测试 | 快速、无依赖 | 重启丢失 |
| Cache | 单机部署 | 与缓存一致、性能好 | 重启丢失 |
| Redis | 集群部署、生产环境 | 持久化、分布式共享 | 需要 Redis 服务 |
# 📚 相关文档
# 🔗 参考链接
- 源代码 (opens new window) -
src/Framework/Config - .NET Core 配置 (opens new window)
最后更新: 2024-09-20