Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,8 @@ Architecture 负责统一生命周期编排,核心阶段包括:

### CQRS

命令与查询分离,支持同步与异步执行。Mediator 模式通过源码生成器集成,以减少模板代码并保持调用路径清晰。
命令与查询分离,支持同步与异步执行。当前版本内建自有 CQRS runtime、行为管道和 handler 自动注册;公开 API 里仍保留少量历史
`Mediator` 命名以兼容旧调用点。

### EventBus

Expand Down
16 changes: 13 additions & 3 deletions GFramework.Core.Abstractions/Architectures/IArchitecture.cs
Original file line number Diff line number Diff line change
Expand Up @@ -73,12 +73,22 @@ public interface IArchitecture : IAsyncInitializable, IAsyncDestroyable, IInitia
void RegisterUtility<T>(Action<T>? onCreated = null) where T : class, IUtility;

/// <summary>
/// 注册中介行为管道
/// 用于配置Mediator框架的行为拦截和处理逻辑。
/// 注册 CQRS 请求管道行为。
/// 既支持实现 <c>IPipelineBehavior&lt;,&gt;</c> 的开放泛型行为类型,
/// 也支持绑定到单一请求/响应对的封闭行为类型。
/// </summary>
/// <typeparam name="TBehavior">行为类型,必须是引用类型</typeparam>
void RegisterCqrsPipelineBehavior<TBehavior>()
where TBehavior : class;

/// <summary>
/// 注册 CQRS 请求管道行为。
/// 该成员保留旧名称以兼容历史调用点,内部行为与 <see cref="RegisterCqrsPipelineBehavior{TBehavior}" /> 一致。
/// 既支持实现 <c>IPipelineBehavior&lt;,&gt;</c> 的开放泛型行为类型,
/// 也支持绑定到单一请求/响应对的封闭行为类型。
/// </summary>
/// <typeparam name="TBehavior">行为类型,必须是引用类型</typeparam>
[Obsolete("Use RegisterCqrsPipelineBehavior<TBehavior>() instead.")]
void RegisterMediatorBehavior<TBehavior>()
where TBehavior : class;

Expand All @@ -101,4 +111,4 @@ void RegisterMediatorBehavior<TBehavior>()
/// </summary>
/// <returns>表示异步等待操作的任务</returns>
Task WaitUntilReadyAsync();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,6 @@
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
</PackageReference>
<PackageReference Include="Mediator.Abstractions" Version="3.0.2"/>
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="10.0.5"/>
</ItemGroup>
</Project>
14 changes: 11 additions & 3 deletions GFramework.Core.Abstractions/Ioc/IIocContainer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -90,10 +90,18 @@ void RegisterScoped<TService, TImpl>()
void RegisterFactory<TService>(Func<IServiceProvider, TService> factory) where TService : class;

/// <summary>
/// 注册中介行为管道
/// 用于配置Mediator框架的行为拦截和处理逻辑
/// 注册 CQRS 请求管道行为。
/// </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;

Expand Down Expand Up @@ -227,4 +235,4 @@ void RegisterMediatorBehavior<TBehavior>()
IServiceScope CreateScope();

#endregion
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,28 @@ public async Task InstallModule_Should_Invoke_Module_Install_With_Current_Archit
/// 验证注册的 CQRS 行为会参与请求管道执行。
/// </summary>
[Test]
public async Task RegisterCqrsPipelineBehavior_Should_Apply_Pipeline_Behavior_To_Request()
{
var architecture = new ModuleTestArchitecture(target =>
target.RegisterCqrsPipelineBehavior<TrackingPipelineBehavior<ModuleBehaviorRequest, string>>());
Comment thread
coderabbitai[bot] marked this conversation as resolved.

await architecture.InitializeAsync();

var response = await architecture.Context.SendRequestAsync(new ModuleBehaviorRequest());

Assert.Multiple(() =>
{
Assert.That(response, Is.EqualTo("handled"));
Assert.That(TrackingPipelineBehavior<ModuleBehaviorRequest, string>.InvocationCount, Is.EqualTo(1));
});

await architecture.DestroyAsync();
}

/// <summary>
/// 验证兼容别名 <c>RegisterMediatorBehavior</c> 仍会把 CQRS 行为接入请求管道。
/// </summary>
[Test]
public async Task RegisterMediatorBehavior_Should_Apply_Pipeline_Behavior_To_Request()
{
var architecture = new ModuleTestArchitecture(target =>
Expand Down
31 changes: 15 additions & 16 deletions GFramework.Core.Tests/Architectures/ArchitectureServicesTests.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using GFramework.Core.Abstractions.Architectures;
using GFramework.Core.Abstractions.Command;
using GFramework.Core.Abstractions.Cqrs;
using GFramework.Core.Abstractions.Environment;
using GFramework.Core.Abstractions.Events;
using GFramework.Core.Abstractions.Ioc;
Expand All @@ -13,7 +14,6 @@
using GFramework.Core.Events;
using GFramework.Core.Ioc;
using GFramework.Core.Query;
using Mediator;
using ICommand = GFramework.Core.Abstractions.Command.ICommand;

namespace GFramework.Core.Tests.Architectures;
Expand All @@ -34,16 +34,17 @@ namespace GFramework.Core.Tests.Architectures;
[TestFixture]
public class ArchitectureServicesTests
{
private TestArchitectureContextV3? _context;

private ArchitectureServices? _services;

[SetUp]
public void SetUp()
{
_services = new ArchitectureServices();
_context = new TestArchitectureContextV3();
}

private ArchitectureServices? _services;
private TestArchitectureContextV3? _context;

private void RegisterBuiltInServices()
{
_services!.ModuleManager.RegisterBuiltInModules(_services.Container);
Expand Down Expand Up @@ -347,61 +348,59 @@ public void UnRegisterEvent<TEvent>(Action<TEvent> onEvent)
{
}

public ValueTask<TResponse> SendRequestAsync<TResponse>(global::GFramework.Core.Abstractions.Cqrs.IRequest<TResponse> request,
public ValueTask<TResponse> SendRequestAsync<TResponse>(IRequest<TResponse> request,
CancellationToken cancellationToken = default)
{
throw new NotImplementedException();
}

public TResponse SendRequest<TResponse>(global::GFramework.Core.Abstractions.Cqrs.IRequest<TResponse> request)
public TResponse SendRequest<TResponse>(IRequest<TResponse> request)
{
throw new NotImplementedException();
}

public ValueTask<TResponse> SendCommandAsync<TResponse>(
global::GFramework.Core.Abstractions.Cqrs.Command.ICommand<TResponse> command,
public ValueTask<TResponse> SendCommandAsync<TResponse>(Abstractions.Cqrs.Command.ICommand<TResponse> command,
CancellationToken cancellationToken = default)
{
throw new NotImplementedException();
}

public TResponse SendCommand<TResponse>(global::GFramework.Core.Abstractions.Cqrs.Command.ICommand<TResponse> command)
public TResponse SendCommand<TResponse>(Abstractions.Cqrs.Command.ICommand<TResponse> command)
{
throw new NotImplementedException();
}

public ValueTask<TResponse> SendQueryAsync<TResponse>(
global::GFramework.Core.Abstractions.Cqrs.Query.IQuery<TResponse> query,
public ValueTask<TResponse> SendQueryAsync<TResponse>(Abstractions.Cqrs.Query.IQuery<TResponse> query,
CancellationToken cancellationToken = default)
{
throw new NotImplementedException();
}

public TResponse SendQuery<TResponse>(global::GFramework.Core.Abstractions.Cqrs.Query.IQuery<TResponse> query)
public TResponse SendQuery<TResponse>(Abstractions.Cqrs.Query.IQuery<TResponse> query)
{
throw new NotImplementedException();
}

public ValueTask PublishAsync<TNotification>(TNotification notification,
CancellationToken cancellationToken = default) where TNotification : global::GFramework.Core.Abstractions.Cqrs.INotification
CancellationToken cancellationToken = default) where TNotification : INotification
{
throw new NotImplementedException();
}

public IAsyncEnumerable<TResponse> CreateStream<TResponse>(
global::GFramework.Core.Abstractions.Cqrs.IStreamRequest<TResponse> request,
IStreamRequest<TResponse> request,
CancellationToken cancellationToken = default)
{
throw new NotImplementedException();
}

public ValueTask SendAsync<TCommand>(TCommand command, CancellationToken cancellationToken = default)
where TCommand : global::GFramework.Core.Abstractions.Cqrs.IRequest<global::GFramework.Core.Abstractions.Cqrs.Unit>
where TCommand : IRequest<Unit>
{
throw new NotImplementedException();
}

public ValueTask<TResponse> SendAsync<TResponse>(global::GFramework.Core.Abstractions.Cqrs.IRequest<TResponse> command,
public ValueTask<TResponse> SendAsync<TResponse>(IRequest<TResponse> command,
CancellationToken cancellationToken = default)
{
throw new NotImplementedException();
Expand Down
105 changes: 90 additions & 15 deletions GFramework.Core.Tests/Architectures/GameContextTests.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using GFramework.Core.Abstractions.Architectures;
using GFramework.Core.Abstractions.Command;
using GFramework.Core.Abstractions.Cqrs;
using GFramework.Core.Abstractions.Environment;
using GFramework.Core.Abstractions.Events;
using GFramework.Core.Abstractions.Ioc;
Expand All @@ -13,7 +14,6 @@
using GFramework.Core.Events;
using GFramework.Core.Ioc;
using GFramework.Core.Query;
using Mediator;
using ICommand = GFramework.Core.Abstractions.Command.ICommand;

namespace GFramework.Core.Tests.Architectures;
Expand Down Expand Up @@ -394,61 +394,136 @@ public void UnRegisterEvent<TEvent>(Action<TEvent> onEvent)
{
}

public ValueTask<TResponse> SendRequestAsync<TResponse>(global::GFramework.Core.Abstractions.Cqrs.IRequest<TResponse> request,
/// <summary>
/// 测试桩:异步发送统一 CQRS 请求。
/// </summary>
/// <typeparam name="TResponse">响应类型。</typeparam>
/// <param name="request">要发送的请求。</param>
/// <param name="cancellationToken">取消令牌。</param>
/// <returns>请求响应任务。</returns>
/// <exception cref="NotImplementedException">该测试桩未实现此成员。</exception>
public ValueTask<TResponse> SendRequestAsync<TResponse>(IRequest<TResponse> request,
CancellationToken cancellationToken = default)
{
throw new NotImplementedException();
}

public TResponse SendRequest<TResponse>(global::GFramework.Core.Abstractions.Cqrs.IRequest<TResponse> request)
/// <summary>
/// 测试桩:同步发送统一 CQRS 请求。
/// </summary>
/// <typeparam name="TResponse">响应类型。</typeparam>
/// <param name="request">要发送的请求。</param>
/// <returns>请求响应。</returns>
/// <exception cref="NotImplementedException">该测试桩未实现此成员。</exception>
public TResponse SendRequest<TResponse>(IRequest<TResponse> request)
{
throw new NotImplementedException();
}

public ValueTask<TResponse> SendCommandAsync<TResponse>(
global::GFramework.Core.Abstractions.Cqrs.Command.ICommand<TResponse> command,
/// <summary>
/// 测试桩:异步发送 CQRS 命令并返回响应。
/// </summary>
/// <typeparam name="TResponse">命令响应类型。</typeparam>
/// <param name="command">要发送的命令。</param>
/// <param name="cancellationToken">取消令牌。</param>
/// <returns>命令响应任务。</returns>
/// <exception cref="NotImplementedException">该测试桩未实现此成员。</exception>
public ValueTask<TResponse> SendCommandAsync<TResponse>(Abstractions.Cqrs.Command.ICommand<TResponse> command,
CancellationToken cancellationToken = default)
{
throw new NotImplementedException();
}

public TResponse SendCommand<TResponse>(global::GFramework.Core.Abstractions.Cqrs.Command.ICommand<TResponse> command)
/// <summary>
/// 测试桩:同步发送 CQRS 命令并返回响应。
/// </summary>
/// <typeparam name="TResponse">命令响应类型。</typeparam>
/// <param name="command">要发送的命令。</param>
/// <returns>命令响应。</returns>
/// <exception cref="NotImplementedException">该测试桩未实现此成员。</exception>
public TResponse SendCommand<TResponse>(Abstractions.Cqrs.Command.ICommand<TResponse> command)
{
throw new NotImplementedException();
}

public ValueTask<TResponse> SendQueryAsync<TResponse>(
global::GFramework.Core.Abstractions.Cqrs.Query.IQuery<TResponse> query,
/// <summary>
/// 测试桩:异步发送 CQRS 查询并返回结果。
/// </summary>
/// <typeparam name="TResponse">查询结果类型。</typeparam>
/// <param name="query">要发送的查询。</param>
/// <param name="cancellationToken">取消令牌。</param>
/// <returns>查询结果任务。</returns>
/// <exception cref="NotImplementedException">该测试桩未实现此成员。</exception>
public ValueTask<TResponse> SendQueryAsync<TResponse>(Abstractions.Cqrs.Query.IQuery<TResponse> query,
CancellationToken cancellationToken = default)
{
throw new NotImplementedException();
}

public TResponse SendQuery<TResponse>(global::GFramework.Core.Abstractions.Cqrs.Query.IQuery<TResponse> query)
/// <summary>
/// 测试桩:同步发送 CQRS 查询并返回结果。
/// </summary>
/// <typeparam name="TResponse">查询结果类型。</typeparam>
/// <param name="query">要发送的查询。</param>
/// <returns>查询结果。</returns>
/// <exception cref="NotImplementedException">该测试桩未实现此成员。</exception>
public TResponse SendQuery<TResponse>(Abstractions.Cqrs.Query.IQuery<TResponse> query)
{
throw new NotImplementedException();
}

/// <summary>
/// 测试桩:异步发布 CQRS 通知。
/// </summary>
/// <typeparam name="TNotification">通知类型。</typeparam>
/// <param name="notification">要发布的通知。</param>
/// <param name="cancellationToken">取消令牌。</param>
/// <returns>通知发布任务。</returns>
/// <exception cref="NotImplementedException">该测试桩未实现此成员。</exception>
public ValueTask PublishAsync<TNotification>(TNotification notification,
CancellationToken cancellationToken = default) where TNotification : global::GFramework.Core.Abstractions.Cqrs.INotification
CancellationToken cancellationToken = default) where TNotification : INotification
{
throw new NotImplementedException();
}

/// <summary>
/// 测试桩:创建 CQRS 流式请求响应序列。
/// </summary>
/// <typeparam name="TResponse">流式响应元素类型。</typeparam>
/// <param name="request">流式请求。</param>
/// <param name="cancellationToken">取消令牌。</param>
/// <returns>异步响应流。</returns>
/// <exception cref="NotImplementedException">该测试桩未实现此成员。</exception>
public IAsyncEnumerable<TResponse> CreateStream<TResponse>(
global::GFramework.Core.Abstractions.Cqrs.IStreamRequest<TResponse> request,
IStreamRequest<TResponse> request,
CancellationToken cancellationToken = default)
{
throw new NotImplementedException();
}

/// <summary>
/// 测试桩:异步发送无返回值 CQRS 命令。
/// </summary>
/// <typeparam name="TCommand">命令类型。</typeparam>
/// <param name="command">要发送的命令。</param>
/// <param name="cancellationToken">取消令牌。</param>
/// <returns>命令发送任务。</returns>
/// <exception cref="NotImplementedException">该测试桩未实现此成员。</exception>
public ValueTask SendAsync<TCommand>(TCommand command, CancellationToken cancellationToken = default)
where TCommand : global::GFramework.Core.Abstractions.Cqrs.IRequest<global::GFramework.Core.Abstractions.Cqrs.Unit>
where TCommand : IRequest<Unit>
{
throw new NotImplementedException();
}

public ValueTask<TResponse> SendAsync<TResponse>(global::GFramework.Core.Abstractions.Cqrs.IRequest<TResponse> command,
/// <summary>
/// 测试桩:异步发送带返回值的 CQRS 请求。
/// </summary>
/// <typeparam name="TResponse">响应类型。</typeparam>
/// <param name="command">要发送的请求。</param>
/// <param name="cancellationToken">取消令牌。</param>
/// <returns>请求响应任务。</returns>
/// <exception cref="NotImplementedException">该测试桩未实现此成员。</exception>
public ValueTask<TResponse> SendAsync<TResponse>(IRequest<TResponse> command,
CancellationToken cancellationToken = default)
{
throw new NotImplementedException();
Expand All @@ -468,7 +543,7 @@ public void SendCommand(ICommand command)
/// <typeparam name="TResult">返回值类型</typeparam>
/// <param name="command">命令对象</param>
/// <returns>命令执行结果</returns>
public TResult SendCommand<TResult>(Abstractions.Command.ICommand<TResult> command)
public TResult SendCommand<TResult>(ICommand<TResult> command)
{
return default!;
}
Expand All @@ -489,7 +564,7 @@ public Task<TResult> SendCommandAsync<TResult>(IAsyncCommand<TResult> command)
/// <typeparam name="TResult">查询结果类型</typeparam>
/// <param name="query">查询对象</param>
/// <returns>查询结果</returns>
public TResult SendQuery<TResult>(Abstractions.Query.IQuery<TResult> query)
public TResult SendQuery<TResult>(IQuery<TResult> query)
{
return default!;
}
Expand Down
Loading
Loading