// Copyright (c) 2025-2026 GeWuYou // SPDX-License-Identifier: Apache-2.0 using System; using System.Linq; using GFramework.Core.Abstractions.Logging; using GFramework.Core.Ioc; using GFramework.Cqrs.Abstractions.Cqrs; using GFramework.Cqrs.Internal; using MediatR; using Microsoft.Extensions.DependencyInjection; using LegacyICqrsRuntime = GFramework.Core.Abstractions.Cqrs.ICqrsRuntime; namespace GFramework.Cqrs.Benchmarks.Messaging; /// /// 为 benchmark 场景构建最小且可重复的 GFramework / MediatR 对照宿主。 /// /// /// 基准工程里的对照目标是“相同消息合同下的调度差异”,而不是程序集扫描量或容器生命周期差异。 /// 因此这里统一封装两类宿主的最小注册形状,确保: /// 1. GFramework 容器在首次发送前已经冻结,可真实解析按类型注册的 handler; /// 2. MediatR 只扫描当前 benchmark 明确拥有的 handler / behavior 类型,避免整个程序集的额外注册污染结果。 /// internal static class BenchmarkHostFactory { /// /// 创建一个已经冻结的 GFramework benchmark 容器。 /// /// 向容器写入 benchmark 所需 handler / pipeline 的注册动作。 /// 已冻结、可立即用于 runtime 分发的容器。 internal static MicrosoftDiContainer CreateFrozenGFrameworkContainer(Action configure) { ArgumentNullException.ThrowIfNull(configure); var container = new MicrosoftDiContainer(); RegisterCqrsInfrastructure(container); configure(container); container.Freeze(); return container; } /// /// 为 benchmark 宿主补齐默认 CQRS runtime seam,确保它既能手工注册 handler,也能走真实的程序集注册入口。 /// /// 当前 benchmark 拥有的 GFramework 容器。 /// /// `RegisterCqrsHandlersFromAssembly(...)` 依赖预先可见的 runtime / registrar / registration service 实例绑定。 /// benchmark 宿主直接使用裸 ,因此需要在配置阶段先补齐这组基础设施, /// 避免各个 benchmark 用例各自复制同一段前置接线逻辑。 /// private static void RegisterCqrsInfrastructure(MicrosoftDiContainer container) { ArgumentNullException.ThrowIfNull(container); if (container.Get() is null) { var runtimeLogger = LoggerFactoryResolver.Provider.CreateLogger("CqrsDispatcher"); var notificationPublisher = container.Get(); var runtime = GFramework.Cqrs.CqrsRuntimeFactory.CreateRuntime(container, runtimeLogger, notificationPublisher); container.Register(runtime); RegisterLegacyRuntimeAlias(container, runtime); } else if (container.Get() is null) { RegisterLegacyRuntimeAlias(container, container.GetRequired()); } if (container.Get() is null) { var registrarLogger = LoggerFactoryResolver.Provider.CreateLogger("DefaultCqrsHandlerRegistrar"); var registrar = GFramework.Cqrs.CqrsRuntimeFactory.CreateHandlerRegistrar(container, registrarLogger); container.Register(registrar); } if (container.Get() is null) { var registrationLogger = LoggerFactoryResolver.Provider.CreateLogger("DefaultCqrsRegistrationService"); var registrar = container.GetRequired(); var registrationService = GFramework.Cqrs.CqrsRuntimeFactory.CreateRegistrationService(registrar, registrationLogger); container.Register(registrationService); } } /// /// 只激活当前 benchmark 场景明确拥有的 generated registry,避免同一程序集里的其他 benchmark registry /// 扩大冻结后服务索引与 dispatcher descriptor 基线。 /// /// 当前 benchmark 需要接入的 generated registry 类型。 /// 承载 generated registry 注册结果的 GFramework benchmark 容器。 internal static void RegisterGeneratedBenchmarkRegistry(MicrosoftDiContainer container) where TRegistry : class, GFramework.Cqrs.ICqrsHandlerRegistry { ArgumentNullException.ThrowIfNull(container); var registrarLogger = LoggerFactoryResolver.Provider.CreateLogger("DefaultCqrsHandlerRegistrar"); CqrsHandlerRegistrar.RegisterGeneratedRegistry(container, typeof(TRegistry), registrarLogger); } /// /// 为旧命名空间下的 CQRS runtime 契约注册兼容别名。 /// /// 承载 runtime 别名的 benchmark 容器。 /// 当前正式 CQRS runtime 实例。 /// /// 未同时实现 legacy CQRS runtime 契约。 /// private static void RegisterLegacyRuntimeAlias(MicrosoftDiContainer container, ICqrsRuntime runtime) { ArgumentNullException.ThrowIfNull(container); ArgumentNullException.ThrowIfNull(runtime); if (runtime is not LegacyICqrsRuntime legacyRuntime) { throw new InvalidOperationException( $"The registered {typeof(ICqrsRuntime).FullName} must also implement {typeof(LegacyICqrsRuntime).FullName}. Actual runtime type: {runtime.GetType().FullName}."); } container.Register(legacyRuntime); } /// /// 创建只承载当前 benchmark handler 集合的最小 MediatR 宿主。 /// /// 补充当前场景的显式服务注册,例如手工单例 handler 或 pipeline 行为。 /// 用于限定扫描程序集的标记类型。 /// /// 仅允许当前 benchmark 场景需要的 handler / behavior 类型通过扫描; /// 这样可保留 `AddMediatR` 的正常装配路径,同时避免整个基准程序集里的其他 handler 被一并注册。 /// /// 当前 benchmark 希望 MediatR 使用的默认注册生命周期。 /// 只承载当前 benchmark 场景所需服务的 DI 宿主。 internal static ServiceProvider CreateMediatRServiceProvider( Action? configure, Type handlerAssemblyMarkerType, Func handlerTypeFilter, ServiceLifetime lifetime = ServiceLifetime.Transient) { ArgumentNullException.ThrowIfNull(handlerAssemblyMarkerType); ArgumentNullException.ThrowIfNull(handlerTypeFilter); var services = new ServiceCollection(); services.AddLogging(static builder => Microsoft.Extensions.Logging.FilterLoggingBuilderExtensions.AddFilter( builder, "LuckyPennySoftware.MediatR.License", Microsoft.Extensions.Logging.LogLevel.None)); configure?.Invoke(services); services.AddMediatR(options => { options.Lifetime = lifetime; options.TypeEvaluator = handlerTypeFilter; options.RegisterServicesFromAssembly(handlerAssemblyMarkerType.Assembly); }); return services.BuildServiceProvider(); } /// /// 创建承载 NuGet `Mediator` source-generated concrete mediator 的最小对照宿主。 /// /// 补充当前场景的显式服务注册。 /// 可直接解析 generated `Mediator.Mediator` 的 DI 宿主。 /// /// 当前 benchmark 只把 `Mediator` 作为单例 steady-state 对照组接入, /// 因为它的 lifetime 由 source generator 在编译期塑形;若后续需要 `Transient` / `Scoped` 矩阵, /// 应按 `Mediator` 官方 benchmark 的做法拆成独立 build config,而不是在同一编译产物里混用多个 lifetime。 /// internal static ServiceProvider CreateMediatorServiceProvider(Action? configure) { var services = new ServiceCollection(); configure?.Invoke(services); services.AddMediator(); return services.BuildServiceProvider(); } /// /// 判断某个类型是否正好实现了指定的闭合或开放 MediatR 合同。 /// /// 待判断类型。 /// 目标开放泛型合同,例如 。 /// 命中任一实现接口时返回 ;否则返回 internal static bool ImplementsOpenGenericContract(Type candidateType, Type openGenericContract) { ArgumentNullException.ThrowIfNull(candidateType); ArgumentNullException.ThrowIfNull(openGenericContract); return candidateType.GetInterfaces().Any(interfaceType => interfaceType.IsGenericType && interfaceType.GetGenericTypeDefinition() == openGenericContract); } }