# 模块抽象 (09_Module)
最后更新: 2024-09-20
# 📚 概述
DarkM 采用模块化架构,每个模块都是独立的单元,可以灵活组合和部署。模块抽象层定义了模块的标准接口和描述符。
源代码位置: DarkM/src/Framework/Module
# 🏗️ 模块架构
# 完整目录结构
Module/
├── Module.Abstractions/
│ ├── IModuleDescriptor.cs # 模块描述符接口
│ ├── IModuleCollection.cs # 模块集合接口
│ ├── IModuleAssemblyDescriptor.cs # 模块程序集描述符接口
│ ├── IModuleServicesConfigurator.cs # 模块服务配置器接口
│ ├── IModuleInitializer.cs # 模块初始化器接口
│ ├── ModuleCollectionAbstract.cs # 模块集合抽象基类
│ ├── ModuleInitDataScriptDescriptor.cs # 模块初始化数据脚本描述符
│ └── ModuleEnumDescriptor.cs # 模块枚举描述符
│
├── Module.AspNetCore/
│ ├── ModuleDescriptor.cs # ASP.NET Core 模块描述符
│ ├── ModuleCollection.cs # 模块集合
│ ├── ModuleAssemblyDescriptor.cs # 模块程序集描述符
│ ├── ServiceCollectionExtensions.cs # 服务注册扩展
│ └── ApplicationBuilderExtensions.cs # 应用构建扩展
│
└── Module.GenericHost/
├── ModuleDescriptor.cs # 通用主机模块描述符
├── ModuleCollection.cs # 模块集合
└── ModuleAssemblyDescriptor.cs # 模块程序集描述符
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# 🏗️ 模块结构
# 标准模块项目结构
ModuleName/
├── build/ # 编译配置
│ └── module.build.targets
│
├── Application/ # 应用服务层
│ ├── UserService/
│ │ ├── IUserService.cs
│ │ ├── UserService.cs
│ │ ├── ViewModels/
│ │ └── _MapperConfig.cs
│ └── ...
│
├── Domain/ # 领域层
│ ├── UserModule/
│ │ ├── Models/
│ │ │ └── UserEntity.cs
│ │ ├── Repository/
│ │ │ └── IUserRepository.cs
│ │ └── QueryModels/
│ │ └── UserQueryModel.cs
│
├── Infrastructure/ # 基础设施层
│ ├── Repositories/
│ │ └── UserRepository.cs
│ └── ModuleDescriptor.cs
│
├── Quartz/ # 任务调度层
│ └── Jobs/
│ └── CleanUserJob.cs
│
├── Web/ # 应用层
│ ├── Controllers/
│ │ └── UserController.cs
│ ├── Validators/
│ │ └── UserAddModelValidator.cs
│ └── ModuleInitializer.cs
│
└── WebHost/ # 启动器
├── appsettings.json
└── Program.cs
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
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
# 🔧 核心接口
# 1. IModuleDescriptor(模块描述符)
文件位置: Module.Abstractions/IModuleDescriptor.cs
public interface IModuleDescriptor
{
/// <summary>
/// 模块名称
/// </summary>
string Name { get; }
/// <summary>
/// 模块描述
/// </summary>
string Description { get; }
/// <summary>
/// 模块版本
/// </summary>
Version Version { get; }
/// <summary>
/// 模块依赖
/// </summary>
IEnumerable<string> Dependencies { get; }
/// <summary>
/// 模块程序集描述符
/// </summary>
IModuleAssemblyDescriptor AssemblyDescriptor { get; }
/// <summary>
/// 模块初始化器
/// </summary>
IModuleInitializer Initializer { get; }
/// <summary>
/// 配置服务
/// </summary>
void ConfigureServices(IServiceCollection services, IModuleCollection modules);
/// <summary>
/// 使用模块
/// </summary>
void UseModule(IApplicationBuilder app);
}
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
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
# 2. IModuleCollection(模块集合)
文件位置: Module.Abstractions/IModuleCollection.cs
public interface IModuleCollection : IList<IModuleDescriptor>
{
/// <summary>
/// 获取模块
/// </summary>
IModuleDescriptor Get(string name);
/// <summary>
/// 尝试获取模块
/// </summary>
bool TryGet(string name, out IModuleDescriptor module);
/// <summary>
/// 是否包含模块
/// </summary>
bool Contains(string name);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 3. IModuleAssemblyDescriptor(模块程序集描述符)
文件位置: Module.Abstractions/IModuleAssemblyDescriptor.cs
public interface IModuleAssemblyDescriptor
{
/// <summary>
/// 应用层程序集
/// </summary>
Assembly Application { get; }
/// <summary>
/// 领域层程序集
/// </summary>
Assembly Domain { get; }
/// <summary>
/// 基础设施层程序集
/// </summary>
Assembly Infrastructure { get; }
/// <summary>
/// Web 层程序集
/// </summary>
Assembly Web { get; }
/// <summary>
/// 任务调度层程序集
/// </summary>
Assembly Quartz { get; }
}
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
# 4. IModuleInitializer(模块初始化器)
文件位置: Module.AspNetCore/IModuleInitializer.cs
public interface IModuleInitializer
{
/// <summary>
/// 初始化模块
/// </summary>
/// <param name="serviceProvider">服务提供器</param>
void Initialize(IServiceProvider serviceProvider);
}
1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
# 💡 使用示例
# 1. 定义模块描述符
文件位置: Module.User/ModuleDescriptor.cs
using DarkM.Lib.Module.Abstractions;
using DarkM.Lib.Module.AspNetCore;
using Microsoft.Extensions.DependencyInjection;
using System.Reflection;
namespace DarkM.Module.User
{
/// <summary>
/// 用户模块描述符
/// </summary>
public class ModuleDescriptor : ModuleDescriptorAbstract
{
public override string Name => "User";
public override string Description => "用户管理模块";
public override Version Version => new Version(1, 0, 0);
/// <summary>
/// 声明模块依赖
/// </summary>
public override IEnumerable<string> Dependencies => new[] { "Admin" };
/// <summary>
/// 配置服务
/// </summary>
public override void ConfigureServices(IServiceCollection services, IModuleCollection modules)
{
// 注册服务
services.AddSingleton<IUserService, UserService>();
services.AddSingleton<IUserRepository, UserRepository>();
// 注册验证器
services.AddValidatorsFromAssembly(Assembly.GetExecutingAssembly());
// 注册任务
services.AddSingleton<ITask, CleanUserJob>();
}
/// <summary>
/// 使用模块
/// </summary>
public override void UseModule(IApplicationBuilder app)
{
// 模块初始化逻辑
var logger = app.ApplicationServices.GetRequiredService<ILogger<ModuleDescriptor>>();
logger.LogInformation("User module initialized");
}
}
}
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
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
# 2. 声明模块依赖
public class ModuleDescriptor : ModuleDescriptorAbstract
{
public override string Name => "Order";
/// <summary>
/// 声明依赖
/// </summary>
public override IEnumerable<string> Dependencies => new[] { "Admin", "User", "Product" };
}
1
2
3
4
5
6
7
8
9
2
3
4
5
6
7
8
9
# 3. 模块初始化
文件位置: Module.User.Web/ModuleInitializer.cs
using DarkM.Lib.Module.AspNetCore;
namespace DarkM.Module.User.Web
{
/// <summary>
/// 用户模块初始化器
/// </summary>
public class ModuleInitializer : IModuleInitializer
{
public void Initialize(IServiceProvider serviceProvider)
{
// 模块初始化逻辑
var logger = serviceProvider.GetRequiredService<ILogger<ModuleInitializer>>();
logger.LogInformation("User module initialized");
// 初始化数据
InitializeData(serviceProvider);
}
private void InitializeData(IServiceProvider serviceProvider)
{
// 初始化模块数据
}
}
}
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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
# 4. 模块配置
appsettings.json:
{
"Db": {
"Modules": [
{
// 模块名称
"Name": "Admin",
// 表前缀
"Prefix": "",
// 数据库名称
"Database": "Nm_Admin",
// 自定义连接字符串
"ConnectionString": "",
// 自定义版本号
"Version": ""
},
{
"Name": "User",
"Database": "Nm_User"
}
]
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# 5. 模块依赖排序
框架会自动根据依赖关系对模块进行排序:
// 模块 A 依赖模块 B
public class ModuleADescriptor : ModuleDescriptorAbstract
{
public override string Name => "ModuleA";
public override IEnumerable<string> Dependencies => new[] { "ModuleB" };
}
// 模块 B 无依赖
public class ModuleBDescriptor : ModuleDescriptorAbstract
{
public override string Name => "ModuleB";
public override IEnumerable<string> Dependencies => Array.Empty<string>();
}
// 框架会自动排序:ModuleB -> ModuleA
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 📚 最佳实践
# 1. 模块命名
以 Module 结尾,使用 PascalCase 命名:
// ✅ 推荐
DarkM.Module.User
DarkM.Module.Order
// ❌ 不推荐
DarkM.UserModule
darkm.module.user
1
2
3
4
5
6
7
2
3
4
5
6
7
# 2. 分层清晰
- Application 层:业务逻辑、服务接口
- Domain 层:实体、仓储接口、查询模型
- Infrastructure 层:仓储实现、外部服务
- Web 层:控制器、验证器、过滤器
# 3. 依赖倒置
通过接口依赖,不要直接依赖具体实现:
// ✅ 推荐
private readonly IUserRepository _repository;
// ❌ 不推荐
private readonly UserRepository _repository;
1
2
3
4
5
2
3
4
5
# 4. 模块独立
模块之间尽量低耦合,通过事件或接口通信:
// 使用观察者模式
await _observerHandler.Add<UserEntity>(userId);
1
2
2
# 5. 模块版本管理
使用语义化版本号:
public override Version Version => new Version(1, 0, 0); // Major.Minor.Patch
1
# 6. 模块文档
每个模块应包含 README.md 文档:
# User Module
用户管理模块
## 功能
- 用户注册
- 用户登录
- 用户管理
## 依赖
- Admin 模块
## 配置
```json
{
"Db": {
"Modules": [
{
"Name": "User",
"Database": "Nm_User"
}
]
}
}
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
---
## 🔍 常见问题
### Q1: 模块未加载?
**检查清单:**
1. ✅ 模块名称是否正确
2. ✅ 模块描述符是否实现
3. ✅ 模块程序集是否被扫描
4. ✅ 模块依赖是否满足
**解决方案:**
```csharp
// 检查模块是否被加载
var module = modules.Get("User");
if (module == null)
{
logger.LogError("User module not loaded");
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# Q2: 模块依赖循环?
问题: 模块 A 依赖模块 B,模块 B 依赖模块 A
解决方案:
- 提取公共模块
- 使用事件解耦
- 使用接口解耦
// 使用事件解耦
await _eventBus.PublishAsync(new UserCreatedEvent(userId));
1
2
2
# Q3: 模块服务未注册?
检查:
- ✅ ConfigureServices 是否调用
- ✅ 服务注册代码是否正确
- ✅ 程序集是否被扫描
解决方案:
public override void ConfigureServices(IServiceCollection services, IModuleCollection modules)
{
// 确保服务被注册
services.AddSingleton<IUserService, UserService>();
}
1
2
3
4
5
2
3
4
5
# Q4: 模块初始化顺序?
框架会自动根据依赖关系排序:
// 依赖关系:Admin -> User -> Order
// 初始化顺序:Admin -> User -> Order
1
2
2
# Q5: 如何卸载模块?
解决方案:
- 从配置中移除模块
- 重启应用
- 清理模块数据
{
"Db": {
"Modules": [
// 移除要卸载的模块
// { "Name": "OldModule" }
]
}
}
1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
# 📚 相关文档
# 🔗 参考链接
- 源代码 (opens new window) -
src/Framework/Module - 模块化架构模式 (opens new window)
最后更新: 2024-09-20