核心概念 · 模块系统
模块系统是 XiHan.Framework 的地基。理解了它,你就理解了整个框架的组织方式。
什么是"模块"
一个模块就是一个继承 XiHanModule 的类。它代表一块可独立安装、可独立启用的能力(一个 NuGet 包通常对应一个模块类)。模块自己负责三件事:
- 注册服务 —— 把自己需要的服务加进 DI 容器
- 声明依赖 —— 用
[DependsOn]说明"我要用哪些别的模块" - 接入生命周期 —— 在合适的时机接入中间件、后台任务等
csharp
using XiHan.Framework.Core.Modularity;
public class MyModule : XiHanModule
{
public override void ConfigureServices(ServiceConfigurationContext context)
{
// 注册服务:context.Services 就是标准的 IServiceCollection
context.Services.AddSingleton<IMyService, MyService>();
}
}[DependsOn]:声明依赖
模块之间不是靠你在 Program.cs 里手动排顺序,而是靠 [DependsOn] 声明依赖关系:
csharp
using XiHan.Framework.Core.Modularity;
using XiHan.Framework.Web.Api;
using XiHan.Framework.Data;
[DependsOn(
typeof(XiHanWebApiModule),
typeof(XiHanDataModule)
)]
public class MyAppModule : XiHanModule
{
}这行声明的含义是:加载 MyAppModule 之前,必须先加载 XiHanWebApiModule 和 XiHanDataModule。而这两个模块又各自 [DependsOn] 更底层的模块……于是整棵依赖树被完整地表达出来。
自动拓扑排序加载
启动时你只需要指定一个根模块:
csharp
await builder.AddApplicationAsync<MyAppModule>();框架会:
- 从根模块出发,沿着
[DependsOn]递归收集所有直接和间接依赖的模块 - 对它们做拓扑排序(被依赖的排在前面)
- 按这个顺序依次调用每个模块的生命周期钩子
text
你只写这一行:
AddApplicationAsync<MyAppModule>()
框架自动展开成有序加载:
Utils → Metadata → Core → Domain.Shared → Domain
→ Data → Application → Web.Core → Web.Api → MyAppModule好处:
- 加/减一块能力 = 加/减一行
[DependsOn],不用管注册顺序 - 依赖图无环、可裁剪,编译期就能发现缺失的模块
- 每个模块可以独立测试、独立发布
自动服务注册
除了模块级别的装配,框架还提供约定式的服务注册:实现了标记接口的类会被自动扫描并注册进 DI,无需逐个 services.AddXxx。
csharp
using XiHan.Framework.Core.DependencyInjection.ServiceLifetimes;
// 实现 ITransientDependency,自动以 Transient 生命周期注册
public class OrderService : IOrderService, ITransientDependency
{
}细节见 依赖注入。
无模块类的包
少数包是纯工具库或分析器,没有模块类,也不参与 [DependsOn]:
XiHan.Framework.Utils—— 零依赖工具库,直接引用、直接调用静态方法XiHan.Framework.Metadata—— 框架元数据常量XiHan.Framework.Analyzers—— Roslyn 分析器,作为Analyzer引用,编译期生效
这些包 dotnet add package 之后即可使用,不需要写 [DependsOn]。
小结
| 概念 | 作用 |
|---|---|
XiHanModule | 模块的基类,一块能力的载体 |
[DependsOn] | 声明模块依赖,驱动自动装配 |
AddApplicationAsync<T> | 指定根模块,收集 + 拓扑排序 + 加载整棵依赖树 |
| 标记接口 | ITransientDependency 等,驱动约定式服务注册 |
