管道行为
使用行为添加横切逻辑。
管道行为 是 CoddyKit 上的免费 C# Academy 课时。 这是第 3 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 C# Academy 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 C# Academy 课程共包含 4 节课。
横切关注点
日志记录、验证、计时和事务适用于许多 handler。将这些代码复制到每个 handler 中既重复又容易出错。
MediatR 的流水线行为可以使用共享逻辑包装每个请求。
// One behavior runs around all handlersIPipelineBehavior
行为会实现 IPipelineBehavior<TRequest, TResponse>。其 Handle 方法会接收请求和一个调用流水线其余部分的 next 委托。
public class LoggingBehavior<TRequest, TResponse>
: IPipelineBehavior<TRequest, TResponse>
where TRequest : notnull
{
public async Task<TResponse> Handle(
TRequest request,
RequestHandlerDelegate<TResponse> next,
CancellationToken ct)
{
// before
var response = await next();
// after
return response;
}
}next 委托
next() 会调用下一个行为;如果当前行为是最后一个,则调用实际的 handler。调用前的代码会在进入过程中运行,调用后的代码会在返回过程中运行。
// [Behavior A in] -> [Behavior B in] -> [Handler]
// <- [Behavior B out] <- [A out]日志记录行为
具体的日志记录行为会在进入过程中记录请求名称,并在返回过程中记录经过的时间。
public async Task<TResponse> Handle(
TRequest request,
RequestHandlerDelegate<TResponse> next,
CancellationToken ct)
{
var name = typeof(TRequest).Name;
_logger.LogInformation("Handling {Name}", name);
var sw = Stopwatch.StartNew();
var response = await next();
_logger.LogInformation("{Name} took {Ms}ms", name, sw.ElapsedMilliseconds);
return response;
}注册行为
在 DI 中注册开放泛型行为。MediatR 会将它应用于每个请求。
builder.Services.AddTransient(
typeof(IPipelineBehavior<,>),
typeof(LoggingBehavior<,>));验证行为
一种常见用途是使用 FluentValidation 验证请求。该行为会在 handler 执行前运行所有验证器,只要有一个验证失败就抛出异常。
public async Task<TResponse> Handle(
TRequest request,
RequestHandlerDelegate<TResponse> next,
CancellationToken ct)
{
var context = new ValidationContext<TRequest>(request);
var failures = _validators
.Select(v => v.Validate(context))
.SelectMany(r => r.Errors)
.Where(f => f is not null)
.ToList();
if (failures.Count != 0)
throw new ValidationException(failures);
return await next();
}短路
行为可以通过不调用 next() 直接返回,从而完全跳过 handler——这对于缓存查询结果或拒绝无效请求很有用。
if (_cache.TryGet(key, out TResponse cached))
return cached; // handler never runs
var response = await next();
_cache.Set(key, response);
return response;行为排序
行为会按照注册顺序执行。请将日志记录放在最外层,然后依次放置验证和事务,这样每一层都能正确包装下一层。
services.AddTransient(typeof(IPipelineBehavior<,>), typeof(LoggingBehavior<,>));
services.AddTransient(typeof(IPipelineBehavior<,>), typeof(ValidationBehavior<,>));
services.AddTransient(typeof(IPipelineBehavior<,>), typeof(TransactionBehavior<,>));事务行为
请在数据库事务中包装命令 handler,使整个操作能够以原子方式提交或回滚。
await using var tx = await _db.Database.BeginTransactionAsync(ct);
try
{
var response = await next();
await tx.CommitAsync(ct);
return response;
}
catch
{
await tx.RollbackAsync(ct);
throw;
}针对特定请求
使用标记接口和泛型约束,让行为只应用于选择启用它的请求——例如,仅为命令启用事务。
public interface ITransactional { }
public record CreateOrderCommand(...) : IRequest<int>, ITransactional;
// where TRequest : ITransactional为什么行为优于中间件
与 HTTP 中间件不同,行为会针对每条消息运行,能够访问类型化的请求和响应,并且即使请求在 HTTP 之外分发(例如来自后台作业),也仍然有效。
// Strongly typed, transport-independent cross-cutting logic快速检查
请确认行为的工作方式。
回顾
您学习了流水线行为:
IPipelineBehavior<TRequest, TResponse>使用共享逻辑包装每个请求。next委托会推进流水线;跳过它会使 handler 短路。- 常见用途包括:日志记录、验证、事务和缓存。
- 行为按注册顺序运行,并且具有强类型。
下一步:通知和事件。
常见问题解答
「管道行为」课时是免费的吗?
是的 — 「管道行为」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 C# Academy 课程的其余内容,请升级到 CoddyKit PRO。 C# Academy 课程共包含 4 节课。
「管道行为」这节课中我会学到什么?
使用行为添加横切逻辑。 你通过在浏览器中直接运行的动手代码来练习 C# Academy,全天候 AI 导师会在你学习这节课的过程中回答你的问题。
学习 C# Academy 需要有经验吗?
无需任何先前经验。CoddyKit 上的 C# Academy 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 3 节课,共 4 节。
「管道行为」课时需要多长时间?
大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。
我能在这节 C# Academy 课中编写并运行代码吗?
能。每节 C# Academy 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。