XiHan.Framework.Auditing.Database
5.0.0-preview.1
Prefix Reserved
See the version list below for details.
dotnet add package XiHan.Framework.Auditing.Database --version 5.0.0-preview.1
NuGet\Install-Package XiHan.Framework.Auditing.Database -Version 5.0.0-preview.1
<PackageReference Include="XiHan.Framework.Auditing.Database" Version="5.0.0-preview.1" />
<PackageVersion Include="XiHan.Framework.Auditing.Database" Version="5.0.0-preview.1" />
<PackageReference Include="XiHan.Framework.Auditing.Database" />
paket add XiHan.Framework.Auditing.Database --version 5.0.0-preview.1
#r "nuget: XiHan.Framework.Auditing.Database, 5.0.0-preview.1"
#:package XiHan.Framework.Auditing.Database@5.0.0-preview.1
#addin nuget:?package=XiHan.Framework.Auditing.Database&version=5.0.0-preview.1&prerelease
#tool nuget:?package=XiHan.Framework.Auditing.Database&version=5.0.0-preview.1&prerelease
XiHan.Framework.Auditing.Database
auditing.trail@1 的数据库 Provider(Ring 3,role: provider,RFC-0015)。审计事件以 AuditRecord 经 persistence.relational@1 的仓储读写:写入只进有界队列、不阻塞调用路径,后台循环攒够一批或到刷写间隔就一次批量落库;查询按写入序号升序分页。装配后顶替默认的 Auditing.InMemory。
builder.AddXiHan(x => x
.UseFeature(new SqlSugarPersistenceFeature(static (binding, config) =>
{
config.DbType = DbType.PostgreSQL;
config.ConnectionString = binding.ValueOrThrow().Value;
}))
.UseFeature<DatabaseAuditingFeature>());
// EF Core 应用在自己的 DbContext 里登记实体:列长按记录上的 [StringLength] 自动映射,[LongText] 的列按 EF Core 默认建长文本;索引由实体上的 [EntityIndex] 经协议约定建出
modelBuilder.Entity<AuditRecord>(static a =>
{
a.Property(static x => x.DetailsJson).HasColumnType("text");
a.Property(static x => x.ErrorDetailsJson).HasColumnType("text");
a.Property(static x => x.ErrorMessage).HasColumnType("text");
});
modelBuilder.ApplyPersistenceConventions(Database);
// 任何地方查询(不要求活动的工作单元)
var page = await trail.QueryAsync(new AuditQuery { TenantId = "acme", Succeeded = false, PageSize = 50 }, ct);
// 测试或停机前让队列立即落库
await host.Services.GetRequiredService<DatabaseAuditTrail>().FlushAsync(ct);
{
"XiHan": {
"Auditing": {
"Selection": "Protected",
"IncludeSuccesses": true,
"Database": { "QueueCapacity": 10000, "BatchSize": 100, "FlushIntervalSeconds": 1, "LogEvents": true }
}
}
}
| 类型 | 用途 |
|---|---|
DatabaseAuditingFeature |
登记 AuditRecord 的仓储;被选中时把 DatabaseAuditTrail 绑定为 IAuditSink 与 IAuditTrail 并挂 AuditMiddleware(Observe 末尾);启动后运行刷写循环,停止时先停循环再把队列里剩余的事件刷完 |
Trail.AuditRecord |
存储行:Sequence(写入序号)、Timestamp、Action、Succeeded、ErrorCode / ErrorMessageKey / ErrorMessage / ErrorDetailsJson、TraceId、Resource、PrincipalId、TenantId、DetailsJson;只追加,不软删除、无并发戳;租户只是普通列,不实现 IMultiTenant。字符串列显式声明长度([StringLength(n)]:动作 256、错误码 64、消息键 256、trace-id 64、资源 1024、主体 256、租户 128),错误文案与两个 JSON 列是长文本([LongText]),SqlSugar 与 EF Core 都据此建表(ADR-0036) |
Trail.DatabaseAuditTrail |
单例接收器与查询:WriteAsync 进队列,FlushAsync 立即刷写并等待完成,QueryAsync 分页查询;PendingCount / PersistedCount / FailedCount / DroppedCount 计数 |
DatabaseAuditingOptions |
XiHan:Auditing:Database:QueueCapacity(10000)、BatchSize(100)、FlushIntervalSeconds(1)、LogEvents(true) |
审计记录是平台级数据:落库与查询在根提供者的新作用域里进行,不绑定租户分片,独立库租户的记录也落应用默认连接,按租户列区分(RFC-0015,ADR-0057 核对)。
中间件的选项(Selection、IncludeSuccesses)仍在 XiHan:Auditing(AuditingOptions)。
规则
- 有界队列与丢弃:
WriteAsync只是TryWrite进容量QueueCapacity的队列,永不阻塞、永不抛出;队列满了(或特性已停止)新到的事件被丢弃并计入DroppedCount,警告每 10 秒最多记一条并附累计数。LogEvents为真时每条事件(含被丢弃的)先以 Information 级写日志。 - 批量刷写:后台循环攒够
BatchSize条或到FlushInterval就取出一批,一次AddRangeAsync写入;整批异常(存储不可达、提交失败)或逐项被仓储拒绝都只记日志、计入FailedCount并丢弃该批,不重试——审计不能反过来拖垮业务,存储不可用时重试只会堆积。刷写串行:后台循环与FlushAsync互斥。 Sequence的顺序语义:出队时分配,取上一个加一与时钟 UTC 刻度的较大者。同一节点严格递增、与提交顺序一致;不同节点之间按时钟大致有序(时钟差之内的交错不保证),所以跨节点的"写入顺序"是时钟序。UUID v7 的Id同毫秒内不单调,不当顺序用。- 查询与续页:过滤项(
From/To含边界、Action、PrincipalId、TenantId、TraceId、Succeeded)都是 SQL 条件,按Sequence升序,多取一条判断是否有下一页;续页令牌是本页最后一条的Sequence(十进制文本),不可解析 →AUDITING_VALIDATION_001;存储不可达 →AUDITING_UNAVAILABLE_001(reason是异常消息)。可空字符串列只写相等比较,不写!= null。 - 细节与错误:
Details与Error.Details手写成 JSON 对象(不经反射,AOT 兼容),值只允许 JSON 可表示的——null、字符串、布尔、整数与浮点、DateTimeOffset/DateTime/Guid(写成字符串)、JsonElement/JsonNode、嵌套字典与列表,其余按ToString();读回时每个值是JsonElement。失败结果按ErrorCode与ErrorMessageKey还原(new Error(code, key, details),读取方可再按调用方区域翻译);没有键的字面错误用写入时按进程默认区域渲染的ErrorMessage原样还原(Error.Literal)。Error.Inner不持久化。 - 读写不走管道:写入由 Observe 阶段的中间件或后台线程发起,查询不要求调用方有活动的工作单元;每个操作在根提供者的新作用域里直接开一个工作单元(不带租户),返回即提交。不加入调用方的事务:审计在调用结束后才知道结果,失败的调用同样要记。
- 停止:
StopAsync先停循环,再停止接收并把队列里剩余的事件刷完(用宿主给的停止令牌);之后到达的事件按丢弃计数。 - 表结构由应用管理(
InitTables只用于开发与测试):DetailsJson/ErrorDetailsJson/ErrorMessage用长文本类型(text/nvarchar(max)/longtext);索引由实体上的[EntityIndex]声明(ADR-0072),SqlSugar 的InitTables与 EF Core 的ApplyPersistenceConventions(Database)都按它建:IX_AuditRecord_Se(Sequence,排序与续页)、IX_AuditRecord_Ti(Timestamp,时间范围)、IX_AuditRecord_TrId(TraceId)、IX_AuditRecord_TeId_Se((TenantId, Sequence),按租户分页)。Sequence不建唯一索引:不同节点的序号只按时钟大致有序、可能相同,唯一索引会让撞号的整批写入失败、整批审计丢失。按主体查询多的应用自己再加(PrincipalId, Sequence)。
依赖方向
依赖 XiHan.Framework.Auditing.Abstractions 与 XiHan.Framework.Persistence.Abstractions;不引用任何数据库驱动,具体数据库由装配的持久化 Provider 决定。
状态
P5:可用,通过 Auditing.Conformance;对 SQLite(Persistence.SqlSugar)验证实体映射与分页查询。
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net10.0
- Microsoft.Extensions.Caching.Abstractions (>= 10.0.14)
- Microsoft.Extensions.Configuration.Abstractions (>= 10.0.14)
- Microsoft.Extensions.DependencyInjection.Abstractions (>= 10.0.14)
- Microsoft.Extensions.Diagnostics.Abstractions (>= 10.0.14)
- Microsoft.Extensions.Hosting.Abstractions (>= 10.0.14)
- Microsoft.Extensions.Logging.Abstractions (>= 10.0.14)
- Microsoft.Extensions.Options (>= 10.0.14)
- System.Threading.RateLimiting (>= 10.0.14)
- XiHan.Framework.Auditing.Abstractions (>= 5.0.0-preview.1)
- XiHan.Framework.Persistence.Abstractions (>= 5.0.0-preview.1)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 5.0.0-preview.2 | 43 | 11/6/2026 |
| 5.0.0-preview.1 | 41 | 11/4/2026 |