diff --git a/GFramework.Cqrs.Tests/Cqrs/AbstractCqrsHandlerContextTests.cs b/GFramework.Cqrs.Tests/Cqrs/AbstractCqrsHandlerContextTests.cs
new file mode 100644
index 00000000..58e86f89
--- /dev/null
+++ b/GFramework.Cqrs.Tests/Cqrs/AbstractCqrsHandlerContextTests.cs
@@ -0,0 +1,74 @@
+using GFramework.Core.Abstractions.Architectures;
+using GFramework.Core.Abstractions.Rule;
+using GFramework.Cqrs.Abstractions.Cqrs;
+using GFramework.Cqrs.Abstractions.Cqrs.Command;
+using GFramework.Cqrs.Cqrs.Command;
+
+namespace GFramework.Cqrs.Tests.Cqrs;
+
+///
+/// 验证 CQRS handler 基类在脱离 dispatcher 使用时会显式失败,并在注入上下文后保持可观察行为。
+///
+[TestFixture]
+internal sealed class AbstractCqrsHandlerContextTests
+{
+ ///
+ /// 验证新的轻量 handler 基类不会再偷偷回退到全局 GameContext。
+ ///
+ [Test]
+ public void GetContext_Should_Throw_When_Handler_Has_Not_Been_Initialized_By_Runtime()
+ {
+ var handler = new TestCommandHandler();
+
+ var exception = Assert.Throws(() => ((IContextAware)handler).GetContext());
+
+ Assert.That(
+ exception!.Message,
+ Does.Contain("has not been initialized").IgnoreCase);
+ }
+
+ ///
+ /// 验证 runtime 注入上下文后,派生 handler 可以继续访问 Context 并收到 OnContextReady 回调。
+ ///
+ [Test]
+ public async Task Handle_Should_Observe_Injected_Context_And_OnContextReady_Callback()
+ {
+ var handler = new TestCommandHandler();
+ var context = new Mock(MockBehavior.Strict).Object;
+
+ ((IContextAware)handler).SetContext(context);
+ await handler.Handle(new TestCommand(), CancellationToken.None);
+
+ Assert.Multiple(() =>
+ {
+ Assert.That(handler.OnContextReadyCallCount, Is.EqualTo(1));
+ Assert.That(handler.LastObservedContext, Is.SameAs(context));
+ });
+ }
+
+ ///
+ /// 用于验证上下文注入行为的最小 CQRS 命令。
+ ///
+ private sealed record TestCommand : ICommand;
+
+ ///
+ /// 暴露基类上下文访问与初始化回调的测试处理器。
+ ///
+ private sealed class TestCommandHandler : AbstractCommandHandler
+ {
+ public int OnContextReadyCallCount { get; private set; }
+
+ public IArchitectureContext? LastObservedContext { get; private set; }
+
+ protected override void OnContextReady()
+ {
+ OnContextReadyCallCount++;
+ }
+
+ public override ValueTask Handle(TestCommand command, CancellationToken cancellationToken)
+ {
+ LastObservedContext = Context;
+ return ValueTask.FromResult(Unit.Value);
+ }
+ }
+}
diff --git a/GFramework.Core/Cqrs/Command/AbstractCommandHandler.cs b/GFramework.Cqrs/Cqrs/Command/AbstractCommandHandler.cs
similarity index 83%
rename from GFramework.Core/Cqrs/Command/AbstractCommandHandler.cs
rename to GFramework.Cqrs/Cqrs/Command/AbstractCommandHandler.cs
index d7ebb117..825737bf 100644
--- a/GFramework.Core/Cqrs/Command/AbstractCommandHandler.cs
+++ b/GFramework.Cqrs/Cqrs/Command/AbstractCommandHandler.cs
@@ -11,19 +11,18 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-using GFramework.Core.Rule;
using GFramework.Cqrs.Abstractions.Cqrs;
using GFramework.Cqrs.Abstractions.Cqrs.Command;
-namespace GFramework.Core.Cqrs.Command;
+namespace GFramework.Cqrs.Cqrs.Command;
///
/// 抽象命令处理器基类
-/// 继承自 ContextAwareBase 并实现 IRequestHandler 接口,为具体的命令处理器提供基础功能。
+/// 继承自轻量 CQRS 上下文基类并实现 IRequestHandler 接口,为具体的命令处理器提供基础功能。
/// 框架会在每次分发前注入当前架构上下文,因此派生类可以通过 Context 访问架构级服务。
///
/// 命令类型
-public abstract class AbstractCommandHandler : ContextAwareBase, IRequestHandler
+public abstract class AbstractCommandHandler : CqrsContextAwareHandlerBase, IRequestHandler
where TCommand : ICommand
{
///
@@ -38,12 +37,13 @@ public abstract class AbstractCommandHandler : ContextAwareBase, IRequ
///
/// 抽象命令处理器基类(带返回值版本)
-/// 继承自 ContextAwareBase 并实现 IRequestHandler 接口,为具体的命令处理器提供基础功能。
+/// 继承自轻量 CQRS 上下文基类并实现 IRequestHandler 接口,为具体的命令处理器提供基础功能。
/// 支持泛型命令和结果类型,框架会在每次分发前注入当前架构上下文。
///
/// 命令类型,必须实现ICommand接口
/// 命令执行结果类型
-public abstract class AbstractCommandHandler : ContextAwareBase, IRequestHandler
+public abstract class AbstractCommandHandler : CqrsContextAwareHandlerBase,
+ IRequestHandler
where TCommand : ICommand
{
///
diff --git a/GFramework.Core/Cqrs/Command/AbstractStreamCommandHandler.cs b/GFramework.Cqrs/Cqrs/Command/AbstractStreamCommandHandler.cs
similarity index 92%
rename from GFramework.Core/Cqrs/Command/AbstractStreamCommandHandler.cs
rename to GFramework.Cqrs/Cqrs/Command/AbstractStreamCommandHandler.cs
index 223a9cc5..cb4ccb6b 100644
--- a/GFramework.Core/Cqrs/Command/AbstractStreamCommandHandler.cs
+++ b/GFramework.Cqrs/Cqrs/Command/AbstractStreamCommandHandler.cs
@@ -11,15 +11,14 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-using GFramework.Core.Rule;
using GFramework.Cqrs.Abstractions.Cqrs;
using GFramework.Cqrs.Abstractions.Cqrs.Command;
-namespace GFramework.Core.Cqrs.Command;
+namespace GFramework.Cqrs.Cqrs.Command;
///
/// 抽象流式命令处理器基类。
-/// 继承自 并实现 ,
+/// 继承自轻量 CQRS 上下文基类并实现 ,
/// 为具体的流式命令处理器提供基础功能。
///
/// 流式命令类型,必须实现 。
@@ -32,7 +31,7 @@ namespace GFramework.Core.Cqrs.Command;
/// 传入 的取消令牌同时约束流的创建与后续枚举,
/// 派生类应在启动阶段和每次生成响应前尊重取消请求,避免在调用方停止枚举后继续执行后台工作。
///
-public abstract class AbstractStreamCommandHandler : ContextAwareBase,
+public abstract class AbstractStreamCommandHandler : CqrsContextAwareHandlerBase,
IStreamRequestHandler
where TCommand : IStreamCommand
{
diff --git a/GFramework.Cqrs/Cqrs/CqrsContextAwareHandlerBase.cs b/GFramework.Cqrs/Cqrs/CqrsContextAwareHandlerBase.cs
new file mode 100644
index 00000000..73e25ff1
--- /dev/null
+++ b/GFramework.Cqrs/Cqrs/CqrsContextAwareHandlerBase.cs
@@ -0,0 +1,59 @@
+using GFramework.Core.Abstractions.Architectures;
+using GFramework.Core.Abstractions.Rule;
+
+namespace GFramework.Cqrs.Cqrs;
+
+///
+/// 为 CQRS 处理器提供最小化的上下文感知基类实现。
+///
+///
+/// 该基类只承接 CQRS runtime 在分发前注入的 ,
+/// 不再像 ContextAwareBase 那样回退到 GameContext 全局查找。
+/// 这样可以让 GFramework.Cqrs 保持对 GFramework.Core 运行时实现的零依赖,
+/// 同时在处理器被错误地脱离 dispatcher 使用时以显式异常快速失败。
+///
+public abstract class CqrsContextAwareHandlerBase : IContextAware
+{
+ private IArchitectureContext? _context;
+
+ ///
+ /// 获取当前分发周期内已注入的架构上下文。
+ ///
+ ///
+ /// 当前处理器尚未被 CQRS runtime 注入上下文。
+ ///
+ protected IArchitectureContext Context => _context ?? throw new InvalidOperationException(
+ "The CQRS handler context has not been initialized. Ensure the handler is invoked through the CQRS runtime.");
+
+ ///
+ /// 由 runtime 在分发前注入当前架构上下文。
+ ///
+ /// 当前架构上下文。
+ void IContextAware.SetContext(IArchitectureContext context)
+ {
+ ArgumentNullException.ThrowIfNull(context);
+
+ _context = context;
+ OnContextReady();
+ }
+
+ ///
+ /// 获取当前处理器实例已绑定的架构上下文。
+ ///
+ /// 当前分发周期内的架构上下文。
+ IArchitectureContext IContextAware.GetContext()
+ {
+ return Context;
+ }
+
+ ///
+ /// 当上下文注入完成后执行额外初始化。
+ ///
+ ///
+ /// 该钩子保留与旧 ContextAwareBase 相近的扩展点,
+ /// 便于处理器在迁移后继续承接分发前的派生类初始化逻辑。
+ ///
+ protected virtual void OnContextReady()
+ {
+ }
+}
diff --git a/GFramework.Core/Cqrs/Notification/AbstractNotificationHandler.cs b/GFramework.Cqrs/Cqrs/Notification/AbstractNotificationHandler.cs
similarity index 85%
rename from GFramework.Core/Cqrs/Notification/AbstractNotificationHandler.cs
rename to GFramework.Cqrs/Cqrs/Notification/AbstractNotificationHandler.cs
index da6f5281..16246d16 100644
--- a/GFramework.Core/Cqrs/Notification/AbstractNotificationHandler.cs
+++ b/GFramework.Cqrs/Cqrs/Notification/AbstractNotificationHandler.cs
@@ -11,18 +11,18 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-using GFramework.Core.Rule;
using GFramework.Cqrs.Abstractions.Cqrs;
-namespace GFramework.Core.Cqrs.Notification;
+namespace GFramework.Cqrs.Cqrs.Notification;
///
/// 抽象通知处理器基类
-/// 继承自ContextAwareBase并实现INotificationHandler接口,为具体的通知处理器提供基础功能
+/// 继承自轻量 CQRS 上下文基类并实现INotificationHandler接口,为具体的通知处理器提供基础功能
/// 用于处理CQRS模式中的通知消息,支持异步处理
///
/// 通知类型,必须实现INotification接口
-public abstract class AbstractNotificationHandler : ContextAwareBase, INotificationHandler
+public abstract class AbstractNotificationHandler : CqrsContextAwareHandlerBase,
+ INotificationHandler
where TNotification : INotification
{
///
diff --git a/GFramework.Core/Cqrs/Query/AbstractQueryHandler.cs b/GFramework.Cqrs/Cqrs/Query/AbstractQueryHandler.cs
similarity index 83%
rename from GFramework.Core/Cqrs/Query/AbstractQueryHandler.cs
rename to GFramework.Cqrs/Cqrs/Query/AbstractQueryHandler.cs
index 85c86425..5096f4b7 100644
--- a/GFramework.Core/Cqrs/Query/AbstractQueryHandler.cs
+++ b/GFramework.Cqrs/Cqrs/Query/AbstractQueryHandler.cs
@@ -11,20 +11,20 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-using GFramework.Core.Rule;
using GFramework.Cqrs.Abstractions.Cqrs;
using GFramework.Cqrs.Abstractions.Cqrs.Query;
-namespace GFramework.Core.Cqrs.Query;
+namespace GFramework.Cqrs.Cqrs.Query;
///
/// 抽象查询处理器基类
-/// 继承自 ContextAwareBase 并实现 IRequestHandler 接口,为具体的查询处理器提供基础功能。
+/// 继承自轻量 CQRS 上下文基类并实现 IRequestHandler 接口,为具体的查询处理器提供基础功能。
/// 框架会在每次分发前注入当前架构上下文,因此派生类可以通过 Context 访问架构级服务。
///
/// 查询类型,必须实现IQuery接口
/// 查询结果类型
-public abstract class AbstractQueryHandler : ContextAwareBase, IRequestHandler
+public abstract class AbstractQueryHandler : CqrsContextAwareHandlerBase,
+ IRequestHandler
where TQuery : IQuery
{
///
diff --git a/GFramework.Core/Cqrs/Query/AbstractStreamQueryHandler.cs b/GFramework.Cqrs/Cqrs/Query/AbstractStreamQueryHandler.cs
similarity index 89%
rename from GFramework.Core/Cqrs/Query/AbstractStreamQueryHandler.cs
rename to GFramework.Cqrs/Cqrs/Query/AbstractStreamQueryHandler.cs
index 9695dc42..7d301009 100644
--- a/GFramework.Core/Cqrs/Query/AbstractStreamQueryHandler.cs
+++ b/GFramework.Cqrs/Cqrs/Query/AbstractStreamQueryHandler.cs
@@ -11,20 +11,19 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-using GFramework.Core.Rule;
using GFramework.Cqrs.Abstractions.Cqrs;
using GFramework.Cqrs.Abstractions.Cqrs.Query;
-namespace GFramework.Core.Cqrs.Query;
+namespace GFramework.Cqrs.Cqrs.Query;
///
/// 抽象流式查询处理器基类
-/// 继承自ContextAwareBase并实现IStreamQueryHandler接口,为具体的流式查询处理器提供基础功能
+/// 继承自轻量 CQRS 上下文基类并实现IStreamQueryHandler接口,为具体的流式查询处理器提供基础功能
/// 支持流式处理查询并产生异步可枚举的响应序列,适用于大数据量或实时数据查询场景
///
/// 流式查询类型,必须实现IStreamQuery接口
/// 流式查询响应元素类型
-public abstract class AbstractStreamQueryHandler : ContextAwareBase,
+public abstract class AbstractStreamQueryHandler : CqrsContextAwareHandlerBase,
IStreamRequestHandler
where TQuery : IStreamQuery
{
diff --git a/GFramework.Core/Cqrs/Request/AbstractRequestHandler.cs b/GFramework.Cqrs/Cqrs/Request/AbstractRequestHandler.cs
similarity index 86%
rename from GFramework.Core/Cqrs/Request/AbstractRequestHandler.cs
rename to GFramework.Cqrs/Cqrs/Request/AbstractRequestHandler.cs
index f26c7cfa..8343576b 100644
--- a/GFramework.Core/Cqrs/Request/AbstractRequestHandler.cs
+++ b/GFramework.Cqrs/Cqrs/Request/AbstractRequestHandler.cs
@@ -11,17 +11,16 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-using GFramework.Core.Rule;
using GFramework.Cqrs.Abstractions.Cqrs;
-namespace GFramework.Core.Cqrs.Request;
+namespace GFramework.Cqrs.Cqrs.Request;
///
/// 抽象请求处理器基类,用于处理不返回具体响应的请求
-/// 继承自ContextAwareBase并实现IRequestHandler接口
+/// 继承自轻量 CQRS 上下文基类并实现IRequestHandler接口
///
/// 请求类型,必须实现IRequest[Unit]接口
-public abstract class AbstractRequestHandler : ContextAwareBase, IRequestHandler
+public abstract class AbstractRequestHandler : CqrsContextAwareHandlerBase, IRequestHandler
where TRequest : IRequest
{
///
@@ -35,11 +34,11 @@ public abstract class AbstractRequestHandler : ContextAwareBase, IRequ
///
/// 抽象请求处理器基类,用于处理需要返回具体响应的请求
-/// 继承自ContextAwareBase并实现IRequestHandler接口
+/// 继承自轻量 CQRS 上下文基类并实现IRequestHandler接口
///
/// 请求类型,必须实现IRequest[TResponse]接口
/// 响应类型
-public abstract class AbstractRequestHandler : ContextAwareBase,
+public abstract class AbstractRequestHandler : CqrsContextAwareHandlerBase,
IRequestHandler where TRequest : IRequest
{
///
diff --git a/GFramework.Core/Cqrs/Request/AbstractStreamRequestHandler.cs b/GFramework.Cqrs/Cqrs/Request/AbstractStreamRequestHandler.cs
similarity index 88%
rename from GFramework.Core/Cqrs/Request/AbstractStreamRequestHandler.cs
rename to GFramework.Cqrs/Cqrs/Request/AbstractStreamRequestHandler.cs
index 2cbf438d..42b968f4 100644
--- a/GFramework.Core/Cqrs/Request/AbstractStreamRequestHandler.cs
+++ b/GFramework.Cqrs/Cqrs/Request/AbstractStreamRequestHandler.cs
@@ -11,19 +11,18 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-using GFramework.Core.Rule;
using GFramework.Cqrs.Abstractions.Cqrs;
-namespace GFramework.Core.Cqrs.Request;
+namespace GFramework.Cqrs.Cqrs.Request;
///
/// 抽象流式请求处理器基类
-/// 继承自ContextAwareBase并实现IStreamRequestHandler接口,为具体的流式请求处理器提供基础功能
+/// 继承自轻量 CQRS 上下文基类并实现IStreamRequestHandler接口,为具体的流式请求处理器提供基础功能
/// 支持流式处理请求并产生异步可枚举的响应序列,适用于需要逐步返回结果的请求处理场景
///
/// 流式请求类型,必须实现IStreamRequest接口
/// 流式请求响应元素类型
-public abstract class AbstractStreamRequestHandler : ContextAwareBase,
+public abstract class AbstractStreamRequestHandler : CqrsContextAwareHandlerBase,
IStreamRequestHandler
where TRequest : IStreamRequest
{
diff --git a/GFramework.Tests.Common/CqrsTestRuntime.cs b/GFramework.Tests.Common/CqrsTestRuntime.cs
index f5913c6e..f044bbc8 100644
--- a/GFramework.Tests.Common/CqrsTestRuntime.cs
+++ b/GFramework.Tests.Common/CqrsTestRuntime.cs
@@ -25,7 +25,7 @@ public static class CqrsTestRuntime
private static readonly Type CqrsHandlerRegistrarType = CqrsRuntimeAssembly
.GetType(
- "GFramework.Core.Cqrs.Internal.CqrsHandlerRegistrar",
+ "GFramework.Cqrs.Internal.CqrsHandlerRegistrar",
throwOnError: true)!;
private static readonly MethodInfo RegisterHandlersMethod = CqrsHandlerRegistrarType