GeWuYou 195c8321a1 feat(cqrs): 添加CQRS命令查询责任分离架构支持
- 实现抽象命令处理器基类支持命令处理
- 添加流式命令处理器基类支持异步流式响应
- 创建查询处理器基类提供统一查询处理接口
- 实现查询基类提供通用查询结构定义
- 扩展架构上下文接口集成CQRS运行时入口
- 定义消息处理器委托支持管道行为处理
- 实现CQRS处理器注册器扫描并注册处理器
- 添加架构模块行为测试验证模块安装功能
- 创建中介器高级特性测试覆盖边界场景
2026-04-14 21:37:32 +08:00

290 lines
13 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using GFramework.Core.Abstractions.Command;
using GFramework.Core.Abstractions.Cqrs;
using GFramework.Core.Abstractions.Environment;
using GFramework.Core.Abstractions.Events;
using GFramework.Core.Abstractions.Model;
using GFramework.Core.Abstractions.Query;
using GFramework.Core.Abstractions.Systems;
using GFramework.Core.Abstractions.Utility;
using ICommand = GFramework.Core.Abstractions.Command.ICommand;
namespace GFramework.Core.Abstractions.Architectures;
/// <summary>
/// 架构上下文接口,统一暴露框架组件访问、兼容旧命令/查询总线,以及当前推荐的 CQRS 运行时入口。
/// </summary>
/// <remarks>
/// <para>旧的 <c>GFramework.Core.Abstractions.Command</c> 与 <c>GFramework.Core.Abstractions.Query</c> 契约会继续通过原有 Command/Query Executor 路径执行,以保证存量代码兼容。</para>
/// <para>新的 <c>GFramework.Core.Abstractions.Cqrs</c> 契约由内置 CQRS dispatcher 统一处理,支持 request pipeline、notification publish 与 stream request。</para>
/// <para>新功能优先使用 <see cref="SendRequestAsync{TResponse}(IRequest{TResponse},CancellationToken)" />、<see cref="SendAsync{TCommand}(TCommand,CancellationToken)" /> 与对应的 CQRS Command/Query 重载;迁移旧代码时可先保留旧入口,再逐步替换为 CQRS 请求模型。</para>
/// </remarks>
public interface IArchitectureContext
{
/// <summary>
/// 获取指定类型的服务实例
/// </summary>
/// <typeparam name="TService">服务类型</typeparam>
/// <returns>服务实例,如果不存在则抛出异常</returns>
TService GetService<TService>() where TService : class;
/// <summary>
/// 获取指定类型的所有服务实例
/// </summary>
/// <typeparam name="TService">服务类型</typeparam>
/// <returns>所有符合条件的服务实例列表</returns>
IReadOnlyList<TService> GetServices<TService>() where TService : class;
/// <summary>
/// 获取指定类型的系统实例
/// </summary>
/// <typeparam name="TSystem">系统类型必须继承自ISystem接口</typeparam>
/// <returns>系统实例,如果不存在则抛出异常</returns>
TSystem GetSystem<TSystem>() where TSystem : class, ISystem;
/// <summary>
/// 获取指定类型的所有系统实例
/// </summary>
/// <typeparam name="TSystem">系统类型必须继承自ISystem接口</typeparam>
/// <returns>所有符合条件的系统实例列表</returns>
IReadOnlyList<TSystem> GetSystems<TSystem>() where TSystem : class, ISystem;
/// <summary>
/// 获取指定类型的模型实例
/// </summary>
/// <typeparam name="TModel">模型类型必须继承自IModel接口</typeparam>
/// <returns>模型实例,如果不存在则抛出异常</returns>
TModel GetModel<TModel>() where TModel : class, IModel;
/// <summary>
/// 获取指定类型的所有模型实例
/// </summary>
/// <typeparam name="TModel">模型类型必须继承自IModel接口</typeparam>
/// <returns>所有符合条件的模型实例列表</returns>
IReadOnlyList<TModel> GetModels<TModel>() where TModel : class, IModel;
/// <summary>
/// 获取指定类型的工具类实例
/// </summary>
/// <typeparam name="TUtility">工具类类型必须继承自IUtility接口</typeparam>
/// <returns>工具类实例,如果不存在则抛出异常</returns>
TUtility GetUtility<TUtility>() where TUtility : class, IUtility;
/// <summary>
/// 获取指定类型的所有工具类实例
/// </summary>
/// <typeparam name="TUtility">工具类类型必须继承自IUtility接口</typeparam>
/// <returns>所有符合条件的工具类实例列表</returns>
IReadOnlyList<TUtility> GetUtilities<TUtility>() where TUtility : class, IUtility;
/// <summary>
/// 获取指定类型的所有服务实例,并按优先级排序
/// 实现 IPrioritized 接口的服务将按优先级排序(数值越小优先级越高)
/// </summary>
/// <typeparam name="TService">服务类型</typeparam>
/// <returns>按优先级排序后的服务实例列表</returns>
IReadOnlyList<TService> GetServicesByPriority<TService>() where TService : class;
/// <summary>
/// 获取指定类型的所有系统实例,并按优先级排序
/// 实现 IPrioritized 接口的系统将按优先级排序(数值越小优先级越高)
/// </summary>
/// <typeparam name="TSystem">系统类型必须继承自ISystem接口</typeparam>
/// <returns>按优先级排序后的系统实例列表</returns>
IReadOnlyList<TSystem> GetSystemsByPriority<TSystem>() where TSystem : class, ISystem;
/// <summary>
/// 获取指定类型的所有模型实例,并按优先级排序
/// 实现 IPrioritized 接口的模型将按优先级排序(数值越小优先级越高)
/// </summary>
/// <typeparam name="TModel">模型类型必须继承自IModel接口</typeparam>
/// <returns>按优先级排序后的模型实例列表</returns>
IReadOnlyList<TModel> GetModelsByPriority<TModel>() where TModel : class, IModel;
/// <summary>
/// 获取指定类型的所有工具类实例,并按优先级排序
/// 实现 IPrioritized 接口的工具将按优先级排序(数值越小优先级越高)
/// </summary>
/// <typeparam name="TUtility">工具类类型必须继承自IUtility接口</typeparam>
/// <returns>按优先级排序后的工具类实例列表</returns>
IReadOnlyList<TUtility> GetUtilitiesByPriority<TUtility>() where TUtility : class, IUtility;
/// <summary>
/// 发送一个旧版命令。
/// </summary>
/// <param name="command">要发送的旧版命令。</param>
void SendCommand(ICommand command);
/// <summary>
/// 发送一个旧版带返回值命令。
/// </summary>
/// <typeparam name="TResult">命令执行结果类型。</typeparam>
/// <param name="command">要发送的旧版命令。</param>
/// <returns>命令执行结果。</returns>
TResult SendCommand<TResult>(ICommand<TResult> command);
/// <summary>
/// 发送一个新版 CQRS 命令并返回结果。
/// </summary>
/// <typeparam name="TResponse">命令响应类型。</typeparam>
/// <param name="command">要发送的 CQRS 命令。</param>
/// <returns>命令执行结果。</returns>
/// <remarks>
/// 这是迁移后的推荐命令入口。无返回值命令应实现 <c>IRequest&lt;Unit&gt;</c>,并优先通过 <see cref="SendAsync{TCommand}(TCommand,CancellationToken)" /> 调用。
/// </remarks>
TResponse SendCommand<TResponse>(Cqrs.Command.ICommand<TResponse> command);
/// <summary>
/// 异步发送一个旧版命令。
/// </summary>
/// <param name="command">要发送的旧版命令。</param>
Task SendCommandAsync(IAsyncCommand command);
/// <summary>
/// 异步发送一个新版 CQRS 命令并返回结果。
/// </summary>
/// <typeparam name="TResponse">命令响应类型。</typeparam>
/// <param name="command">要发送的 CQRS 命令。</param>
/// <param name="cancellationToken">取消令牌。</param>
/// <returns>包含命令执行结果的值任务。</returns>
ValueTask<TResponse> SendCommandAsync<TResponse>(Cqrs.Command.ICommand<TResponse> command,
CancellationToken cancellationToken = default);
/// <summary>
/// 异步发送一个旧版带返回值命令。
/// </summary>
/// <typeparam name="TResult">命令执行结果类型。</typeparam>
/// <param name="command">要发送的旧版命令。</param>
/// <returns>命令执行结果。</returns>
Task<TResult> SendCommandAsync<TResult>(IAsyncCommand<TResult> command);
/// <summary>
/// 发送一个旧版查询请求。
/// </summary>
/// <typeparam name="TResult">查询结果类型。</typeparam>
/// <param name="query">要发送的旧版查询。</param>
/// <returns>查询结果。</returns>
TResult SendQuery<TResult>(IQuery<TResult> query);
/// <summary>
/// 发送一个新版 CQRS 查询并返回结果。
/// </summary>
/// <typeparam name="TResponse">查询响应类型。</typeparam>
/// <param name="query">要发送的 CQRS 查询。</param>
/// <returns>查询结果。</returns>
/// <remarks>
/// 这是迁移后的推荐查询入口。新查询应优先实现 <c>GFramework.Core.Abstractions.Cqrs.Query.IQuery&lt;TResponse&gt;</c>。
/// </remarks>
TResponse SendQuery<TResponse>(Cqrs.Query.IQuery<TResponse> query);
/// <summary>
/// 异步发送一个旧版查询请求。
/// </summary>
/// <typeparam name="TResult">查询结果类型。</typeparam>
/// <param name="query">要发送的旧版异步查询。</param>
/// <returns>查询结果。</returns>
Task<TResult> SendQueryAsync<TResult>(IAsyncQuery<TResult> query);
/// <summary>
/// 异步发送一个新版 CQRS 查询并返回结果。
/// </summary>
/// <typeparam name="TResponse">查询响应类型。</typeparam>
/// <param name="query">要发送的 CQRS 查询。</param>
/// <param name="cancellationToken">取消令牌。</param>
/// <returns>包含查询结果的值任务。</returns>
ValueTask<TResponse> SendQueryAsync<TResponse>(Cqrs.Query.IQuery<TResponse> query,
CancellationToken cancellationToken = default);
/// <summary>
/// 发送一个事件
/// </summary>
/// <typeparam name="TEvent">事件类型,必须具有无参构造函数</typeparam>
void SendEvent<TEvent>() where TEvent : new();
/// <summary>
/// 发送一个带参数的事件
/// </summary>
/// <typeparam name="TEvent">事件类型</typeparam>
/// <param name="e">事件参数</param>
void SendEvent<TEvent>(TEvent e) where TEvent : class;
/// <summary>
/// 注册事件处理器
/// </summary>
/// <typeparam name="TEvent">事件类型</typeparam>
/// <param name="handler">事件处理委托</param>
/// <returns>事件注销接口</returns>
IUnRegister RegisterEvent<TEvent>(Action<TEvent> handler);
/// <summary>
/// 取消注册事件监听器
/// </summary>
/// <typeparam name="TEvent">事件类型</typeparam>
/// <param name="onEvent">要取消注册的事件回调方法</param>
void UnRegisterEvent<TEvent>(Action<TEvent> onEvent);
/// <summary>
/// 发送新版 CQRS 请求,并统一处理命令与查询。
/// </summary>
/// <remarks>
/// 这是自有 CQRS 运行时的主入口。新代码应优先通过该方法或 <see cref="SendAsync{TCommand}(TCommand,CancellationToken)" /> 进入 dispatcher。
/// </remarks>
ValueTask<TResponse> SendRequestAsync<TResponse>(
IRequest<TResponse> request,
CancellationToken cancellationToken = default);
/// <summary>
/// 发送新版 CQRS 请求的同步包装版本。
/// </summary>
/// <remarks>
/// 仅为兼容同步调用链保留;新代码应优先使用异步入口,避免阻塞当前线程。
/// </remarks>
TResponse SendRequest<TResponse>(IRequest<TResponse> request);
/// <summary>
/// 发布新版 CQRS 通知。
/// </summary>
/// <remarks>
/// 该入口用于一对多通知分发,与框架级 <c>EventBus</c> 事件系统并存,适合围绕请求处理过程传播领域通知。
/// </remarks>
ValueTask PublishAsync<TNotification>(
TNotification notification,
CancellationToken cancellationToken = default)
where TNotification : INotification;
/// <summary>
/// 创建新版 CQRS 流式请求。
/// </summary>
/// <remarks>
/// 适用于需要按序惰性产出大量结果的场景。调用方应消费返回的异步序列,而不是回退到旧版查询总线。
/// </remarks>
IAsyncEnumerable<TResponse> CreateStream<TResponse>(
IStreamRequest<TResponse> request,
CancellationToken cancellationToken = default);
// === 便捷扩展方法 ===
/// <summary>
/// 发送一个无返回值的新版 CQRS 命令。
/// </summary>
ValueTask SendAsync<TCommand>(
TCommand command,
CancellationToken cancellationToken = default)
where TCommand : IRequest<Unit>;
/// <summary>
/// 发送一个有返回值的新版 CQRS 请求。
/// </summary>
ValueTask<TResponse> SendAsync<TResponse>(
IRequest<TResponse> command,
CancellationToken cancellationToken = default);
/// <summary>
/// 获取环境对象
/// </summary>
/// <returns>环境对象实例</returns>
IEnvironment GetEnvironment();
}