using GFramework.Core.Abstractions.Logging;
using GFramework.Core.Architectures;
using GFramework.Core.Ioc;
using GFramework.Core.Logging;
using GFramework.Cqrs.Abstractions.Cqrs;
using GFramework.Cqrs.Tests.Logging;
namespace GFramework.Cqrs.Tests.Cqrs;
///
/// 验证 CQRS 处理器自动注册在顺序与容错层面的可观察行为。
///
[TestFixture]
internal sealed class CqrsHandlerRegistrarTests
{
private MicrosoftDiContainer? _container;
private ArchitectureContext? _context;
///
/// 初始化测试容器并重置共享状态。
///
[SetUp]
public void SetUp()
{
LoggerFactoryResolver.Provider = new ConsoleLoggerFactoryProvider();
DeterministicNotificationHandlerState.Reset();
_container = new MicrosoftDiContainer();
CqrsTestRuntime.RegisterHandlers(
_container,
typeof(CqrsHandlerRegistrarTests).Assembly);
_container.Freeze();
_context = new ArchitectureContext(_container);
ClearRegistrarCaches();
}
///
/// 清理测试过程中创建的上下文与共享状态。
///
[TearDown]
public void TearDown()
{
_context = null;
_container = null;
DeterministicNotificationHandlerState.Reset();
ClearRegistrarCaches();
}
///
/// 验证自动扫描到的通知处理器会按稳定名称顺序执行,而不是依赖反射枚举顺序。
///
[Test]
public async Task PublishAsync_Should_Run_Notification_Handlers_In_Deterministic_Name_Order()
{
await _context!.PublishAsync(new DeterministicOrderNotification());
Assert.That(
DeterministicNotificationHandlerState.InvocationOrder,
Is.EqualTo(
[
nameof(AlphaDeterministicNotificationHandler),
nameof(ZetaDeterministicNotificationHandler)
]));
}
///
/// 验证部分类型加载失败时仍能保留可加载类型,并记录诊断日志。
///
[Test]
public void RegisterHandlers_Should_Register_Loadable_Types_And_Log_Warnings_When_Assembly_Load_Partially_Fails()
{
var originalProvider = LoggerFactoryResolver.Provider;
var capturingProvider = new CapturingLoggerFactoryProvider(LogLevel.Warning);
var reflectionTypeLoadException = new ReflectionTypeLoadException(
[typeof(AlphaDeterministicNotificationHandler), null],
[new TypeLoadException("Missing optional dependency for registrar test.")]);
var partiallyLoadableAssembly = new Mock();
partiallyLoadableAssembly
.SetupGet(static assembly => assembly.FullName)
.Returns("GFramework.Core.Tests.Cqrs.PartiallyLoadableAssembly, Version=1.0.0.0");
partiallyLoadableAssembly
.Setup(static assembly => assembly.GetTypes())
.Throws(reflectionTypeLoadException);
LoggerFactoryResolver.Provider = capturingProvider;
try
{
var container = new MicrosoftDiContainer();
CqrsTestRuntime.RegisterHandlers(container, partiallyLoadableAssembly.Object);
container.Freeze();
var handlers = container.GetAll>();
var warningLogs = capturingProvider.Loggers
.SelectMany(static logger => logger.Logs)
.Where(static log => log.Level == LogLevel.Warning)
.ToList();
Assert.Multiple(() =>
{
Assert.That(
handlers.Select(static handler => handler.GetType()),
Is.EqualTo([typeof(AlphaDeterministicNotificationHandler)]));
Assert.That(warningLogs.Count, Is.GreaterThanOrEqualTo(2));
Assert.That(
warningLogs.Any(log => log.Message.Contains("partially failed", StringComparison.Ordinal)),
Is.True);
Assert.That(
warningLogs.Any(log =>
log.Message.Contains("Missing optional dependency", StringComparison.Ordinal)),
Is.True);
});
}
finally
{
LoggerFactoryResolver.Provider = originalProvider;
}
}
///
/// 验证当程序集提供源码生成的注册器时,运行时会优先使用该注册器而不是反射扫描类型列表。
///
[Test]
public void RegisterHandlers_Should_Use_Generated_Registry_When_Available()
{
var generatedAssembly = new Mock();
generatedAssembly
.SetupGet(static assembly => assembly.FullName)
.Returns("GFramework.Core.Tests.Cqrs.GeneratedRegistryAssembly, Version=1.0.0.0");
generatedAssembly
.Setup(static assembly => assembly.GetCustomAttributes(typeof(CqrsHandlerRegistryAttribute), false))
.Returns([new CqrsHandlerRegistryAttribute(typeof(GeneratedNotificationHandlerRegistry))]);
var container = new MicrosoftDiContainer();
CqrsTestRuntime.RegisterHandlers(container, generatedAssembly.Object);
container.Freeze();
var handlers = container.GetAll>();
Assert.That(
handlers.Select(static handler => handler.GetType()),
Is.EqualTo([typeof(GeneratedRegistryNotificationHandler)]));
}
///
/// 验证 generated registry 使用私有无参构造器时,运行时仍可激活它并完成处理器注册。
///
[Test]
public void RegisterHandlers_Should_Activate_Generated_Registry_With_Private_Parameterless_Constructor()
{
var generatedAssembly = new Mock();
generatedAssembly
.SetupGet(static assembly => assembly.FullName)
.Returns("GFramework.Core.Tests.Cqrs.PrivateGeneratedRegistryAssembly, Version=1.0.0.0");
generatedAssembly
.Setup(static assembly => assembly.GetCustomAttributes(typeof(CqrsHandlerRegistryAttribute), false))
.Returns([new CqrsHandlerRegistryAttribute(typeof(PrivateConstructorNotificationHandlerRegistry))]);
var container = new MicrosoftDiContainer();
CqrsTestRuntime.RegisterHandlers(container, generatedAssembly.Object);
container.Freeze();
var handlers = container.GetAll>();
Assert.That(
handlers.Select(static handler => handler.GetType()),
Is.EqualTo([typeof(GeneratedRegistryNotificationHandler)]));
}
///
/// 验证当生成注册器元数据损坏时,运行时会记录告警并回退到反射扫描路径。
///
[Test]
public void RegisterHandlers_Should_Fall_Back_To_Reflection_When_Generated_Registry_Is_Invalid()
{
var originalProvider = LoggerFactoryResolver.Provider;
var capturingProvider = new CapturingLoggerFactoryProvider(LogLevel.Warning);
var generatedAssembly = new Mock();
generatedAssembly
.SetupGet(static assembly => assembly.FullName)
.Returns("GFramework.Core.Tests.Cqrs.InvalidGeneratedRegistryAssembly, Version=1.0.0.0");
generatedAssembly
.Setup(static assembly => assembly.GetCustomAttributes(typeof(CqrsHandlerRegistryAttribute), false))
.Returns([new CqrsHandlerRegistryAttribute(typeof(string))]);
generatedAssembly
.Setup(static assembly => assembly.GetTypes())
.Returns([typeof(AlphaDeterministicNotificationHandler)]);
LoggerFactoryResolver.Provider = capturingProvider;
try
{
var container = new MicrosoftDiContainer();
CqrsTestRuntime.RegisterHandlers(container, generatedAssembly.Object);
container.Freeze();
var handlers = container.GetAll>();
var warningLogs = capturingProvider.Loggers
.SelectMany(static logger => logger.Logs)
.Where(static log => log.Level == LogLevel.Warning)
.ToList();
Assert.Multiple(() =>
{
Assert.That(
handlers.Select(static handler => handler.GetType()),
Is.EqualTo([typeof(AlphaDeterministicNotificationHandler)]));
Assert.That(
warningLogs.Any(log =>
log.Message.Contains("does not implement", StringComparison.Ordinal)),
Is.True);
});
}
finally
{
LoggerFactoryResolver.Provider = originalProvider;
}
}
///
/// 验证当生成注册器提供精确 fallback 类型名时,运行时会定向补扫剩余 handlers,
/// 而不是重新枚举整个程序集的类型列表。
///
[Test]
public void RegisterHandlers_Should_Use_Targeted_Type_Lookups_For_Reflection_Fallback_Without_Duplicates()
{
var generatedAssembly = new Mock();
generatedAssembly
.SetupGet(static assembly => assembly.FullName)
.Returns("GFramework.Core.Tests.Cqrs.PartialGeneratedRegistryAssembly, Version=1.0.0.0");
generatedAssembly
.Setup(static assembly => assembly.GetCustomAttributes(typeof(CqrsHandlerRegistryAttribute), false))
.Returns([new CqrsHandlerRegistryAttribute(typeof(PartialGeneratedNotificationHandlerRegistry))]);
generatedAssembly
.Setup(static assembly => assembly.GetCustomAttributes(typeof(CqrsReflectionFallbackAttribute), false))
.Returns(
[
new CqrsReflectionFallbackAttribute(
ReflectionFallbackNotificationContainer.ReflectionOnlyHandlerType.FullName!)
]);
generatedAssembly
.Setup(static assembly => assembly.GetType(
ReflectionFallbackNotificationContainer.ReflectionOnlyHandlerType.FullName!,
false,
false))
.Returns(ReflectionFallbackNotificationContainer.ReflectionOnlyHandlerType);
var container = new MicrosoftDiContainer();
CqrsTestRuntime.RegisterHandlers(container, generatedAssembly.Object);
var registrations = container.GetServicesUnsafe
.Where(static descriptor =>
descriptor.ServiceType == typeof(INotificationHandler) &&
descriptor.ImplementationType is not null)
.Select(static descriptor => descriptor.ImplementationType!)
.ToList();
Assert.That(
registrations,
Is.EqualTo(
[
typeof(GeneratedRegistryNotificationHandler),
ReflectionFallbackNotificationContainer.ReflectionOnlyHandlerType
]));
generatedAssembly.Verify(
static assembly => assembly.GetType(
ReflectionFallbackNotificationContainer.ReflectionOnlyHandlerType.FullName!,
false,
false),
Times.Once);
generatedAssembly.Verify(static assembly => assembly.GetTypes(), Times.Never);
}
///
/// 验证手写 fallback metadata 直接提供 handler 类型时,运行时会复用这些类型,
/// 而不会再通过程序集名称查找或整程序集扫描补齐映射。
///
[Test]
public void RegisterHandlers_Should_Use_Direct_Fallback_Types_Without_GetType_Or_GetTypes()
{
var generatedAssembly = new Mock();
generatedAssembly
.SetupGet(static assembly => assembly.FullName)
.Returns(ReflectionFallbackNotificationContainer.ReflectionOnlyHandlerType.Assembly.FullName);
generatedAssembly
.Setup(static assembly => assembly.GetCustomAttributes(typeof(CqrsHandlerRegistryAttribute), false))
.Returns([new CqrsHandlerRegistryAttribute(typeof(PartialGeneratedNotificationHandlerRegistry))]);
generatedAssembly
.Setup(static assembly => assembly.GetCustomAttributes(typeof(CqrsReflectionFallbackAttribute), false))
.Returns(
[
new CqrsReflectionFallbackAttribute(
ReflectionFallbackNotificationContainer.ReflectionOnlyHandlerType)
]);
var container = new MicrosoftDiContainer();
CqrsTestRuntime.RegisterHandlers(container, generatedAssembly.Object);
var registrations = container.GetServicesUnsafe
.Where(static descriptor =>
descriptor.ServiceType == typeof(INotificationHandler) &&
descriptor.ImplementationType is not null)
.Select(static descriptor => descriptor.ImplementationType!)
.ToList();
Assert.That(
registrations,
Is.EqualTo(
[
typeof(GeneratedRegistryNotificationHandler),
ReflectionFallbackNotificationContainer.ReflectionOnlyHandlerType
]));
generatedAssembly.Verify(
static assembly => assembly.GetType(
ReflectionFallbackNotificationContainer.ReflectionOnlyHandlerType.FullName!,
false,
false),
Times.Never);
generatedAssembly.Verify(static assembly => assembly.GetTypes(), Times.Never);
}
///
/// 验证同一程序集对象重复接入多个容器时,会复用已解析的 registry / fallback 元数据,
/// 而不是重复读取程序集级 attribute 或重复执行 type-name lookup。
///
[Test]
public void RegisterHandlers_Should_Cache_Assembly_Metadata_Across_Containers()
{
var generatedAssembly = new Mock();
generatedAssembly
.SetupGet(static assembly => assembly.FullName)
.Returns("GFramework.Core.Tests.Cqrs.CachedMetadataAssembly, Version=1.0.0.0");
generatedAssembly
.Setup(static assembly => assembly.GetCustomAttributes(typeof(CqrsHandlerRegistryAttribute), false))
.Returns([new CqrsHandlerRegistryAttribute(typeof(PartialGeneratedNotificationHandlerRegistry))]);
generatedAssembly
.Setup(static assembly => assembly.GetCustomAttributes(typeof(CqrsReflectionFallbackAttribute), false))
.Returns(
[
new CqrsReflectionFallbackAttribute(
ReflectionFallbackNotificationContainer.ReflectionOnlyHandlerType.FullName!)
]);
generatedAssembly
.Setup(static assembly => assembly.GetType(
ReflectionFallbackNotificationContainer.ReflectionOnlyHandlerType.FullName!,
false,
false))
.Returns(ReflectionFallbackNotificationContainer.ReflectionOnlyHandlerType);
var firstContainer = new MicrosoftDiContainer();
var secondContainer = new MicrosoftDiContainer();
CqrsTestRuntime.RegisterHandlers(firstContainer, generatedAssembly.Object);
CqrsTestRuntime.RegisterHandlers(secondContainer, generatedAssembly.Object);
firstContainer.Freeze();
secondContainer.Freeze();
var firstRegistrations = firstContainer.GetAll>()
.Select(static handler => handler.GetType())
.ToArray();
var secondRegistrations = secondContainer.GetAll>()
.Select(static handler => handler.GetType())
.ToArray();
Assert.Multiple(() =>
{
Assert.That(
firstRegistrations,
Is.EqualTo(
[
typeof(GeneratedRegistryNotificationHandler),
ReflectionFallbackNotificationContainer.ReflectionOnlyHandlerType
]));
Assert.That(
secondRegistrations,
Is.EqualTo(
[
typeof(GeneratedRegistryNotificationHandler),
ReflectionFallbackNotificationContainer.ReflectionOnlyHandlerType
]));
});
generatedAssembly.Verify(
static assembly => assembly.GetCustomAttributes(typeof(CqrsHandlerRegistryAttribute), false),
Times.Once);
generatedAssembly.Verify(
static assembly => assembly.GetCustomAttributes(typeof(CqrsReflectionFallbackAttribute), false),
Times.Once);
generatedAssembly.Verify(
static assembly => assembly.GetType(
ReflectionFallbackNotificationContainer.ReflectionOnlyHandlerType.FullName!,
false,
false),
Times.Once);
}
///
/// 验证同一程序集对象在未命中 generated registry 时,会复用首次扫描得到的可加载类型列表,
/// 而不是为每个容器重复执行整程序集 GetTypes()。
///
[Test]
public void RegisterHandlers_Should_Cache_Loadable_Types_Across_Containers()
{
var reflectionTypeLoadException = new ReflectionTypeLoadException(
[typeof(AlphaDeterministicNotificationHandler), null],
[new TypeLoadException("Cached loadable-type probe.")]);
var partiallyLoadableAssembly = new Mock();
partiallyLoadableAssembly
.SetupGet(static assembly => assembly.FullName)
.Returns("GFramework.Core.Tests.Cqrs.CachedLoadableTypesAssembly, Version=1.0.0.0");
partiallyLoadableAssembly
.Setup(static assembly => assembly.GetTypes())
.Throws(reflectionTypeLoadException);
var firstContainer = new MicrosoftDiContainer();
var secondContainer = new MicrosoftDiContainer();
CqrsTestRuntime.RegisterHandlers(firstContainer, partiallyLoadableAssembly.Object);
CqrsTestRuntime.RegisterHandlers(secondContainer, partiallyLoadableAssembly.Object);
firstContainer.Freeze();
secondContainer.Freeze();
Assert.Multiple(() =>
{
Assert.That(
firstContainer.GetAll>()
.Select(static handler => handler.GetType())
.ToArray(),
Is.EqualTo([typeof(AlphaDeterministicNotificationHandler)]));
Assert.That(
secondContainer.GetAll>()
.Select(static handler => handler.GetType())
.ToArray(),
Is.EqualTo([typeof(AlphaDeterministicNotificationHandler)]));
});
partiallyLoadableAssembly.Verify(static assembly => assembly.GetTypes(), Times.Once);
}
///
/// 验证同一 handler 类型跨容器重复注册时,会复用已筛选的 supported handler interface 列表,
/// 而不是为每个容器重新执行接口反射分析。
///
[Test]
public void RegisterHandlers_Should_Cache_Supported_Handler_Interfaces_Across_Containers()
{
var supportedHandlerInterfacesCache = GetRegistrarCacheField("SupportedHandlerInterfacesCache");
var firstHandlerType = typeof(AlphaDeterministicNotificationHandler);
var secondHandlerType = typeof(ZetaDeterministicNotificationHandler);
var handlerAssembly = new Mock();
handlerAssembly
.SetupGet(static assembly => assembly.FullName)
.Returns("GFramework.Core.Tests.Cqrs.CachedHandlerInterfacesAssembly, Version=1.0.0.0");
handlerAssembly
.Setup(static assembly => assembly.GetTypes())
.Returns([firstHandlerType, secondHandlerType]);
Assert.Multiple(() =>
{
Assert.That(GetSingleKeyCacheValue(supportedHandlerInterfacesCache, firstHandlerType), Is.Null);
Assert.That(GetSingleKeyCacheValue(supportedHandlerInterfacesCache, secondHandlerType), Is.Null);
});
var firstContainer = new MicrosoftDiContainer();
var secondContainer = new MicrosoftDiContainer();
CqrsTestRuntime.RegisterHandlers(firstContainer, handlerAssembly.Object);
var firstHandlerInterfaces =
GetSingleKeyCacheValue(supportedHandlerInterfacesCache, firstHandlerType);
var secondHandlerInterfaces =
GetSingleKeyCacheValue(supportedHandlerInterfacesCache, secondHandlerType);
CqrsTestRuntime.RegisterHandlers(secondContainer, handlerAssembly.Object);
Assert.Multiple(() =>
{
Assert.That(firstHandlerInterfaces, Is.Not.Null);
Assert.That(secondHandlerInterfaces, Is.Not.Null);
Assert.That(
GetSingleKeyCacheValue(supportedHandlerInterfacesCache, firstHandlerType),
Is.SameAs(firstHandlerInterfaces));
Assert.That(
GetSingleKeyCacheValue(supportedHandlerInterfacesCache, secondHandlerType),
Is.SameAs(secondHandlerInterfaces));
});
handlerAssembly.Verify(static assembly => assembly.GetTypes(), Times.Once);
}
///
/// 验证当程序集枚举结果包含重复 handler 类型时,registrar 仍只会写入一份 handler 映射。
///
[Test]
public void RegisterHandlers_Should_Skip_Duplicate_Handler_Mappings_When_Assembly_Returns_Duplicate_Types()
{
var handlerType = typeof(AlphaDeterministicNotificationHandler);
var handlerAssembly = new Mock();
handlerAssembly
.SetupGet(static assembly => assembly.FullName)
.Returns("GFramework.Core.Tests.Cqrs.DuplicateHandlerMappingsAssembly, Version=1.0.0.0");
handlerAssembly
.Setup(static assembly => assembly.GetTypes())
.Returns([handlerType, handlerType]);
var container = new MicrosoftDiContainer();
CqrsTestRuntime.RegisterHandlers(container, handlerAssembly.Object);
var registrations = container.GetServicesUnsafe
.Where(static descriptor =>
descriptor.ServiceType == typeof(INotificationHandler) &&
descriptor.ImplementationType == typeof(AlphaDeterministicNotificationHandler))
.ToArray();
Assert.That(registrations, Has.Length.EqualTo(1));
}
///
/// 清空本测试依赖的 registrar 静态缓存,避免跨用例共享进程级状态导致断言漂移。
///
private static void ClearRegistrarCaches()
{
ClearCache(GetRegistrarCacheField("AssemblyMetadataCache"));
ClearCache(GetRegistrarCacheField("RegistryActivationMetadataCache"));
ClearCache(GetRegistrarCacheField("LoadableTypesCache"));
ClearCache(GetRegistrarCacheField("SupportedHandlerInterfacesCache"));
}
///
/// 通过反射读取 registrar 的静态缓存对象。
///
private static object GetRegistrarCacheField(string fieldName)
{
var registrarType = GetRegistrarType();
var field = registrarType.GetField(
fieldName,
BindingFlags.NonPublic | BindingFlags.Static);
Assert.That(field, Is.Not.Null, $"Missing registrar cache field {fieldName}.");
return field!.GetValue(null)
?? throw new InvalidOperationException(
$"Registrar cache field {fieldName} returned null.");
}
///
/// 清空指定缓存对象。
///
private static void ClearCache(object cache)
{
_ = InvokeInstanceMethod(cache, "Clear");
}
///
/// 读取单键缓存中当前保存的对象。
///
private static object? GetSingleKeyCacheValue(object cache, Type key)
{
return InvokeInstanceMethod(cache, "GetValueOrDefaultForTesting", key);
}
///
/// 调用缓存对象上的实例方法。
///
private static object? InvokeInstanceMethod(object target, string methodName, params object[] arguments)
{
var method = target.GetType().GetMethod(
methodName,
BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
Assert.That(method, Is.Not.Null, $"Missing cache method {target.GetType().FullName}.{methodName}.");
return method!.Invoke(target, arguments);
}
///
/// 获取 CQRS handler registrar 运行时类型。
///
private static Type GetRegistrarType()
{
return typeof(CqrsReflectionFallbackAttribute).Assembly
.GetType("GFramework.Cqrs.Internal.CqrsHandlerRegistrar", throwOnError: true)!;
}
}
///
/// 记录确定性通知处理器的实际执行顺序。
///
internal static class DeterministicNotificationHandlerState
{
///
/// 获取当前测试中的通知处理器执行顺序。
///
public static List InvocationOrder { get; } = [];
///
/// 重置共享的执行顺序状态。
///
public static void Reset()
{
InvocationOrder.Clear();
}
}
///
/// 用于验证同一通知的多个处理器是否按稳定顺序执行。
///
internal sealed record DeterministicOrderNotification : INotification;
///
/// 故意放在 Alpha 之前声明,用于验证注册器不会依赖源码声明顺序。
///
internal sealed class ZetaDeterministicNotificationHandler : INotificationHandler
{
///
/// 记录当前处理器已执行。
///
/// 通知实例。
/// 取消令牌。
/// 已完成任务。
public ValueTask Handle(DeterministicOrderNotification notification, CancellationToken cancellationToken)
{
DeterministicNotificationHandlerState.InvocationOrder.Add(nameof(ZetaDeterministicNotificationHandler));
return ValueTask.CompletedTask;
}
}
///
/// 名称排序上应先于 Zeta 处理器执行的通知处理器。
///
internal sealed class AlphaDeterministicNotificationHandler : INotificationHandler
{
///
/// 记录当前处理器已执行。
///
/// 通知实例。
/// 取消令牌。
/// 已完成任务。
public ValueTask Handle(DeterministicOrderNotification notification, CancellationToken cancellationToken)
{
DeterministicNotificationHandlerState.InvocationOrder.Add(nameof(AlphaDeterministicNotificationHandler));
return ValueTask.CompletedTask;
}
}
///
/// 为 CQRS 注册测试捕获真实启动路径中创建的日志记录器。
///
///
/// 处理器注册入口会分别为测试运行时、容器和注册器创建日志器。
/// 该提供程序统一保留这些测试日志器,以便断言警告是否经由公开入口真正发出。
///
internal sealed class CapturingLoggerFactoryProvider : ILoggerFactoryProvider
{
private readonly List _loggers = [];
///
/// 使用指定的最小日志级别初始化一个新的捕获型日志工厂提供程序。
///
/// 要应用到新建测试日志器的最小日志级别。
public CapturingLoggerFactoryProvider(LogLevel minLevel = LogLevel.Info)
{
MinLevel = minLevel;
}
///
/// 获取通过当前提供程序创建的全部测试日志器。
///
public IReadOnlyList Loggers => _loggers;
///
/// 获取或设置新建测试日志器的最小日志级别。
///
public LogLevel MinLevel { get; set; }
///
/// 创建一个测试日志器并将其纳入捕获集合。
///
/// 日志记录器名称。
/// 用于后续断言的测试日志器。
public ILogger CreateLogger(string name)
{
var logger = new TestLogger(name, MinLevel);
_loggers.Add(logger);
return logger;
}
}
///
/// 用于验证生成注册器路径的通知消息。
///
internal sealed record GeneratedRegistryNotification : INotification;
///
/// 由模拟的源码生成注册器显式注册的通知处理器。
///
internal sealed class GeneratedRegistryNotificationHandler : INotificationHandler
{
///
/// 处理生成注册器测试中的通知。
///
/// 通知实例。
/// 取消令牌。
/// 已完成任务。
public ValueTask Handle(GeneratedRegistryNotification notification, CancellationToken cancellationToken)
{
return ValueTask.CompletedTask;
}
}
///
/// 模拟源码生成器为某个程序集生成的 CQRS 处理器注册器。
///
internal sealed class GeneratedNotificationHandlerRegistry : ICqrsHandlerRegistry
{
///
/// 将测试通知处理器注册到目标服务集合。
///
/// 承载处理器映射的服务集合。
/// 用于记录注册诊断的日志器。
public void Register(IServiceCollection services, ILogger logger)
{
ArgumentNullException.ThrowIfNull(services);
ArgumentNullException.ThrowIfNull(logger);
services.AddTransient(
typeof(INotificationHandler),
typeof(GeneratedRegistryNotificationHandler));
logger.Debug(
$"Registered CQRS handler {typeof(GeneratedRegistryNotificationHandler).FullName} as {typeof(INotificationHandler).FullName}.");
}
}
///
/// 用于验证“生成注册器 + reflection fallback”组合路径的私有嵌套处理器容器。
///
internal sealed class ReflectionFallbackNotificationContainer
{
///
/// 获取仅能通过反射补扫接入的私有嵌套处理器类型。
///
public static Type ReflectionOnlyHandlerType => typeof(ReflectionOnlyGeneratedRegistryNotificationHandler);
private sealed class ReflectionOnlyGeneratedRegistryNotificationHandler
: INotificationHandler
{
///
/// 处理测试通知。
///
/// 通知实例。
/// 取消令牌。
/// 已完成任务。
public ValueTask Handle(GeneratedRegistryNotification notification, CancellationToken cancellationToken)
{
return ValueTask.CompletedTask;
}
}
}
///
/// 模拟局部生成注册器场景中,仅注册“可由生成代码直接引用”的那部分 handlers。
///
internal sealed class PartialGeneratedNotificationHandlerRegistry : ICqrsHandlerRegistry
{
///
/// 将生成路径可见的通知处理器注册到目标服务集合。
///
/// 承载处理器映射的服务集合。
/// 用于记录注册诊断的日志器。
public void Register(IServiceCollection services, ILogger logger)
{
ArgumentNullException.ThrowIfNull(services);
ArgumentNullException.ThrowIfNull(logger);
services.AddTransient(
typeof(INotificationHandler),
typeof(GeneratedRegistryNotificationHandler));
logger.Debug(
$"Registered CQRS handler {typeof(GeneratedRegistryNotificationHandler).FullName} as {typeof(INotificationHandler).FullName}.");
}
}
///
/// 模拟生成注册器使用私有无参构造器的场景,验证运行时仍可通过缓存工厂激活它。
///
internal sealed class PrivateConstructorNotificationHandlerRegistry : ICqrsHandlerRegistry
{
///
/// 初始化一个新的私有生成注册器实例。
///
private PrivateConstructorNotificationHandlerRegistry()
{
}
///
/// 将测试通知处理器注册到目标服务集合。
///
/// 承载处理器映射的服务集合。
/// 用于记录注册诊断的日志器。
public void Register(IServiceCollection services, ILogger logger)
{
ArgumentNullException.ThrowIfNull(services);
ArgumentNullException.ThrowIfNull(logger);
services.AddTransient(
typeof(INotificationHandler),
typeof(GeneratedRegistryNotificationHandler));
logger.Debug(
$"Registered CQRS handler {typeof(GeneratedRegistryNotificationHandler).FullName} as {typeof(INotificationHandler).FullName}.");
}
}