mirror of
https://github.com/GeWuYou/GFramework.git
synced 2026-05-06 16:16:44 +08:00
docs(core): 添加 CQRS 和核心框架文档
- 新增 CQRS 模块详细文档,介绍命令查询职责分离模式 - 添加核心框架架构概述和五层架构设计说明 - 补充快速开始指南和最佳实践建议 - 完善包说明和组件联动机制介绍 - 添加架构生命周期管理和模块化设计说明
This commit is contained in:
parent
5c112f8545
commit
115fe65e88
@ -73,11 +73,21 @@ public interface IArchitecture : IAsyncInitializable, IAsyncDestroyable, IInitia
|
||||
|
||||
/// <summary>
|
||||
/// 注册 CQRS 请求管道行为。
|
||||
/// 历史方法名保留了 Mediator 前缀,但当前用于配置框架内建 CQRS runtime 的行为拦截和处理逻辑。
|
||||
/// 既支持实现 <c>IPipelineBehavior<,></c> 的开放泛型行为类型,
|
||||
/// 也支持绑定到单一请求/响应对的封闭行为类型。
|
||||
/// </summary>
|
||||
/// <typeparam name="TBehavior">行为类型,必须是引用类型</typeparam>
|
||||
void RegisterCqrsPipelineBehavior<TBehavior>()
|
||||
where TBehavior : class;
|
||||
|
||||
/// <summary>
|
||||
/// 注册 CQRS 请求管道行为。
|
||||
/// 该成员保留旧名称以兼容历史调用点,内部行为与 <see cref="RegisterCqrsPipelineBehavior{TBehavior}" /> 一致。
|
||||
/// 既支持实现 <c>IPipelineBehavior<,></c> 的开放泛型行为类型,
|
||||
/// 也支持绑定到单一请求/响应对的封闭行为类型。
|
||||
/// </summary>
|
||||
/// <typeparam name="TBehavior">行为类型,必须是引用类型</typeparam>
|
||||
[Obsolete("Use RegisterCqrsPipelineBehavior<TBehavior>() instead.")]
|
||||
void RegisterMediatorBehavior<TBehavior>()
|
||||
where TBehavior : class;
|
||||
|
||||
|
||||
@ -90,9 +90,17 @@ public interface IIocContainer : IContextAware
|
||||
|
||||
/// <summary>
|
||||
/// 注册 CQRS 请求管道行为。
|
||||
/// 历史方法名保留了 Mediator 前缀,但当前用于配置框架内建 CQRS runtime 的行为拦截和处理逻辑。
|
||||
/// </summary>
|
||||
/// <typeparam name="TBehavior">行为类型,必须是引用类型</typeparam>
|
||||
void RegisterCqrsPipelineBehavior<TBehavior>()
|
||||
where TBehavior : class;
|
||||
|
||||
/// <summary>
|
||||
/// 注册 CQRS 请求管道行为。
|
||||
/// 该成员保留旧名称以兼容历史调用点,内部行为与 <see cref="RegisterCqrsPipelineBehavior{TBehavior}" /> 一致。
|
||||
/// </summary>
|
||||
/// <typeparam name="TBehavior">行为类型,必须是引用类型</typeparam>
|
||||
[Obsolete("Use RegisterCqrsPipelineBehavior<TBehavior>() instead.")]
|
||||
void RegisterMediatorBehavior<TBehavior>()
|
||||
where TBehavior : class;
|
||||
|
||||
|
||||
@ -59,10 +59,10 @@ public class ArchitectureModulesBehaviorTests
|
||||
/// 验证注册的 CQRS 行为会参与请求管道执行。
|
||||
/// </summary>
|
||||
[Test]
|
||||
public async Task RegisterMediatorBehavior_Should_Apply_Pipeline_Behavior_To_Request()
|
||||
public async Task RegisterCqrsPipelineBehavior_Should_Apply_Pipeline_Behavior_To_Request()
|
||||
{
|
||||
var architecture = new ModuleTestArchitecture(target =>
|
||||
target.RegisterMediatorBehavior<TrackingPipelineBehavior<ModuleBehaviorRequest, string>>());
|
||||
target.RegisterCqrsPipelineBehavior<TrackingPipelineBehavior<ModuleBehaviorRequest, string>>());
|
||||
|
||||
await architecture.InitializeAsync();
|
||||
|
||||
|
||||
@ -5,7 +5,6 @@ using GFramework.Core.Abstractions.Model;
|
||||
using GFramework.Core.Abstractions.Systems;
|
||||
using GFramework.Core.Abstractions.Utility;
|
||||
using GFramework.Core.Architectures;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
namespace GFramework.Core.Tests.Architectures;
|
||||
|
||||
@ -181,11 +180,17 @@ public class TestArchitectureWithRegistry : IArchitecture
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public void RegisterMediatorBehavior<TBehavior>() where TBehavior : class
|
||||
public void RegisterCqrsPipelineBehavior<TBehavior>() where TBehavior : class
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
[Obsolete("Use RegisterCqrsPipelineBehavior<TBehavior>() instead.")]
|
||||
public void RegisterMediatorBehavior<TBehavior>() where TBehavior : class
|
||||
{
|
||||
RegisterCqrsPipelineBehavior<TBehavior>();
|
||||
}
|
||||
|
||||
public IArchitectureModule InstallModule(IArchitectureModule module)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
@ -306,11 +311,17 @@ public class TestArchitectureWithoutRegistry : IArchitecture
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public void RegisterMediatorBehavior<TBehavior>() where TBehavior : class
|
||||
public void RegisterCqrsPipelineBehavior<TBehavior>() where TBehavior : class
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
[Obsolete("Use RegisterCqrsPipelineBehavior<TBehavior>() instead.")]
|
||||
public void RegisterMediatorBehavior<TBehavior>() where TBehavior : class
|
||||
{
|
||||
RegisterCqrsPipelineBehavior<TBehavior>();
|
||||
}
|
||||
|
||||
public IArchitectureModule InstallModule(IArchitectureModule module)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
@ -363,4 +374,4 @@ public class TestArchitectureWithoutRegistry : IArchitecture
|
||||
public void RegisterLifecycleHook(IArchitectureLifecycleHook hook)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -15,17 +15,17 @@ using GFramework.Core.Abstractions.Architectures;
|
||||
using GFramework.Core.Abstractions.Coroutine;
|
||||
using GFramework.Core.Abstractions.Cqrs;
|
||||
using GFramework.Core.Abstractions.Rule;
|
||||
using GFramework.Core.Coroutine.Extensions;
|
||||
using GFramework.Core.Cqrs.Extensions;
|
||||
|
||||
namespace GFramework.Core.Tests.Coroutine;
|
||||
|
||||
/// <summary>
|
||||
/// <see cref="MediatorCoroutineExtensions" /> 的单元测试类。
|
||||
/// 验证历史命名的协程扩展已切到框架内建 CQRS runtime,
|
||||
/// <see cref="CqrsCoroutineExtensions" /> 的单元测试类。
|
||||
/// 验证新的 CQRS 协程扩展直接走框架内建 CQRS runtime,
|
||||
/// 并确保协程对命令调度异常的传播行为保持稳定。
|
||||
/// </summary>
|
||||
[TestFixture]
|
||||
public class MediatorCoroutineExtensionsTests
|
||||
public class CqrsCoroutineExtensionsTests
|
||||
{
|
||||
/// <summary>
|
||||
/// 验证SendCommandCoroutine应该返回IEnumerator<IYieldInstruction>
|
||||
@ -40,7 +40,7 @@ public class MediatorCoroutineExtensionsTests
|
||||
.Setup(ctx => ctx.SendAsync(command, It.IsAny<CancellationToken>()))
|
||||
.Returns(ValueTask.CompletedTask);
|
||||
|
||||
var coroutine = MediatorCoroutineExtensions.SendCommandCoroutine(contextAware, command);
|
||||
var coroutine = CqrsCoroutineExtensions.SendCommandCoroutine(contextAware, command);
|
||||
|
||||
Assert.That(coroutine, Is.InstanceOf<IEnumerator<IYieldInstruction>>());
|
||||
}
|
||||
@ -59,7 +59,7 @@ public class MediatorCoroutineExtensionsTests
|
||||
.Setup(ctx => ctx.SendAsync(command, It.IsAny<CancellationToken>()))
|
||||
.Returns(new ValueTask(Task.FromException(expectedException)));
|
||||
|
||||
var coroutine = MediatorCoroutineExtensions.SendCommandCoroutine(contextAware, command);
|
||||
var coroutine = CqrsCoroutineExtensions.SendCommandCoroutine(contextAware, command);
|
||||
|
||||
Assert.That(coroutine.MoveNext(), Is.True);
|
||||
var exception = Assert.Throws<InvalidOperationException>(() => coroutine.MoveNext());
|
||||
@ -146,13 +146,23 @@ public abstract class Architecture : IArchitecture
|
||||
|
||||
/// <summary>
|
||||
/// 注册 CQRS 请求管道行为。
|
||||
/// 历史方法名保留了 Mediator 前缀,但当前用于配置框架内建 CQRS runtime 的行为拦截和处理逻辑。
|
||||
/// 可以传入开放泛型行为类型,也可以传入绑定到特定请求的封闭行为类型。
|
||||
/// </summary>
|
||||
/// <typeparam name="TBehavior">行为类型,必须是引用类型</typeparam>
|
||||
public void RegisterCqrsPipelineBehavior<TBehavior>() where TBehavior : class
|
||||
{
|
||||
_modules.RegisterCqrsPipelineBehavior<TBehavior>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 注册 CQRS 请求管道行为。
|
||||
/// 该成员保留旧名称以兼容历史调用点,内部行为与 <see cref="RegisterCqrsPipelineBehavior{TBehavior}" /> 一致。
|
||||
/// </summary>
|
||||
/// <typeparam name="TBehavior">行为类型,必须是引用类型</typeparam>
|
||||
[Obsolete("Use RegisterCqrsPipelineBehavior<TBehavior>() instead.")]
|
||||
public void RegisterMediatorBehavior<TBehavior>() where TBehavior : class
|
||||
{
|
||||
_modules.RegisterMediatorBehavior<TBehavior>();
|
||||
RegisterCqrsPipelineBehavior<TBehavior>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@ -14,14 +14,24 @@ internal sealed class ArchitectureModules(
|
||||
{
|
||||
/// <summary>
|
||||
/// 注册 CQRS 请求管道行为。
|
||||
/// 历史方法名保留了 Mediator 前缀,但当前用于配置框架内建 CQRS runtime 的行为拦截和处理逻辑。
|
||||
/// 支持开放泛型行为类型和针对单一请求的封闭行为类型。
|
||||
/// </summary>
|
||||
/// <typeparam name="TBehavior">行为类型,必须是引用类型</typeparam>
|
||||
public void RegisterMediatorBehavior<TBehavior>() where TBehavior : class
|
||||
public void RegisterCqrsPipelineBehavior<TBehavior>() where TBehavior : class
|
||||
{
|
||||
logger.Debug($"Registering CQRS pipeline behavior: {typeof(TBehavior).Name}");
|
||||
services.Container.RegisterMediatorBehavior<TBehavior>();
|
||||
services.Container.RegisterCqrsPipelineBehavior<TBehavior>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 注册 CQRS 请求管道行为。
|
||||
/// 该成员保留旧名称以兼容历史调用点,内部行为与 <see cref="RegisterCqrsPipelineBehavior{TBehavior}" /> 一致。
|
||||
/// </summary>
|
||||
/// <typeparam name="TBehavior">行为类型,必须是引用类型</typeparam>
|
||||
[Obsolete("Use RegisterCqrsPipelineBehavior<TBehavior>() instead.")]
|
||||
public void RegisterMediatorBehavior<TBehavior>() where TBehavior : class
|
||||
{
|
||||
RegisterCqrsPipelineBehavior<TBehavior>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@ -0,0 +1,43 @@
|
||||
using GFramework.Core.Abstractions.Coroutine;
|
||||
using GFramework.Core.Abstractions.Cqrs;
|
||||
using GFramework.Core.Abstractions.Rule;
|
||||
using GFramework.Core.Coroutine.Extensions;
|
||||
|
||||
namespace GFramework.Core.Cqrs.Extensions;
|
||||
|
||||
/// <summary>
|
||||
/// 提供 CQRS 命令与协程集成的扩展方法。
|
||||
/// 这些扩展直接走架构上下文的内建 CQRS runtime,不依赖外部 Mediator 服务。
|
||||
/// </summary>
|
||||
public static class CqrsCoroutineExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// 以协程方式发送无返回值 CQRS 命令并处理可能的异常。
|
||||
/// </summary>
|
||||
/// <typeparam name="TCommand">命令类型。</typeparam>
|
||||
/// <param name="contextAware">上下文感知对象,用于获取架构上下文。</param>
|
||||
/// <param name="command">要发送的命令对象。</param>
|
||||
/// <param name="onError">发生异常时的回调处理函数。</param>
|
||||
/// <returns>协程枚举器,用于协程执行。</returns>
|
||||
public static IEnumerator<IYieldInstruction> SendCommandCoroutine<TCommand>(
|
||||
this IContextAware contextAware,
|
||||
TCommand command,
|
||||
Action<Exception>? onError = null)
|
||||
where TCommand : IRequest<Unit>
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(contextAware);
|
||||
ArgumentNullException.ThrowIfNull(command);
|
||||
|
||||
var task = contextAware.GetContext().SendAsync(command).AsTask();
|
||||
|
||||
yield return task.AsCoroutineInstruction();
|
||||
|
||||
if (!task.IsFaulted)
|
||||
yield break;
|
||||
|
||||
if (onError != null)
|
||||
onError.Invoke(task.Exception!);
|
||||
else
|
||||
throw task.Exception!.InnerException ?? task.Exception;
|
||||
}
|
||||
}
|
||||
@ -14,14 +14,15 @@
|
||||
using GFramework.Core.Abstractions.Coroutine;
|
||||
using GFramework.Core.Abstractions.Cqrs;
|
||||
using GFramework.Core.Abstractions.Rule;
|
||||
using GFramework.Core.Cqrs.Extensions;
|
||||
|
||||
namespace GFramework.Core.Coroutine.Extensions;
|
||||
|
||||
/// <summary>
|
||||
/// 提供 CQRS 命令与协程集成的扩展方法。
|
||||
/// 历史命名保留了 Mediator 前缀,但当前实现直接走 <see cref="IContextAware.GetContext" /> 返回的
|
||||
/// <see cref="GFramework.Core.Abstractions.Architectures.IArchitectureContext" /> CQRS 入口,不再依赖外部 Mediator 服务。
|
||||
/// 该类型保留旧名称以兼容历史调用点;新代码应改用 <see cref="GFramework.Core.Cqrs.Extensions.CqrsCoroutineExtensions" />。
|
||||
/// </summary>
|
||||
[Obsolete("Use GFramework.Core.Cqrs.Extensions.CqrsCoroutineExtensions instead.")]
|
||||
public static class MediatorCoroutineExtensions
|
||||
{
|
||||
/// <summary>
|
||||
@ -38,17 +39,6 @@ public static class MediatorCoroutineExtensions
|
||||
Action<Exception>? onError = null)
|
||||
where TCommand : IRequest<Unit>
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(contextAware);
|
||||
ArgumentNullException.ThrowIfNull(command);
|
||||
|
||||
var task = contextAware.GetContext().SendAsync(command).AsTask();
|
||||
|
||||
yield return task.AsCoroutineInstruction();
|
||||
|
||||
if (!task.IsFaulted) yield break;
|
||||
if (onError != null)
|
||||
onError.Invoke(task.Exception!);
|
||||
else
|
||||
throw task.Exception!.InnerException ?? task.Exception;
|
||||
return CqrsCoroutineExtensions.SendCommandCoroutine(contextAware, command, onError);
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,44 @@
|
||||
using GFramework.Core.Abstractions.Cqrs.Command;
|
||||
using GFramework.Core.Abstractions.Rule;
|
||||
|
||||
namespace GFramework.Core.Cqrs.Extensions;
|
||||
|
||||
/// <summary>
|
||||
/// 提供对 <see cref="IContextAware" /> 接口的 CQRS 命令扩展方法。
|
||||
/// </summary>
|
||||
public static class ContextAwareCqrsCommandExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// 发送命令的同步版本(不推荐,仅用于兼容同步调用链)。
|
||||
/// </summary>
|
||||
/// <typeparam name="TResponse">命令响应类型。</typeparam>
|
||||
/// <param name="contextAware">实现 <see cref="IContextAware" /> 接口的对象。</param>
|
||||
/// <param name="command">要发送的命令对象。</param>
|
||||
/// <returns>命令执行结果。</returns>
|
||||
public static TResponse SendCommand<TResponse>(this IContextAware contextAware, ICommand<TResponse> command)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(contextAware);
|
||||
ArgumentNullException.ThrowIfNull(command);
|
||||
|
||||
return contextAware.GetContext().SendCommand(command);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 异步发送命令并返回结果。
|
||||
/// </summary>
|
||||
/// <typeparam name="TResponse">命令响应类型。</typeparam>
|
||||
/// <param name="contextAware">实现 <see cref="IContextAware" /> 接口的对象。</param>
|
||||
/// <param name="command">要发送的命令对象。</param>
|
||||
/// <param name="cancellationToken">取消令牌,用于取消操作。</param>
|
||||
/// <returns>包含命令执行结果的 <see cref="ValueTask{TResult}" />。</returns>
|
||||
public static ValueTask<TResponse> SendCommandAsync<TResponse>(
|
||||
this IContextAware contextAware,
|
||||
ICommand<TResponse> command,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(contextAware);
|
||||
ArgumentNullException.ThrowIfNull(command);
|
||||
|
||||
return contextAware.GetContext().SendCommandAsync(command, cancellationToken);
|
||||
}
|
||||
}
|
||||
123
GFramework.Core/Extensions/ContextAwareCqrsExtensions.cs
Normal file
123
GFramework.Core/Extensions/ContextAwareCqrsExtensions.cs
Normal file
@ -0,0 +1,123 @@
|
||||
using GFramework.Core.Abstractions.Cqrs;
|
||||
using GFramework.Core.Abstractions.Rule;
|
||||
|
||||
namespace GFramework.Core.Cqrs.Extensions;
|
||||
|
||||
/// <summary>
|
||||
/// 提供对 <see cref="IContextAware" /> 接口的 CQRS 统一扩展方法。
|
||||
/// 这些扩展直接委托给架构上下文的内建 CQRS runtime,作为新的中性命名入口。
|
||||
/// </summary>
|
||||
public static class ContextAwareCqrsExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// 发送请求(统一处理 Command/Query)。
|
||||
/// </summary>
|
||||
/// <typeparam name="TResponse">响应类型。</typeparam>
|
||||
/// <param name="contextAware">实现 <see cref="IContextAware" /> 接口的对象。</param>
|
||||
/// <param name="request">要发送的请求。</param>
|
||||
/// <param name="cancellationToken">取消令牌。</param>
|
||||
/// <returns>请求结果。</returns>
|
||||
public static ValueTask<TResponse> SendRequestAsync<TResponse>(
|
||||
this IContextAware contextAware,
|
||||
IRequest<TResponse> request,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(contextAware);
|
||||
ArgumentNullException.ThrowIfNull(request);
|
||||
|
||||
return contextAware.GetContext().SendRequestAsync(request, cancellationToken);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 发送请求(同步版本,不推荐)。
|
||||
/// </summary>
|
||||
/// <typeparam name="TResponse">响应类型。</typeparam>
|
||||
/// <param name="contextAware">实现 <see cref="IContextAware" /> 接口的对象。</param>
|
||||
/// <param name="request">要发送的请求。</param>
|
||||
/// <returns>请求结果。</returns>
|
||||
public static TResponse SendRequest<TResponse>(this IContextAware contextAware, IRequest<TResponse> request)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(contextAware);
|
||||
ArgumentNullException.ThrowIfNull(request);
|
||||
|
||||
return contextAware.GetContext().SendRequest(request);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 发布通知(一对多事件)。
|
||||
/// </summary>
|
||||
/// <typeparam name="TNotification">通知类型。</typeparam>
|
||||
/// <param name="contextAware">实现 <see cref="IContextAware" /> 接口的对象。</param>
|
||||
/// <param name="notification">要发布的通知。</param>
|
||||
/// <param name="cancellationToken">取消令牌。</param>
|
||||
/// <returns>异步任务。</returns>
|
||||
public static ValueTask PublishAsync<TNotification>(
|
||||
this IContextAware contextAware,
|
||||
TNotification notification,
|
||||
CancellationToken cancellationToken = default)
|
||||
where TNotification : INotification
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(contextAware);
|
||||
ArgumentNullException.ThrowIfNull(notification);
|
||||
|
||||
return contextAware.GetContext().PublishAsync(notification, cancellationToken);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 创建流式请求。
|
||||
/// </summary>
|
||||
/// <typeparam name="TResponse">响应类型。</typeparam>
|
||||
/// <param name="contextAware">实现 <see cref="IContextAware" /> 接口的对象。</param>
|
||||
/// <param name="request">流式请求。</param>
|
||||
/// <param name="cancellationToken">取消令牌。</param>
|
||||
/// <returns>异步响应流。</returns>
|
||||
public static IAsyncEnumerable<TResponse> CreateStream<TResponse>(
|
||||
this IContextAware contextAware,
|
||||
IStreamRequest<TResponse> request,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(contextAware);
|
||||
ArgumentNullException.ThrowIfNull(request);
|
||||
|
||||
return contextAware.GetContext().CreateStream(request, cancellationToken);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 发送无返回值命令。
|
||||
/// </summary>
|
||||
/// <typeparam name="TCommand">命令类型。</typeparam>
|
||||
/// <param name="contextAware">实现 <see cref="IContextAware" /> 接口的对象。</param>
|
||||
/// <param name="command">要发送的命令。</param>
|
||||
/// <param name="cancellationToken">取消令牌。</param>
|
||||
/// <returns>异步任务。</returns>
|
||||
public static ValueTask SendAsync<TCommand>(
|
||||
this IContextAware contextAware,
|
||||
TCommand command,
|
||||
CancellationToken cancellationToken = default)
|
||||
where TCommand : IRequest<Unit>
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(contextAware);
|
||||
ArgumentNullException.ThrowIfNull(command);
|
||||
|
||||
return contextAware.GetContext().SendAsync(command, cancellationToken);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 发送带返回值命令。
|
||||
/// </summary>
|
||||
/// <typeparam name="TResponse">响应类型。</typeparam>
|
||||
/// <param name="contextAware">实现 <see cref="IContextAware" /> 接口的对象。</param>
|
||||
/// <param name="command">要发送的命令。</param>
|
||||
/// <param name="cancellationToken">取消令牌。</param>
|
||||
/// <returns>命令执行结果。</returns>
|
||||
public static ValueTask<TResponse> SendAsync<TResponse>(
|
||||
this IContextAware contextAware,
|
||||
IRequest<TResponse> command,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(contextAware);
|
||||
ArgumentNullException.ThrowIfNull(command);
|
||||
|
||||
return contextAware.GetContext().SendAsync(command, cancellationToken);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,44 @@
|
||||
using GFramework.Core.Abstractions.Cqrs.Query;
|
||||
using GFramework.Core.Abstractions.Rule;
|
||||
|
||||
namespace GFramework.Core.Cqrs.Extensions;
|
||||
|
||||
/// <summary>
|
||||
/// 提供对 <see cref="IContextAware" /> 接口的 CQRS 查询扩展方法。
|
||||
/// </summary>
|
||||
public static class ContextAwareCqrsQueryExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// 发送查询的同步版本(不推荐,仅用于兼容同步调用链)。
|
||||
/// </summary>
|
||||
/// <typeparam name="TResponse">查询响应类型。</typeparam>
|
||||
/// <param name="contextAware">实现 <see cref="IContextAware" /> 接口的对象。</param>
|
||||
/// <param name="query">要发送的查询对象。</param>
|
||||
/// <returns>查询结果。</returns>
|
||||
public static TResponse SendQuery<TResponse>(this IContextAware contextAware, IQuery<TResponse> query)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(contextAware);
|
||||
ArgumentNullException.ThrowIfNull(query);
|
||||
|
||||
return contextAware.GetContext().SendQuery(query);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 异步发送查询并返回结果。
|
||||
/// </summary>
|
||||
/// <typeparam name="TResponse">查询响应类型。</typeparam>
|
||||
/// <param name="contextAware">实现 <see cref="IContextAware" /> 接口的对象。</param>
|
||||
/// <param name="query">要发送的查询对象。</param>
|
||||
/// <param name="cancellationToken">取消令牌,用于取消操作。</param>
|
||||
/// <returns>包含查询结果的 <see cref="ValueTask{TResult}" />。</returns>
|
||||
public static ValueTask<TResponse> SendQueryAsync<TResponse>(
|
||||
this IContextAware contextAware,
|
||||
IQuery<TResponse> query,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(contextAware);
|
||||
ArgumentNullException.ThrowIfNull(query);
|
||||
|
||||
return contextAware.GetContext().SendQueryAsync(query, cancellationToken);
|
||||
}
|
||||
}
|
||||
@ -1,11 +1,14 @@
|
||||
using GFramework.Core.Abstractions.Rule;
|
||||
using GFramework.Core.Abstractions.Cqrs.Command;
|
||||
using GFramework.Core.Abstractions.Rule;
|
||||
using GFramework.Core.Cqrs.Extensions;
|
||||
|
||||
namespace GFramework.Core.Extensions;
|
||||
|
||||
/// <summary>
|
||||
/// 提供对 IContextAware 接口的 CQRS 命令扩展方法。
|
||||
/// 提供对 <see cref="IContextAware" /> 接口的 CQRS 命令扩展方法。
|
||||
/// 该类型保留旧名称以兼容历史调用点;新代码应改用 <see cref="GFramework.Core.Cqrs.Extensions.ContextAwareCqrsCommandExtensions" />。
|
||||
/// </summary>
|
||||
[Obsolete("Use GFramework.Core.Cqrs.Extensions.ContextAwareCqrsCommandExtensions instead.")]
|
||||
public static class ContextAwareMediatorCommandExtensions
|
||||
{
|
||||
/// <summary>
|
||||
@ -19,11 +22,7 @@ public static class ContextAwareMediatorCommandExtensions
|
||||
public static TResponse SendCommand<TResponse>(this IContextAware contextAware,
|
||||
ICommand<TResponse> command)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(contextAware);
|
||||
ArgumentNullException.ThrowIfNull(command);
|
||||
|
||||
var context = contextAware.GetContext();
|
||||
return context.SendCommand(command);
|
||||
return ContextAwareCqrsCommandExtensions.SendCommand(contextAware, command);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -38,10 +37,9 @@ public static class ContextAwareMediatorCommandExtensions
|
||||
public static ValueTask<TResponse> SendCommandAsync<TResponse>(this IContextAware contextAware,
|
||||
ICommand<TResponse> command, CancellationToken cancellationToken = default)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(contextAware);
|
||||
ArgumentNullException.ThrowIfNull(command);
|
||||
|
||||
var context = contextAware.GetContext();
|
||||
return context.SendCommandAsync(command, cancellationToken);
|
||||
return ContextAwareCqrsCommandExtensions.SendCommandAsync(
|
||||
contextAware,
|
||||
command,
|
||||
cancellationToken);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,11 +1,14 @@
|
||||
using GFramework.Core.Abstractions.Rule;
|
||||
using GFramework.Core.Abstractions.Cqrs;
|
||||
using GFramework.Core.Abstractions.Rule;
|
||||
using GFramework.Core.Cqrs.Extensions;
|
||||
|
||||
namespace GFramework.Core.Extensions;
|
||||
|
||||
/// <summary>
|
||||
/// 提供对 IContextAware 接口的 CQRS 统一接口扩展方法。
|
||||
/// 提供对 <see cref="IContextAware" /> 接口的 CQRS 统一接口扩展方法。
|
||||
/// 该类型保留旧名称以兼容历史调用点;新代码应改用 <see cref="GFramework.Core.Cqrs.Extensions.ContextAwareCqrsExtensions" />。
|
||||
/// </summary>
|
||||
[Obsolete("Use GFramework.Core.Cqrs.Extensions.ContextAwareCqrsExtensions instead.")]
|
||||
public static class ContextAwareMediatorExtensions
|
||||
{
|
||||
/// <summary>
|
||||
@ -20,11 +23,10 @@ public static class ContextAwareMediatorExtensions
|
||||
public static ValueTask<TResponse> SendRequestAsync<TResponse>(this IContextAware contextAware,
|
||||
IRequest<TResponse> request, CancellationToken cancellationToken = default)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(contextAware);
|
||||
ArgumentNullException.ThrowIfNull(request);
|
||||
|
||||
var context = contextAware.GetContext();
|
||||
return context.SendRequestAsync(request, cancellationToken);
|
||||
return ContextAwareCqrsExtensions.SendRequestAsync(
|
||||
contextAware,
|
||||
request,
|
||||
cancellationToken);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -38,11 +40,7 @@ public static class ContextAwareMediatorExtensions
|
||||
public static TResponse SendRequest<TResponse>(this IContextAware contextAware,
|
||||
IRequest<TResponse> request)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(contextAware);
|
||||
ArgumentNullException.ThrowIfNull(request);
|
||||
|
||||
var context = contextAware.GetContext();
|
||||
return context.SendRequest(request);
|
||||
return ContextAwareCqrsExtensions.SendRequest(contextAware, request);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -58,11 +56,10 @@ public static class ContextAwareMediatorExtensions
|
||||
TNotification notification, CancellationToken cancellationToken = default)
|
||||
where TNotification : INotification
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(contextAware);
|
||||
ArgumentNullException.ThrowIfNull(notification);
|
||||
|
||||
var context = contextAware.GetContext();
|
||||
return context.PublishAsync(notification, cancellationToken);
|
||||
return ContextAwareCqrsExtensions.PublishAsync(
|
||||
contextAware,
|
||||
notification,
|
||||
cancellationToken);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -77,11 +74,10 @@ public static class ContextAwareMediatorExtensions
|
||||
public static IAsyncEnumerable<TResponse> CreateStream<TResponse>(this IContextAware contextAware,
|
||||
IStreamRequest<TResponse> request, CancellationToken cancellationToken = default)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(contextAware);
|
||||
ArgumentNullException.ThrowIfNull(request);
|
||||
|
||||
var context = contextAware.GetContext();
|
||||
return context.CreateStream(request, cancellationToken);
|
||||
return ContextAwareCqrsExtensions.CreateStream(
|
||||
contextAware,
|
||||
request,
|
||||
cancellationToken);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -97,11 +93,10 @@ public static class ContextAwareMediatorExtensions
|
||||
CancellationToken cancellationToken = default)
|
||||
where TCommand : IRequest<Unit>
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(contextAware);
|
||||
ArgumentNullException.ThrowIfNull(command);
|
||||
|
||||
var context = contextAware.GetContext();
|
||||
return context.SendAsync(command, cancellationToken);
|
||||
return ContextAwareCqrsExtensions.SendAsync(
|
||||
contextAware,
|
||||
command,
|
||||
cancellationToken);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -116,10 +111,9 @@ public static class ContextAwareMediatorExtensions
|
||||
public static ValueTask<TResponse> SendAsync<TResponse>(this IContextAware contextAware,
|
||||
IRequest<TResponse> command, CancellationToken cancellationToken = default)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(contextAware);
|
||||
ArgumentNullException.ThrowIfNull(command);
|
||||
|
||||
var context = contextAware.GetContext();
|
||||
return context.SendAsync(command, cancellationToken);
|
||||
return ContextAwareCqrsExtensions.SendAsync(
|
||||
contextAware,
|
||||
command,
|
||||
cancellationToken);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,11 +1,14 @@
|
||||
using GFramework.Core.Abstractions.Rule;
|
||||
using GFramework.Core.Abstractions.Cqrs.Query;
|
||||
using GFramework.Core.Abstractions.Rule;
|
||||
using GFramework.Core.Cqrs.Extensions;
|
||||
|
||||
namespace GFramework.Core.Extensions;
|
||||
|
||||
/// <summary>
|
||||
/// 提供对 IContextAware 接口的 CQRS 查询扩展方法。
|
||||
/// 提供对 <see cref="IContextAware" /> 接口的 CQRS 查询扩展方法。
|
||||
/// 该类型保留旧名称以兼容历史调用点;新代码应改用 <see cref="GFramework.Core.Cqrs.Extensions.ContextAwareCqrsQueryExtensions" />。
|
||||
/// </summary>
|
||||
[Obsolete("Use GFramework.Core.Cqrs.Extensions.ContextAwareCqrsQueryExtensions instead.")]
|
||||
public static class ContextAwareMediatorQueryExtensions
|
||||
{
|
||||
/// <summary>
|
||||
@ -18,11 +21,7 @@ public static class ContextAwareMediatorQueryExtensions
|
||||
/// <exception cref="ArgumentNullException">当 contextAware 或 query 为 null 时抛出</exception>
|
||||
public static TResponse SendQuery<TResponse>(this IContextAware contextAware, IQuery<TResponse> query)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(contextAware);
|
||||
ArgumentNullException.ThrowIfNull(query);
|
||||
|
||||
var context = contextAware.GetContext();
|
||||
return context.SendQuery(query);
|
||||
return ContextAwareCqrsQueryExtensions.SendQuery(contextAware, query);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -37,10 +36,9 @@ public static class ContextAwareMediatorQueryExtensions
|
||||
public static ValueTask<TResponse> SendQueryAsync<TResponse>(this IContextAware contextAware,
|
||||
IQuery<TResponse> query, CancellationToken cancellationToken = default)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(contextAware);
|
||||
ArgumentNullException.ThrowIfNull(query);
|
||||
|
||||
var context = contextAware.GetContext();
|
||||
return context.SendQueryAsync(query, cancellationToken);
|
||||
return ContextAwareCqrsQueryExtensions.SendQueryAsync(
|
||||
contextAware,
|
||||
query,
|
||||
cancellationToken);
|
||||
}
|
||||
}
|
||||
|
||||
@ -310,12 +310,11 @@ public class MicrosoftDiContainer(IServiceCollection? serviceCollection = null)
|
||||
|
||||
/// <summary>
|
||||
/// 注册 CQRS 请求管道行为。
|
||||
/// 历史方法名保留了 Mediator 前缀,但当前用于配置框架内建 CQRS runtime 的行为拦截和处理逻辑。
|
||||
/// 同时支持开放泛型行为类型和已闭合的具体行为类型,
|
||||
/// 以兼容通用行为和针对单一请求的专用行为两种注册方式。
|
||||
/// </summary>
|
||||
/// <typeparam name="TBehavior">行为类型,必须是引用类型</typeparam>
|
||||
public void RegisterMediatorBehavior<TBehavior>() where TBehavior : class
|
||||
public void RegisterCqrsPipelineBehavior<TBehavior>() where TBehavior : class
|
||||
{
|
||||
_lock.EnterWriteLock();
|
||||
try
|
||||
@ -358,6 +357,17 @@ public class MicrosoftDiContainer(IServiceCollection? serviceCollection = null)
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 注册 CQRS 请求管道行为。
|
||||
/// 该成员保留旧名称以兼容历史调用点,内部行为与 <see cref="RegisterCqrsPipelineBehavior{TBehavior}" /> 一致。
|
||||
/// </summary>
|
||||
/// <typeparam name="TBehavior">行为类型,必须是引用类型</typeparam>
|
||||
[Obsolete("Use RegisterCqrsPipelineBehavior<TBehavior>() instead.")]
|
||||
public void RegisterMediatorBehavior<TBehavior>() where TBehavior : class
|
||||
{
|
||||
RegisterCqrsPipelineBehavior<TBehavior>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 配置服务
|
||||
/// </summary>
|
||||
|
||||
@ -2,9 +2,6 @@
|
||||
using GFramework.Core.Abstractions.Cqrs.Command;
|
||||
using GFramework.Core.Abstractions.Cqrs.Query;
|
||||
using GFramework.Core.Abstractions.Rule;
|
||||
using GFramework.Core.Coroutine;
|
||||
using GFramework.Core.Coroutine.Extensions;
|
||||
using GFramework.Core.Extensions;
|
||||
|
||||
namespace GFramework.Godot.Coroutine;
|
||||
|
||||
@ -29,8 +26,8 @@ public static class ContextAwareCoroutineExtensions
|
||||
string? tag = null,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
return contextAware
|
||||
.SendCommandAsync(command, cancellationToken)
|
||||
return Core.Cqrs.Extensions.ContextAwareCqrsCommandExtensions
|
||||
.SendCommandAsync(contextAware, command, cancellationToken)
|
||||
.AsTask()
|
||||
.ToCoroutineEnumerator()
|
||||
.RunCoroutine(segment, tag);
|
||||
@ -53,8 +50,8 @@ public static class ContextAwareCoroutineExtensions
|
||||
string? tag = null,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
return contextAware
|
||||
.SendCommandAsync(command, cancellationToken)
|
||||
return Core.Cqrs.Extensions.ContextAwareCqrsCommandExtensions
|
||||
.SendCommandAsync(contextAware, command, cancellationToken)
|
||||
.AsTask()
|
||||
.ToCoroutineEnumerator()
|
||||
.RunCoroutine(segment, tag);
|
||||
@ -77,8 +74,8 @@ public static class ContextAwareCoroutineExtensions
|
||||
string? tag = null,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
return contextAware
|
||||
.SendQueryAsync(query, cancellationToken)
|
||||
return Core.Cqrs.Extensions.ContextAwareCqrsQueryExtensions
|
||||
.SendQueryAsync(contextAware, query, cancellationToken)
|
||||
.AsTask()
|
||||
.ToCoroutineEnumerator()
|
||||
.RunCoroutine(segment, tag);
|
||||
@ -100,8 +97,8 @@ public static class ContextAwareCoroutineExtensions
|
||||
string? tag = null,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
return contextAware
|
||||
.PublishAsync(notification, cancellationToken)
|
||||
return Core.Cqrs.Extensions.ContextAwareCqrsExtensions
|
||||
.PublishAsync(contextAware, notification, cancellationToken)
|
||||
.AsTask()
|
||||
.ToCoroutineEnumerator()
|
||||
.RunCoroutine(segment, tag);
|
||||
|
||||
@ -212,15 +212,16 @@ public class GameArchitecture : Architecture
|
||||
protected override void Init()
|
||||
{
|
||||
// 注册通用开放泛型行为
|
||||
RegisterMediatorBehavior<LoggingBehavior<,>>();
|
||||
RegisterMediatorBehavior<PerformanceBehavior<,>>();
|
||||
RegisterCqrsPipelineBehavior<LoggingBehavior<,>>();
|
||||
RegisterCqrsPipelineBehavior<PerformanceBehavior<,>>();
|
||||
|
||||
// 处理器会自动通过依赖注入注册
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
`RegisterMediatorBehavior<TBehavior>()` 是保留的兼容名称,当前用于注册框架内建 CQRS pipeline,支持两种形式:
|
||||
`RegisterCqrsPipelineBehavior<TBehavior>()` 是推荐入口;旧的 `RegisterMediatorBehavior<TBehavior>()`
|
||||
仅作为兼容名称保留。当前接口支持两种形式:
|
||||
|
||||
- 开放泛型行为,例如 `LoggingBehavior<,>`,用于匹配所有请求
|
||||
- 封闭行为类型,例如某个只服务于单一请求的 `SpecialBehavior`
|
||||
@ -377,8 +378,8 @@ public class PerformanceBehavior<TMessage, TResponse> : IPipelineBehavior<TMessa
|
||||
}
|
||||
|
||||
// 注册行为
|
||||
RegisterMediatorBehavior<LoggingBehavior<,>>();
|
||||
RegisterMediatorBehavior<PerformanceBehavior<,>>();
|
||||
RegisterCqrsPipelineBehavior<LoggingBehavior<,>>();
|
||||
RegisterCqrsPipelineBehavior<PerformanceBehavior<,>>();
|
||||
```
|
||||
|
||||
### 验证行为
|
||||
@ -471,8 +472,8 @@ await foreach (var player in stream)
|
||||
|
||||
4. **使用 Behaviors 处理横切关注点**:日志、性能、验证等
|
||||
```csharp
|
||||
RegisterMediatorBehavior<LoggingBehavior<,>>();
|
||||
RegisterMediatorBehavior<ValidationBehavior<,>>();
|
||||
RegisterCqrsPipelineBehavior<LoggingBehavior<,>>();
|
||||
RegisterCqrsPipelineBehavior<ValidationBehavior<,>>();
|
||||
```
|
||||
|
||||
5. **保持处理器简单**:一个处理器只做一件事
|
||||
|
||||
@ -396,12 +396,12 @@ public class PlayerController : IController
|
||||
**核心功能**:
|
||||
|
||||
- 模块安装 (IArchitectureModule)
|
||||
- CQRS 管道行为注册(历史 API 名称仍为 `RegisterMediatorBehavior`)
|
||||
- CQRS 管道行为注册(推荐 API 为 `RegisterCqrsPipelineBehavior`)
|
||||
|
||||
**关键方法**:
|
||||
|
||||
- `InstallModule()` - 安装模块
|
||||
- `RegisterMediatorBehavior<T>()` - 注册 CQRS 管道行为
|
||||
- `RegisterCqrsPipelineBehavior<T>()` - 注册 CQRS 管道行为
|
||||
|
||||
#### 设计优势
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user