增加Mediat Pip特性,并用实例来做一个demo
This commit is contained in:
1 parent
292cb8638c
commit
c9ac7412ab
19 files changed
+682
-108
No files matched your search
@@ -0,0 +1,26 @@
|
||||
using FreeSql;
|
||||
using MediatR;
|
||||
|
||||
namespace MAX.Framework.Mediation;
|
||||
|
||||
/// <summary>为通过特性选择的命令管理事务;所有读写使用执行上下文中的 ORM。</summary>
|
||||
public sealed class TransactionBehavior<TRequest, TResponse>(
|
||||
IFreeSql freeSql, UnitOfWorkExecutionContext context) : IPipelineBehavior<TRequest, TResponse>
|
||||
where TRequest : IRequest<TResponse>
|
||||
{
|
||||
public async Task<TResponse> Handle(TRequest request, CancellationToken cancellationToken,
|
||||
RequestHandlerDelegate<TResponse> next)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
if (context.IsActive)
|
||||
throw new InvalidOperationException("不支持嵌套事务命令,请在同一个命令处理器内完成事务操作");
|
||||
using var work = freeSql.CreateUnitOfWork();
|
||||
work.GetOrBeginTransaction();
|
||||
using var execution = context.Enter(work.Orm);
|
||||
var response = await next();
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
work.Commit();
|
||||
return response;
|
||||
// 未提交时,工作单元释放自动回滚;执行上下文同时清理。
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
using System.Threading;
|
||||
|
||||
namespace MAX.Framework.Mediation;
|
||||
|
||||
/// <summary>沿当前异步调用链传递事务 ORM,隔离并行命令的执行状态。</summary>
|
||||
public sealed class UnitOfWorkExecutionContext
|
||||
{
|
||||
private readonly AsyncLocal<IFreeSql?> _current = new();
|
||||
|
||||
public IFreeSql Orm => _current.Value
|
||||
?? throw new InvalidOperationException("当前操作必须在事务管道内执行");
|
||||
|
||||
public bool IsActive => _current.Value != null;
|
||||
|
||||
internal IDisposable Enter(IFreeSql orm)
|
||||
{
|
||||
if (IsActive)
|
||||
throw new InvalidOperationException("不支持嵌套事务命令,请在同一个命令处理器内完成事务操作");
|
||||
_current.Value = orm;
|
||||
return new ExecutionScope(this);
|
||||
}
|
||||
|
||||
private sealed class ExecutionScope(UnitOfWorkExecutionContext context) : IDisposable
|
||||
{
|
||||
public void Dispose() => context._current.Value = null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
using MAX.Core.Mediation;
|
||||
using MediatR;
|
||||
|
||||
namespace MAX.Framework.Mediation;
|
||||
|
||||
/// <summary>执行请求自身的参数校验,验证通过后才进入后续管道。</summary>
|
||||
public sealed class ValidationBehavior<TRequest, TResponse> : IPipelineBehavior<TRequest, TResponse>
|
||||
where TRequest : IRequest<TResponse>, IValidatableRequest
|
||||
{
|
||||
public Task<TResponse> Handle(TRequest request, CancellationToken cancellationToken,
|
||||
RequestHandlerDelegate<TResponse> next)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(request);
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
request.Validate();
|
||||
return next();
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user