IGeekFan.FreeKit.Web
IGeekFan.FreeKit.Web 提供 ASP.NET Core Host 的服务注册与组合辅助能力。核心入口 UseFreeKit(...) 会装配模块、Autofac、Serilog、FreeSql、缓存、认证、Swagger 等服务;HTTP 中间件、端点映射、模块 Configure 阶段和 OpenTelemetry 仍由 Host 显式调用。
:::info 一句话理解
UseFreeKit(...) 是服务与容器的组合入口,不是完整的 Program.cs。AddFreeKitObservability(...)、app.ConfigureModules()、UsePathBase、Swagger UI、认证授权中间件和 MapHealthChecks 都不在这一行里自动执行。
:::
UseFreeKit 实际做什么
方法签名位于 FreeKit.DI.Extensions 命名空间:
WebApplicationBuilder UseFreeKit(
this WebApplicationBuilder builder,
IDictionary<string, Type> moduleTypeMap,
IEnumerable<Assembly>? extraAssemblies = null,
FreeKitStartupAction? configure = null);
| 阶段 | 当前行为 |
|---|---|
| 模块服务 | 对 moduleTypeMap 中每个 IModuleStartup 调用 AddModule(...),执行 ConfigureServices 并把启动类程序集加入 MVC ApplicationParts |
| 程序集集合 | 合并映射中的启动类程序集与 extraAssemblies,用于 Autofac 基础设施/领域服务扫描、CAP/MediatR 与模块可见性 |
| 容器 | 使用 AutofacServiceProviderFactory,注册 FreeKit Infrastructure 与 Domain Services |
| 日志 | 从配置创建 Serilog Logger,并把 Serilog 接入 Host |
| 基础服务 | 调用 AddFreeKitHost(...) → AddFreeKitComplete(...),按默认 FreeKitDIOptions 注册数据、缓存、认证、API、本地化和分布式事件等能力 |
| Kestrel | 默认把最大请求体设为 1 GB |
| 可选 Host 能力 | 默认注册 FreeScheduler |
它不会自动完成:
AddFreeKitObservability(...);builder.Build()、app.ConfigureModules()或app.Run();- CORS、静态文件、PathBase、异常页、认证/授权中间件;
- Swagger UI / RapiDoc UI 的 URL;
- Controller、gRPC、HealthChecks 等最终端点映射;
- Core、Infrastructure、HttpApi 三层的业务取舍。
当前主 Host 的真实组合
主 Web Host 不是把所有职责塞进一个模块启动类,而是由组合根区分 Core、Infrastructure 与 HttpApi。下面保留 Identity 的关键结构:
WebApplicationBuilder builder = WebApplication.CreateBuilder(args);
// 独立注册;UseFreeKit 不会隐式调用。
builder.Services.AddFreeKitObservability(
builder.Configuration,
builder.Environment,
defaultServiceName: "freekit-host");
// Core:应用/领域服务、Identity/FreeSql、授权处理器、租户中间件等。
builder.Services.AddModule<IdentityModuleStartup>(
"identity",
builder.Configuration);
// E.Modules 包含 identity-inf -> IdentityInfrastructureModuleStartup。
// Web Host 用 HttpApi 替换 identity 映射,Core 已在上方显式注册。
var hostModules = new Dictionary<string, Type>(E.Modules, StringComparer.OrdinalIgnoreCase)
{
["identity"] = typeof(IdentityHttpApiModuleStartup)
};
builder.UseFreeKit(
moduleTypeMap: hostModules,
extraAssemblies: new[]
{
typeof(Program).Assembly,
// HttpApi 负责 Controller;Core 仍需参与 Autofac 服务扫描。
typeof(IdentityModuleStartup).Assembly
});
WebApplication app = builder.Build();
// 执行所有已注册 IModuleStartup.Configure。
app.ConfigureModules().Init();
实际主 Host 对 CmsKit、Identity、Member、Platform 都采用相同模式:先显式注册 Core,再把 hostModules 对应 key 替换为 HttpApi 启动类,并把 Core 程序集加入 extraAssemblies。
| 层 | 示例启动类 | 边界 |
|---|---|---|
| Core | IdentityModuleStartup | 领域/应用服务依赖与核心初始化,不负责 Controller 发现 |
| Infrastructure | IdentityInfrastructureModuleStartup | 文件、设置、附件等横切基础设施;在 E.Modules 中使用 identity-inf key |
| HttpApi | IdentityHttpApiModuleStartup | Controller 所在程序集、SignalR 等 HTTP 专属能力 |
FreeKit.Job.Host 与 FreeKit.MessageHandler.Host 直接使用 E.Modules,因此加载的是共享 Core/Infrastructure 映射,不会因为 UseFreeKit 自动切换成 HttpApi。层次选择是 Host 组合根的责任。
可观测性必须显式注册
三个业务 Host 都在 UseFreeKit(...) 之前调用:
builder.Services.AddFreeKitObservability(
builder.Configuration,
builder.Environment,
defaultServiceName: "freekit-host");
对应配置:
{
"OpenTelemetry": {
"Enabled": true,
"ServiceName": "freekit-host",
"Otlp": {
"Endpoint": "http://otel-collector:4317",
"Protocol": "grpc"
}
}
}
也可使用标准环境变量 OTEL_SERVICE_NAME、OTEL_EXPORTER_OTLP_ENDPOINT、OTEL_EXPORTER_OTLP_PROTOCOL。当前扩展注册 ASP.NET Core、HttpClient、Runtime 与 FreeSql ActivitySource,导出 Trace + Metrics;Serilog 的 OTLP Logs 由日志配置单独负责,不属于该扩展。
详见 可观测性总览。
模块生命周期
UseFreeKit(...) 只执行 ConfigureServices 阶段。需要模块初始化和模块端点时,Host 必须在 Build() 后调用:
app.ConfigureModules();
主 Host 随后调用自有 Init()。不要误以为 UseFreeKit 会自动执行模块 Configure。
FreeKitDIOptions
当前 UseFreeKit(...) 内部创建默认选项,主要开关均默认为 true:
| 选项 | 默认值 | 注册内容 |
|---|---|---|
EnableDataAccess | true | 默认 FreeSql |
EnableCaching | true | Redis 客户端与缓存策略 |
EnableAuthentication | true | 本地 JWT 或 OpenIddict Validation |
EnableApiFeatures | true | MVC、Swagger、IP2Region、解密过滤器 |
EnableLocalization | true | zh-Hans / en-US |
EnableDistributedEvents | true | CAP + MediatR |
EnableFeishu | true | 飞书 SDK / WebSocket |
EnableGrpc | true | gRPC 服务注册 |
EnableJobScheduler | true | FreeScheduler |
EnableIpRateLimiting | true | IP 限流服务 |
EnableEncryption | true | EncryptionMiddleware 服务 |
EnableHealthChecks | true | HealthChecks 服务;路由仍需 Host 映射 |
EnableLargeRequestBody | true | Kestrel 1 GB 请求体上限 |
Validate() 还要求:启用 Job 时必须同时启用数据访问与缓存;启用大请求体时 MaxRequestBodySize 必须大于 0。
:::warning configure 不是前置选项回调
UseFreeKit 的第三个 configure 参数在 Autofac ConfigureContainer 阶段执行,而 AddFreeKitHost(...) 已在此前使用默认选项完成服务注册。它适合补充 Autofac 注册,不应依赖它关闭前面表格中的服务。需要确定性裁剪时,应由自定义组合根预先构造 FreeKitDIOptions 并调用较低层的 AddFreeKitComplete(...) / AddFreeKitHost(...),同时自行完成模块、Autofac、Serilog和管道组装。
:::
认证模式
AddDefaultJsonWebToken(...) 读取 Security:AuthMode:
| 值 | 行为 |
|---|---|
Jwt(默认) | 注册本地 CookieJwtBearerHandler,并按配置注册第三方 OAuth / KitSSO |
OpenIddict | 默认使用 OpenIddict Validation 验证独立 Auth Host 的 Token,同时保留本地 JwtBearer handler |
本地 JWT
JwtSettings 的当前扁平配置键是 Authentication:*,不是旧文档中的 JwtSettings:*:
{
"Authentication": {
"SigningKeys": ["<BASE64_SIGNING_KEY>"],
"ValidIssuer": "https://api.example.com",
"ValidAudience": "https://api.example.com",
"ExpiresTime": 900
},
"Security": {
"AuthMode": "Jwt",
"Cryptography": {
"Key": "<CRYPTOGRAPHY_KEY>"
}
}
}
SigningKeys[0] 必须是可被 Convert.FromBase64String(...) 解析的密钥;真实密钥通过 Secret 管理器或环境变量注入。
CookieJwtBearerHandler 支持从标准 Authorization: Bearer、access_token Cookie,以及 SignalR 常用的 query string 读取 Token。
OpenIddict Validation
{
"Security": {
"AuthMode": "OpenIddict",
"OpenIddict": {
"Validation": {
"Issuer": "https://localhost:7005",
"SigningCertificatePath": "",
"SigningCertificatePassword": "<SIGNING_CERT_PASSWORD>",
"EncryptionCertificatePath": "",
"EncryptionCertificatePassword": "<ENCRYPTION_CERT_PASSWORD>"
}
}
}
}
这是资源服务器验证配置,不包含客户端 ClientId / ClientSecret。交互式 SSO 见 SSO 文档。
Swagger:注册与 UI 分开
UseFreeKit 根据 moduleTypeMap 中的启动类程序集推导 SwaggerProjectNames,并在 API 功能开启时注册 Swagger 服务。但 UI 地址由 Host 手工配置。
主 Host 当前显式公开:
app.UseSwagger();
app.UseSwaggerUI(c =>
{
c.RoutePrefix = "swagger";
c.SwaggerEndpoint($"{vPath}/swagger/v1/swagger.json", "v1");
c.SwaggerEndpoint($"{vPath}/swagger/identity/swagger.json", "identity");
c.SwaggerEndpoint($"{vPath}/swagger/plat/swagger.json", "plat");
c.SwaggerEndpoint($"{vPath}/swagger/cms/swagger.json", "cms");
c.SwaggerEndpoint($"{vPath}/swagger/cms-admin/swagger.json", "cms-admin");
});
主 Compose 设置 /kit_api 后,UI 为 /kit_api/swagger。RapiDoc 同理由 Host 通过 UseRapiDocUI(...) 配置,而非 UseFreeKit 自动映射。
HTTP 管道由 Host 负责
主 Host 的关键顺序以 src/Services/Host/FreeKit.Host/Program.cs 为准:
WebApplication app = builder.Build();
app.ConfigureModules().Init();
app.UsePathBase(new PathString(vPath));
app.UseCors("CorsPolicy");
app.UseStaticFiles();
app.UseDeveloperExceptionPage();
app.UseHttpsRedirection();
app.UseForwardedHeaders();
app.UseSerilogRequestLogging();
app.UseSwagger();
app.UseSwaggerUI();
app.UseRapiDocUI();
app.UseRequestLocalization();
app.UseAuthentication();
app.UseMiddleware<EncryptionMiddleware>();
app.UseCurrentUserAccessor();
app.UseRouting();
app.UseRateLimiter();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
endpoints.MapGrpcService<AccessKeyService>();
endpoints.MapHealthChecks("/health");
});
IdentityHttpApiModuleStartup.Configure(...) 另外映射 /hubs/onlineuser。在 /kit_api PathBase 下,对外地址分别是 /kit_api/health 和 /kit_api/hubs/onlineuser。
基础能力速查
| 能力 | 服务注册入口 | 端点/中间件责任 |
|---|---|---|
| FreeSql | AddDefaultFreeSql(config) | 无自动 HTTP 端点 |
| Redis | AddRedisClient(config).AddCacheStrategy() | 无自动 HTTP 端点 |
| CAP + MediatR | AddFreeKitDistributedEvents(...) | Subscriber 来自组合程序集 |
| HealthChecks | services.AddHealthChecks() | Host 自行 MapHealthChecks(...) |
| Swagger | AddSwagger(...) | Host 自行 UseSwaggerUI(...) / UseRapiDocUI(...) |
| gRPC | services.AddGrpc() | Host 自行 MapGrpcService<T>() |
| Encryption | 注册 EncryptionMiddleware | Host 自行 UseMiddleware<EncryptionMiddleware>() |
| 模块端点 | IModuleStartup.Configure | Host 先调用 app.ConfigureModules() |
源码定位
src/BuildingBlocks/IGeekFan.FreeKit.Web/DI/WebApplicationBuilderExtensions.cs:UseFreeKit与AddFreeKitHostsrc/BuildingBlocks/IGeekFan.FreeKit.Web/DI/FreeKitCoreServiceExtensions.cs:按选项注册基础服务src/BuildingBlocks/IGeekFan.FreeKit.Web/DI/FreeKitDIOptions.cs:开关、默认值与约束src/BuildingBlocks/IGeekFan.FreeKit.Web/DI/ModuleCollectionExtensions.cs:模块映射与程序集集合src/BuildingBlocks/IGeekFan.FreeKit.Web/Extensions/ObservabilityExtensions.cs:显式 OpenTelemetry 注册src/FreeKit/src/IGeekFan.FreeKit.Modularity/ModuleServiceCollection.cs:模块ConfigureServicessrc/FreeKit/src/IGeekFan.FreeKit.Modularity/ModuleApplicationBuilderExtensions.cs:模块Configuresrc/Services/Host/FreeKit.Host/Program.cs:主 Web Host 的真实组合与管道