mirror of
https://github.com/GeWuYou/GFramework.git
synced 2026-05-06 16:16:44 +08:00
- 修复 Godot 模块在附加流程失败时的登记时机,确保后续销毁仍可感知半安装模块 - 更新 ConfigurableLoggerFactory 的 name 空值校验与 minLevel XML 契约,并用可观察行为替换脆弱的反射测试 - 补充 WeakTypePairCache 热路径注释,并新增 Godot 模块安装顺序回归测试
GFramework.Cqrs
GFramework.Cqrs 是 GFramework 的默认 CQRS runtime 包。它在 GFramework.Cqrs.Abstractions 之上提供请求分发、通知发布、流式请求处理、处理器注册、上下文扩展方法,以及消息/处理器基类,面向直接使用 GFramework CQRS 的业务模块。
模块定位
- 这是 CQRS 的“默认实现层”。
- 包内同时承载运行时基础设施和面向业务代码的便捷基类。
- 它依赖
GFramework.Cqrs.Abstractions与GFramework.Core.Abstractions。 - 在标准 GFramework 架构启动路径中,
GFramework.Core的CqrsRuntimeModule会把默认 runtime、处理器注册器与注册服务自动接入容器。
如果你只需要声明跨模块共享的消息契约,而不想依赖默认 runtime,请改为引用 GeWuYou.GFramework.Cqrs.Abstractions。
包关系
推荐的依赖关系如下:
GeWuYou.GFramework.Cqrs.Abstractions- 最小 CQRS 契约层。
GeWuYou.GFramework.Cqrs- 默认 runtime 与业务侧常用基类。
GeWuYou.GFramework.Cqrs.SourceGenerators- 可选。为消费端程序集生成
ICqrsHandlerRegistry,运行时优先走生成注册表;缺失或不适用时,回退到反射扫描。
- 可选。为消费端程序集生成
GFramework.Core- 架构上下文中实际调用
ICqrsRuntime,并在模块初始化时注册 CQRS 基础设施。
- 架构上下文中实际调用
子系统地图
本包当前主要由以下子系统组成:
- 消息基类
Command/CommandBase.csQuery/QueryBase.csRequest/RequestBase.csNotification/NotificationBase.cs
- 处理器基类
Cqrs/CqrsContextAwareHandlerBase.csCqrs/Command/AbstractCommandHandler.csCqrs/Query/AbstractQueryHandler.csCqrs/Notification/AbstractNotificationHandler.csCqrs/Request/AbstractRequestHandler.csCqrs/Request/AbstractStreamRequestHandler.csCqrs/Command/AbstractStreamCommandHandler.csCqrs/Query/AbstractStreamQueryHandler.cs
- 请求管道
Cqrs/Behaviors/LoggingBehavior.csCqrs/Behaviors/PerformanceBehavior.cs- 管道契约定义在
GFramework.Cqrs.Abstractions的IPipelineBehavior<,>
- 默认 runtime 与注册入口
CqrsRuntimeFactory.csInternal/CqrsDispatcher.csInternal/CqrsHandlerRegistrar.csInternal/DefaultCqrsHandlerRegistrar.csInternal/DefaultCqrsRegistrationService.cs
- 生成注册表协作接口
ICqrsHandlerRegistry.csCqrsHandlerRegistryAttribute.csCqrsReflectionFallbackAttribute.cs
- 业务侧扩展入口
Extensions/ContextAwareCqrsExtensions.csExtensions/ContextAwareCqrsCommandExtensions.csExtensions/ContextAwareCqrsQueryExtensions.cs
最小接入路径
在标准 GFramework 架构中,最小接入通常是“安装包 + 定义消息 + 定义处理器 + 通过上下文发送”:
dotnet add package GeWuYou.GFramework.Cqrs
dotnet add package GeWuYou.GFramework.Cqrs.Abstractions
如果你希望减少处理器注册时的反射扫描,再额外安装:
dotnet add package GeWuYou.GFramework.Cqrs.SourceGenerators
示例:
using GFramework.Cqrs.Command;
using GFramework.Cqrs.Cqrs.Command;
using GFramework.Cqrs.Abstractions.Cqrs.Command;
public sealed record CreatePlayerInput(string Name) : ICommandInput;
public sealed class CreatePlayerCommand : CommandBase<CreatePlayerInput, int>
{
public CreatePlayerCommand(CreatePlayerInput input) : base(input)
{
}
}
public sealed class CreatePlayerCommandHandler
: AbstractCommandHandler<CreatePlayerCommand, int>
{
public override ValueTask<int> Handle(
CreatePlayerCommand command,
CancellationToken cancellationToken)
{
var playerModel = Context.GetModel<PlayerModel>();
var playerId = playerModel.Create(command.Input.Name);
return ValueTask.FromResult(playerId);
}
}
在 IContextAware 对象内发送命令:
using GFramework.Cqrs.Extensions;
var playerId = await this.SendAsync(new CreatePlayerCommand(new CreatePlayerInput("Alice")));
在 ArchitectureContext 上也可以直接使用统一 CQRS 入口,例如 SendRequestAsync、SendQueryAsync、PublishAsync 和 CreateStream。
运行时行为
- 请求分发
CqrsDispatcher按请求实际类型解析IRequestHandler<,>,未找到处理器会抛出异常。
- 通知分发
- 通知会分发给所有已注册
INotificationHandler<>;零处理器时默认静默完成。
- 通知会分发给所有已注册
- 流式请求
- 通过
IStreamRequest<TResponse>和IStreamRequestHandler<,>返回IAsyncEnumerable<TResponse>。
- 通过
- 上下文注入
- 处理器基类继承
CqrsContextAwareHandlerBase,runtime 会在分发前注入当前IArchitectureContext。 - 如果处理器或行为需要上下文注入,而当前
ICqrsContext不是IArchitectureContext,默认实现会抛出异常。
- 处理器基类继承
- 管道行为
- 所有已注册
IPipelineBehavior<TRequest, TResponse>会包裹请求处理器执行。 - 当前包内提供了
LoggingBehavior和PerformanceBehavior两个可复用行为。
- 所有已注册
处理器注册与程序集接入
默认注册流程由 ICqrsRegistrationService.RegisterHandlers(IEnumerable<Assembly>) 协调,语义是:
- 同一程序集按稳定键去重,避免重复注册。
- 优先尝试消费端程序集上的
ICqrsHandlerRegistry生成注册器。 - 生成注册器不可用,或声明了
CqrsReflectionFallbackAttribute时,回退到反射扫描。 - 处理器以 transient 方式注册,避免上下文感知处理器在并发请求间共享可变上下文。
如果你走标准 GFramework.Core 架构初始化路径,这些步骤通常由框架自动完成;裸容器或测试环境则需要显式补齐 runtime 与注册入口。
适用边界
- 这个包是默认实现,不是“纯契约包”。
- 处理器基类依赖 runtime 在分发前注入上下文,不适合脱离 dispatcher 直接手动实例化后调用。
- README 中的消息基类和 handler 基类位于
GFramework.Cqrs,接口契约位于GFramework.Cqrs.Abstractions;最小示例通常需要同时引入这两个命名空间层级。
文档入口
- 总体文档:
docs/zh-CN/core/cqrs.md - 契约层说明:
GFramework.Cqrs.Abstractions/README.md