feat(architecture): 添加异步查询总线支持

- 在Architecture类中添加AsyncQueryBus属性
- 在ArchitectureContext中添加异步查询执行方法SendQueryAsync
- 在ArchitectureServices中添加AsyncQueryBus服务实例
- 扩展IArchitectureContext接口以包含异步查询方法
- 扩展IArchitectureServices接口以包含异步查询总线
- 更新ArchitectureContext构造函数以接受异步查询总线参数
- 为ArchitectureContextTests添加异步查询总线相关测试用例
- 更新测试中的构造函数调用以包含新的异步查询总线参数
This commit is contained in:
GeWuYou 2026-01-18 20:53:44 +08:00
parent 15844b7077
commit 1c1385ee24
9 changed files with 129 additions and 12 deletions

View File

@ -72,6 +72,14 @@ public interface IArchitectureContext
/// <returns>查询结果</returns> /// <returns>查询结果</returns>
TResult SendQuery<TResult>(IQuery<TResult> query); TResult SendQuery<TResult>(IQuery<TResult> query);
/// <summary>
/// 异步发送一个查询请求
/// </summary>
/// <typeparam name="TResult">查询结果类型</typeparam>
/// <param name="query">要发送的异步查询</param>
/// <returns>查询结果</returns>
Task<TResult> SendQueryAsync<TResult>(IAsyncQuery<TResult> query);
/// <summary> /// <summary>
/// 发送一个事件 /// 发送一个事件
/// </summary> /// </summary>

View File

@ -1,4 +1,4 @@
using GFramework.Core.Abstractions.command; using GFramework.Core.Abstractions.command;
using GFramework.Core.Abstractions.events; using GFramework.Core.Abstractions.events;
using GFramework.Core.Abstractions.ioc; using GFramework.Core.Abstractions.ioc;
using GFramework.Core.Abstractions.query; using GFramework.Core.Abstractions.query;
@ -32,4 +32,9 @@ public interface IArchitectureServices : IContextAware
/// 获取查询总线 /// 获取查询总线
/// </summary> /// </summary>
public IQueryBus QueryBus { get; } public IQueryBus QueryBus { get; }
/// <summary>
/// 获取异步查询总线
/// </summary>
public IAsyncQueryBus AsyncQueryBus { get; }
} }

View File

@ -60,8 +60,9 @@ public class ArchitectureContextTests
_eventBus = new EventBus(); _eventBus = new EventBus();
_commandBus = new CommandBus(); _commandBus = new CommandBus();
_queryBus = new QueryBus(); _queryBus = new QueryBus();
_asyncQueryBus = new AsyncQueryBus();
_environment = new DefaultEnvironment(); _environment = new DefaultEnvironment();
_context = new ArchitectureContext(_container, _eventBus, _commandBus, _queryBus, _environment); _context = new ArchitectureContext(_container, _eventBus, _commandBus, _queryBus, _environment, _asyncQueryBus);
} }
private ArchitectureContext? _context; private ArchitectureContext? _context;
@ -69,6 +70,7 @@ public class ArchitectureContextTests
private EventBus? _eventBus; private EventBus? _eventBus;
private CommandBus? _commandBus; private CommandBus? _commandBus;
private QueryBus? _queryBus; private QueryBus? _queryBus;
private AsyncQueryBus? _asyncQueryBus;
private DefaultEnvironment? _environment; private DefaultEnvironment? _environment;
/// <summary> /// <summary>
@ -77,17 +79,75 @@ public class ArchitectureContextTests
[Test] [Test]
public void Constructor_Should_NotThrow_When_AllParameters_AreValid() public void Constructor_Should_NotThrow_When_AllParameters_AreValid()
{ {
Assert.That(() => new ArchitectureContext(_container!, _eventBus!, _commandBus!, _queryBus!, _environment!), Assert.That(
() => new ArchitectureContext(_container!, _eventBus!, _commandBus!, _queryBus!, _environment!,
_asyncQueryBus!),
Throws.Nothing); Throws.Nothing);
} }
/// <summary>
/// 测试构造函数在 container 为 null 时应抛出 ArgumentNullException
/// </summary>
[Test]
public void Constructor_Should_Throw_When_Container_IsNull()
{
Assert.That(
() => new ArchitectureContext(null!, _eventBus!, _commandBus!, _queryBus!, _environment!, _asyncQueryBus!),
Throws.ArgumentNullException);
}
/// <summary>
/// 测试构造函数在 eventBus 为 null 时应抛出 ArgumentNullException
/// </summary>
[Test]
public void Constructor_Should_Throw_When_EventBus_IsNull()
{
Assert.That(
() => new ArchitectureContext(_container!, null!, _commandBus!, _queryBus!, _environment!, _asyncQueryBus!),
Throws.ArgumentNullException);
}
/// <summary>
/// 测试构造函数在 commandBus 为 null 时应抛出 ArgumentNullException
/// </summary>
[Test]
public void Constructor_Should_Throw_When_CommandBus_IsNull()
{
Assert.That(
() => new ArchitectureContext(_container!, _eventBus!, null!, _queryBus!, _environment!, _asyncQueryBus!),
Throws.ArgumentNullException);
}
/// <summary>
/// 测试构造函数在 queryBus 为 null 时应抛出 ArgumentNullException
/// </summary>
[Test]
public void Constructor_Should_Throw_When_QueryBus_IsNull()
{
Assert.That(
() => new ArchitectureContext(_container!, _eventBus!, _commandBus!, null!, _environment!, _asyncQueryBus!),
Throws.ArgumentNullException);
}
/// <summary>
/// 测试构造函数在 environment 为 null 时应抛出 ArgumentNullException
/// </summary>
[Test]
public void Constructor_Should_Throw_When_Environment_IsNull()
{
Assert.That(
() => new ArchitectureContext(_container!, _eventBus!, _commandBus!, _queryBus!, null!, _asyncQueryBus!),
Throws.ArgumentNullException);
}
/// <summary> /// <summary>
/// 测试构造函数在Container为null时应抛出ArgumentNullException /// 测试构造函数在Container为null时应抛出ArgumentNullException
/// </summary> /// </summary>
[Test] [Test]
public void Constructor_Should_ThrowArgumentNullException_When_Container_IsNull() public void Constructor_Should_ThrowArgumentNullException_When_Container_IsNull()
{ {
Assert.That(() => new ArchitectureContext(null!, _eventBus!, _commandBus!, _queryBus!, _environment!), Assert.That(
() => new ArchitectureContext(null!, _eventBus!, _commandBus!, _queryBus!, _environment!, _asyncQueryBus!),
Throws.ArgumentNullException.With.Property("ParamName").EqualTo("container")); Throws.ArgumentNullException.With.Property("ParamName").EqualTo("container"));
} }
@ -97,7 +157,8 @@ public class ArchitectureContextTests
[Test] [Test]
public void Constructor_Should_ThrowArgumentNullException_When_EventBus_IsNull() public void Constructor_Should_ThrowArgumentNullException_When_EventBus_IsNull()
{ {
Assert.That(() => new ArchitectureContext(_container!, null!, _commandBus!, _queryBus!, _environment!), Assert.That(
() => new ArchitectureContext(_container!, null!, _commandBus!, _queryBus!, _environment!, _asyncQueryBus!),
Throws.ArgumentNullException.With.Property("ParamName").EqualTo("eventBus")); Throws.ArgumentNullException.With.Property("ParamName").EqualTo("eventBus"));
} }
@ -107,7 +168,8 @@ public class ArchitectureContextTests
[Test] [Test]
public void Constructor_Should_ThrowArgumentNullException_When_CommandBus_IsNull() public void Constructor_Should_ThrowArgumentNullException_When_CommandBus_IsNull()
{ {
Assert.That(() => new ArchitectureContext(_container!, _eventBus!, null!, _queryBus!, _environment!), Assert.That(
() => new ArchitectureContext(_container!, _eventBus!, null!, _queryBus!, _environment!, _asyncQueryBus!),
Throws.ArgumentNullException.With.Property("ParamName").EqualTo("commandBus")); Throws.ArgumentNullException.With.Property("ParamName").EqualTo("commandBus"));
} }
@ -117,7 +179,8 @@ public class ArchitectureContextTests
[Test] [Test]
public void Constructor_Should_ThrowArgumentNullException_When_QueryBus_IsNull() public void Constructor_Should_ThrowArgumentNullException_When_QueryBus_IsNull()
{ {
Assert.That(() => new ArchitectureContext(_container!, _eventBus!, _commandBus!, null!, _environment!), Assert.That(
() => new ArchitectureContext(_container!, _eventBus!, _commandBus!, null!, _environment!, _asyncQueryBus!),
Throws.ArgumentNullException.With.Property("ParamName").EqualTo("queryBus")); Throws.ArgumentNullException.With.Property("ParamName").EqualTo("queryBus"));
} }
@ -127,7 +190,8 @@ public class ArchitectureContextTests
[Test] [Test]
public void Constructor_Should_ThrowArgumentNullException_When_Environment_IsNull() public void Constructor_Should_ThrowArgumentNullException_When_Environment_IsNull()
{ {
Assert.That(() => new ArchitectureContext(_container!, _eventBus!, _commandBus!, _queryBus!, null!), Assert.That(
() => new ArchitectureContext(_container!, _eventBus!, _commandBus!, _queryBus!, null!, _asyncQueryBus!),
Throws.ArgumentNullException.With.Property("ParamName").EqualTo("environment")); Throws.ArgumentNullException.With.Property("ParamName").EqualTo("environment"));
} }

View File

@ -262,6 +262,9 @@ public class TestArchitectureContextV3 : IArchitectureContext
} }
public TResult SendQuery<TResult>(IQuery<TResult> query) => default!; public TResult SendQuery<TResult>(IQuery<TResult> query) => default!;
public Task<TResult> SendQueryAsync<TResult>(IAsyncQuery<TResult> query) => (Task<TResult>)Task.CompletedTask;
public IEnvironment GetEnvironment() => _environment; public IEnvironment GetEnvironment() => _environment;
} }

View File

@ -345,6 +345,14 @@ public class TestArchitectureContext : IArchitectureContext
/// <returns>查询结果</returns> /// <returns>查询结果</returns>
public TResult SendQuery<TResult>(IQuery<TResult> query) => default!; public TResult SendQuery<TResult>(IQuery<TResult> query) => default!;
/// <summary>
/// 异步发送查询请求
/// </summary>
/// <typeparam name="TResult">查询结果类型</typeparam>
/// <param name="query">异步查询对象</param>
/// <returns>查询结果</returns>
public Task<TResult> SendQueryAsync<TResult>(IAsyncQuery<TResult> query) => (Task<TResult>)Task.CompletedTask;
/// <summary> /// <summary>
/// 获取环境对象 /// 获取环境对象
/// </summary> /// </summary>

View File

@ -41,7 +41,8 @@ public class StateMachineSystemTests
_eventBus, _eventBus,
new CommandBus(), new CommandBus(),
new QueryBus(), new QueryBus(),
new DefaultEnvironment()); new DefaultEnvironment(),
new AsyncQueryBus());
_stateMachine = new TestStateMachineSystemV5(); _stateMachine = new TestStateMachineSystemV5();
_stateMachine.SetContext(_context); _stateMachine.SetContext(_context);

View File

@ -14,6 +14,7 @@ using GFramework.Core.environment;
using GFramework.Core.events; using GFramework.Core.events;
using GFramework.Core.extensions; using GFramework.Core.extensions;
using GFramework.Core.logging; using GFramework.Core.logging;
using IAsyncQueryBus = GFramework.Core.Abstractions.query.IAsyncQueryBus;
using IDisposable = GFramework.Core.Abstractions.lifecycle.IDisposable; using IDisposable = GFramework.Core.Abstractions.lifecycle.IDisposable;
namespace GFramework.Core.architecture; namespace GFramework.Core.architecture;
@ -88,6 +89,11 @@ public abstract class Architecture(
/// </summary> /// </summary>
private IQueryBus QueryBus => Services.QueryBus; private IQueryBus QueryBus => Services.QueryBus;
/// <summary>
/// 获取异步查询总线
/// </summary>
private IAsyncQueryBus AsyncQueryBus => Services.AsyncQueryBus;
/// <summary> /// <summary>
/// 当前架构的阶段 /// 当前架构的阶段
/// </summary> /// </summary>
@ -548,7 +554,7 @@ public abstract class Architecture(
Environment.Initialize(); Environment.Initialize();
// 初始化架构上下文(如果尚未初始化) // 初始化架构上下文(如果尚未初始化)
_context ??= new ArchitectureContext(Container, EventBus, CommandBus, QueryBus, Environment); _context ??= new ArchitectureContext(Container, EventBus, CommandBus, QueryBus, Environment, AsyncQueryBus);
GameContext.Bind(GetType(), _context); GameContext.Bind(GetType(), _context);
// 为服务设置上下文 // 为服务设置上下文

View File

@ -7,6 +7,7 @@ using GFramework.Core.Abstractions.model;
using GFramework.Core.Abstractions.query; using GFramework.Core.Abstractions.query;
using GFramework.Core.Abstractions.system; using GFramework.Core.Abstractions.system;
using GFramework.Core.Abstractions.utility; using GFramework.Core.Abstractions.utility;
using IAsyncQueryBus = GFramework.Core.Abstractions.query.IAsyncQueryBus;
namespace GFramework.Core.architecture; namespace GFramework.Core.architecture;
@ -18,9 +19,13 @@ public class ArchitectureContext(
IEventBus eventBus, IEventBus eventBus,
ICommandBus commandBus, ICommandBus commandBus,
IQueryBus queryBus, IQueryBus queryBus,
IEnvironment environment) IEnvironment environment,
IAsyncQueryBus asyncQueryBus)
: IArchitectureContext : IArchitectureContext
{ {
private readonly IAsyncQueryBus _asyncQueryBus =
asyncQueryBus ?? throw new ArgumentNullException(nameof(asyncQueryBus));
private readonly ICommandBus _commandBus = commandBus ?? throw new ArgumentNullException(nameof(commandBus)); private readonly ICommandBus _commandBus = commandBus ?? throw new ArgumentNullException(nameof(commandBus));
private readonly IIocContainer _container = container ?? throw new ArgumentNullException(nameof(container)); private readonly IIocContainer _container = container ?? throw new ArgumentNullException(nameof(container));
@ -44,6 +49,17 @@ public class ArchitectureContext(
return query == null ? throw new ArgumentNullException(nameof(query)) : _queryBus.Send(query); return query == null ? throw new ArgumentNullException(nameof(query)) : _queryBus.Send(query);
} }
/// <summary>
/// 异步发送一个查询请求
/// </summary>
/// <typeparam name="TResult">查询结果类型</typeparam>
/// <param name="query">要发送的异步查询</param>
/// <returns>查询结果</returns>
public Task<TResult> SendQueryAsync<TResult>(IAsyncQuery<TResult> query)
{
return query == null ? throw new ArgumentNullException(nameof(query)) : _asyncQueryBus.SendAsync(query);
}
#endregion #endregion
#region Component Retrieval #region Component Retrieval

View File

@ -1,4 +1,4 @@
using GFramework.Core.Abstractions.architecture; using GFramework.Core.Abstractions.architecture;
using GFramework.Core.Abstractions.command; using GFramework.Core.Abstractions.command;
using GFramework.Core.Abstractions.events; using GFramework.Core.Abstractions.events;
using GFramework.Core.Abstractions.ioc; using GFramework.Core.Abstractions.ioc;
@ -7,6 +7,7 @@ using GFramework.Core.command;
using GFramework.Core.events; using GFramework.Core.events;
using GFramework.Core.ioc; using GFramework.Core.ioc;
using GFramework.Core.query; using GFramework.Core.query;
using IAsyncQueryBus = GFramework.Core.Abstractions.query.IAsyncQueryBus;
namespace GFramework.Core.architecture; namespace GFramework.Core.architecture;
@ -37,6 +38,11 @@ public class ArchitectureServices : IArchitectureServices
/// </summary> /// </summary>
public IQueryBus QueryBus { get; } = new QueryBus(); public IQueryBus QueryBus { get; } = new QueryBus();
/// <summary>
/// 获取异步查询总线
/// </summary>
public IAsyncQueryBus AsyncQueryBus { get; } = new AsyncQueryBus();
/// <summary> /// <summary>
/// 设置架构上下文 /// 设置架构上下文
/// </summary> /// </summary>