feat(core): 集成Mediator框架并添加CQRS行为支持

- 移除直接的Mediator包依赖,改用Source Generator方式集成
- 添加RegisterMediator方法用于配置Mediator框架
- 添加RegisterMediatorBehavior方法用于注册管道行为
- 实现LoggingBehavior用于记录CQRS请求处理日志
- 实现PerformanceBehavior用于监控请求执行性能
- 更新架构配置以支持Mediator自定义配置
- 优化容器冻结检查的代码结构
This commit is contained in:
GeWuYou 2026-02-14 11:55:13 +08:00 committed by gewuyou
parent b7efe0cac4
commit 91c9163312
10 changed files with 237 additions and 19 deletions

View File

@ -26,5 +26,9 @@
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
</PackageReference>
<PackageReference Include="Mediator.Abstractions" Version="3.0.1"/>
<PackageReference Include="Mediator.SourceGenerator" Version="3.0.1">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
</ItemGroup>
</Project>

View File

@ -78,6 +78,14 @@ public interface IArchitecture : IAsyncInitializable
/// <param name="onCreated">工具实例创建后的回调函数可为null</param>
void RegisterUtility<T>(Action<T>? onCreated = null) where T : class, IUtility;
/// <summary>
/// 注册中介行为管道
/// 用于配置Mediator框架的行为拦截和处理逻辑
/// </summary>
/// <typeparam name="TBehavior">行为类型,必须是引用类型</typeparam>
void RegisterMediatorBehavior<TBehavior>()
where TBehavior : class;
/// <summary>
/// 安装架构模块
/// </summary>

View File

@ -1,4 +1,5 @@
using GFramework.Core.Abstractions.properties;
using Mediator;
namespace GFramework.Core.Abstractions.architecture;
@ -16,4 +17,11 @@ public interface IArchitectureConfiguration
/// 获取或设置架构选项,包含架构相关的配置参数
/// </summary>
ArchitectureProperties ArchitectureProperties { get; set; }
/// <summary>
/// 获取或设置Mediator配置委托
/// 用于自定义Mediator框架的配置选项
/// </summary>
/// <returns>配置Mediator选项的委托函数可为null</returns>
Action<MediatorOptions>? Configurator { get; set; }
}

View File

@ -1,5 +1,6 @@
using GFramework.Core.Abstractions.rule;
using GFramework.Core.Abstractions.system;
using Mediator;
using Microsoft.Extensions.DependencyInjection;
namespace GFramework.Core.Abstractions.ioc;
@ -71,6 +72,21 @@ public interface IIocContainer : IContextAware
/// <param name="factory">创建服务实例的工厂委托函数</param>
void RegisterFactory<TService>(Func<IServiceProvider, TService> factory) where TService : class;
/// <summary>
/// 注册中介行为管道
/// 用于配置Mediator框架的行为拦截和处理逻辑
/// </summary>
/// <typeparam name="TBehavior">行为类型,必须是引用类型</typeparam>
void RegisterMediatorBehavior<TBehavior>()
where TBehavior : class;
/// <summary>
/// 注册并配置Mediator框架
/// 提供自定义配置选项来调整Mediator的行为
/// </summary>
/// <param name="configurator">可选的配置委托函数用于自定义Mediator选项</param>
void RegisterMediator(Action<MediatorOptions>? configurator = null);
#endregion
#region Get Methods

View File

@ -13,10 +13,6 @@
<ItemGroup>
<PackageReference Include="LanguageExt.Core" Version="4.4.9"/>
<PackageReference Include="Mediator.Abstractions" Version="3.0.1"/>
<PackageReference Include="Mediator.SourceGenerator" Version="3.0.1">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="10.0.3"/>
</ItemGroup>
</Project>

View File

@ -10,7 +10,6 @@ using GFramework.Core.Abstractions.utility;
using GFramework.Core.environment;
using GFramework.Core.extensions;
using GFramework.Core.logging;
using Mediator;
using Microsoft.Extensions.DependencyInjection;
using IDisposable = GFramework.Core.Abstractions.lifecycle.IDisposable;
@ -30,6 +29,17 @@ public abstract class Architecture(
{
#region Module Management
/// <summary>
/// 注册中介行为管道
/// 用于配置Mediator框架的行为拦截和处理逻辑
/// </summary>
/// <typeparam name="TBehavior">行为类型,必须是引用类型</typeparam>
public void RegisterMediatorBehavior<TBehavior>() where TBehavior : class
{
_logger.Debug($"Registering mediator behavior: {typeof(TBehavior).Name}");
Container.RegisterPlurality<TBehavior>();
}
/// <summary>
/// 安装架构模块
/// </summary>
@ -627,14 +637,7 @@ public abstract class Architecture(
// 为服务设置上下文
Services.SetContext(_context);
// 添加 Mediator
Container.Services.AddMediator(options =>
{
options.Namespace = "GFramework.Core.Mediator";
options.ServiceLifetime = ServiceLifetime.Singleton;
options.GenerateTypesAsInternal = true;
options.NotificationPublisherType = typeof(ForeachAwaitPublisher);
});
Container.RegisterMediator(Configuration.Configurator);
// === 用户 Init ===
_logger.Debug("Calling user Init()");
Init();

View File

@ -2,6 +2,8 @@
using GFramework.Core.Abstractions.logging;
using GFramework.Core.Abstractions.properties;
using GFramework.Core.logging;
using Mediator;
using Microsoft.Extensions.DependencyInjection;
namespace GFramework.Core.architecture;
@ -32,4 +34,17 @@ public sealed class ArchitectureConfiguration : IArchitectureConfiguration
AllowLateRegistration = false,
StrictPhaseValidation = true
};
/// <summary>
/// 获取或设置Mediator配置委托
/// 用于自定义Mediator框架的配置选项
/// </summary>
/// <returns>配置Mediator选项的委托函数可为null</returns>
public Action<MediatorOptions>? Configurator { get; set; } = options =>
{
options.Namespace = "GFramework.Core.Mediator";
options.ServiceLifetime = ServiceLifetime.Singleton;
options.GenerateTypesAsInternal = true;
options.NotificationPublisherType = typeof(ForeachAwaitPublisher);
};
}

View File

@ -0,0 +1,59 @@
// Copyright (c) 2026 GeWuYou
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
using GFramework.Core.Abstractions.logging;
using GFramework.Core.logging;
using Mediator;
namespace GFramework.Core.cqrs.behaviors;
/// <summary>
/// 日志记录行为类用于在CQRS管道中记录请求处理的日志信息
/// 实现IPipelineBehavior接口为请求处理提供日志记录功能
/// </summary>
/// <typeparam name="TRequest">请求类型必须实现IRequest接口</typeparam>
/// <typeparam name="TResponse">响应类型</typeparam>
public sealed class LoggingBehavior<TRequest, TResponse> : IPipelineBehavior<TRequest, TResponse>
where TRequest : IRequest<TResponse>
{
private readonly ILogger _logger =
LoggerFactoryResolver.Provider.CreateLogger(nameof(LoggingBehavior<TRequest, TResponse>));
/// <summary>
/// 处理请求并记录日志
/// 在请求处理前后记录调试信息,处理异常时记录错误日志
/// </summary>
/// <param name="message">要处理的请求消息</param>
/// <param name="next">下一个处理委托,用于继续管道执行</param>
/// <param name="cancellationToken">取消令牌,用于取消操作</param>
/// <returns>处理结果的ValueTask</returns>
public ValueTask<TResponse> Handle(TRequest message, MessageHandlerDelegate<TRequest, TResponse> next,
CancellationToken cancellationToken)
{
var requestName = typeof(TRequest).Name;
_logger.Debug($"Handling {requestName}");
try
{
var response = next(message, cancellationToken);
_logger.Debug($"Handled {requestName} successfully");
return response;
}
catch (Exception ex)
{
_logger.Error($"Error handling {requestName}", ex);
throw;
}
}
}

View File

@ -0,0 +1,59 @@
// Copyright (c) 2026 GeWuYou
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
using System.Diagnostics;
using GFramework.Core.Abstractions.logging;
using GFramework.Core.logging;
using Mediator;
namespace GFramework.Core.cqrs.behaviors;
/// <summary>
/// 性能监控行为类用于监控CQRS请求的执行时间
/// 实现IPipelineBehavior接口检测并记录执行时间过长的请求
/// </summary>
/// <typeparam name="TRequest">请求类型必须实现IRequest接口</typeparam>
/// <typeparam name="TResponse">响应类型</typeparam>
public sealed class PerformanceBehavior<TRequest, TResponse> : IPipelineBehavior<TRequest, TResponse>
where TRequest : IRequest<TResponse>
{
private readonly ILogger _logger =
LoggerFactoryResolver.Provider.CreateLogger(nameof(PerformanceBehavior<TRequest, TResponse>));
/// <summary>
/// 处理请求并监控执行时间
/// 使用Stopwatch测量请求处理耗时超过500ms时记录警告日志
/// </summary>
/// <param name="message">要处理的请求消息</param>
/// <param name="next">下一个处理委托,用于继续管道执行</param>
/// <param name="cancellationToken">取消令牌,用于取消操作</param>
/// <returns>处理结果的ValueTask</returns>
public ValueTask<TResponse> Handle(TRequest message, MessageHandlerDelegate<TRequest, TResponse> next,
CancellationToken cancellationToken)
{
var stopwatch = Stopwatch.StartNew();
var response = next(message, cancellationToken);
stopwatch.Stop();
var elapsedMilliseconds = stopwatch.ElapsedMilliseconds;
// 只有当执行时间超过500毫秒时才记录警告日志
if (elapsedMilliseconds <= 500) return response;
var requestName = typeof(TRequest).Name;
_logger.Warn($"Long Running Request: {requestName} ({elapsedMilliseconds} ms)");
return response;
}
}

View File

@ -3,6 +3,7 @@ using GFramework.Core.Abstractions.logging;
using GFramework.Core.Abstractions.system;
using GFramework.Core.logging;
using GFramework.Core.rule;
using Mediator;
using Microsoft.Extensions.DependencyInjection;
namespace GFramework.Core.ioc;
@ -24,12 +25,10 @@ public class MicrosoftDiContainer(IServiceCollection? serviceCollection = null)
/// <exception cref="InvalidOperationException">当容器已冻结时抛出</exception>
private void ThrowIfFrozen()
{
if (_frozen)
{
const string errorMsg = "MicrosoftDiContainer is frozen";
_logger.Error(errorMsg);
throw new InvalidOperationException(errorMsg);
}
if (!_frozen) return;
const string errorMsg = "MicrosoftDiContainer is frozen";
_logger.Error(errorMsg);
throw new InvalidOperationException(errorMsg);
}
#endregion
@ -241,6 +240,57 @@ public class MicrosoftDiContainer(IServiceCollection? serviceCollection = null)
Services.AddSingleton(factory);
}
/// <summary>
/// 注册中介行为管道
/// 用于配置Mediator框架的行为拦截和处理逻辑
/// </summary>
/// <typeparam name="TBehavior">行为类型,必须是引用类型</typeparam>
public void RegisterMediatorBehavior<TBehavior>() where TBehavior : class
{
_lock.EnterWriteLock();
try
{
ThrowIfFrozen();
Services.AddSingleton(
typeof(IPipelineBehavior<,>),
typeof(TBehavior)
);
_logger.Debug($"Mediator behavior registered: {typeof(TBehavior).Name}");
}
finally
{
_lock.ExitWriteLock();
}
}
/// <summary>
/// 注册 Mediator基于 Source Generator
/// </summary>
/// <param name="configurator">可选的配置委托</param>
public void RegisterMediator(Action<MediatorOptions>? configurator = null)
{
_lock.EnterWriteLock();
try
{
ThrowIfFrozen();
// 添加 Mediator
Services.AddMediator(options =>
{
// 用户自定义配置
configurator?.Invoke(options);
});
_logger.Info("Mediator registered with Source Generator");
}
finally
{
_lock.ExitWriteLock();
}
}
#endregion
#region Get