下面用“由浅入深 + 可运行代码”的方式,把 C# 里常见的 3 种管道(HTTP 管道 / MediatR 管道 / TPL Dataflow 管道) 一次讲透。
所有示例都基于 .NET 6/7 Minimal API,复制即可运行。
1. HTTP 管道(ASP.NET Core Middleware)
1.1 概念
- 运行在 Kestrel 服务器 内部。
- 对 每个 HTTP 请求 做横切逻辑(日志、鉴权、异常处理、压缩 …)。
- 以 洋葱模型 组织:先注册的先执行外层,再进入内层,返回时反向再执行。
1.2 最小完整示例:全局计时 + 异常捕获
var builder = WebApplication.CreateBuilder();
var app = builder.Build();
// ① 计时中间件
app.Use(async (ctx, next) =>
{
var sw = System.Diagnostics.Stopwatch.StartNew();
await next(); // 继续下一个中间件
sw.Stop();
Console.WriteLine($"[{DateTime.Now:HH:mm:ss}] {ctx.Request.Path} 耗时 {sw.ElapsedMilliseconds} ms");
});
// ② 异常捕获中间件
app.Use(async (ctx, next) =>
{
try { await next(); }
catch (Exception ex)
{
ctx.Response.StatusCode = 500;
await ctx.Response.WriteAsync($"Error: {ex.Message}");
}
});
// ③ 业务端点
app.MapGet("/", () => "Hello Pipeline");
app.MapGet("/boom", () => throw new InvalidOperationException("boom!"));
app.Run();
运行后
/
→ 200 + 控制台打印耗时/boom
→ 500 +Error: boom!
2. MediatR 管道(进程内业务级)
2.1 概念
- 不是 HTTP 层,而是在你调用
IMediator.Send/ Publish
时生效。 - 通过
IPipelineBehavior<TRequest,TResponse>
实现 验证、缓存、事务、日志 等横切。 - 支持 多行为按注册顺序 包裹 Handler。
2.2 NuGet & 注册
dotnet add package MediatR
dotnet add package MediatR.Extensions.Microsoft.DependencyInjection
builder.Services.AddMediatR(cfg =>
cfg.RegisterServicesFromAssembly(typeof(Program).Assembly));
2.3 完整示例:验证 + 缓存 + Handler
// ① 请求/响应
public record GetUserQuery(int Id) : IRequest<UserDto>;
public record UserDto(int Id, string Name);
// ② Handler
public class GetUserHandler : IRequestHandler<GetUserQuery, UserDto>
{
public Task<UserDto> Handle(GetUserQuery req, CancellationToken ct)
{
Console.WriteLine("👉 Handler 被执行");
return Task.FromResult(new UserDto(req.Id, "Alice"));
}
}
// ③ 验证行为
public class ValidateBehavior<TReq, TRes> : IPipelineBehavior<TReq, TRes>
{
public async Task<TRes> Handle(TReq req, RequestHandlerDelegate<TRes> next, CancellationToken ct)
{
if (req is GetUserQuery q && q.Id <= 0)
throw new ArgumentException("Id 必须 > 0");
return await next();
}
}
// ④ 缓存行为(极简内存缓存)
public class CacheBehavior<TReq, TRes> : IPipelineBehavior<TReq, TRes>
{
private static readonly ConcurrentDictionary<string, object?> _cache = new();
public async Task<TRes> Handle(TReq req, RequestHandlerDelegate<TRes> next, CancellationToken ct)
{
var key = $"{typeof(TReq).Name}:{JsonSerializer.Serialize(req)}";
if (_cache.TryGetValue(key, out var boxed)) return (TRes)boxed!;
var res = await next();
_cache[key] = res;
return res;
}
}
// ⑤ 注册顺序 == 执行顺序
builder.Services.AddTransient(typeof(IPipelineBehavior<,>), typeof(ValidateBehavior<,>));
builder.Services.AddTransient(typeof(IPipelineBehavior<,>), typeof(CacheBehavior<,>));
// ⑥ 使用
app.MapGet("/user/{id:int}", async (int id, ISender mediatr) =>
{
var user = await mediatr.Send(new GetUserQuery(id));
return user;
});
控制台输出
第一次:👉 Handler 被执行
第二次:直接返回缓存结果,不再进入 Handler。
3. TPL Dataflow 管道(进程内数据流)
3.1 概念
- 在 同一进程 内把任务拆成 块(Block) → 流水线并行。
- 适合 ETL、爬虫、图片处理 等 CPU/IO 密集型流水线。
3.2 NuGet & 最小示例:下载 → 转换 → 保存
dotnet add package System.Threading.Tasks.Dataflow
using System.Threading.Tasks.Dataflow;
// ① 定义 3 个块
var downloader = new TransformBlock<string, string>(url =>
{
Console.WriteLine($"下载 {url}");
Thread.Sleep(500); // 模拟 IO
return $"html-of-{url}";
});
var transformer = new TransformBlock<string, int>(html =>
{
Console.WriteLine($"解析 {html}");
return html.Length;
});
var saver = new ActionBlock<int>(len =>
{
Console.WriteLine($"保存长度 {len}");
});
// ② 链接成管道
downloader.LinkTo(transformer, new() { PropagateCompletion = true });
transformer.LinkTo(saver, new() { PropagateCompletion = true });
// ③ 灌数据
foreach (var url in new[] { "a.com", "b.com", "c.com" })
downloader.Post(url);
downloader.Complete();
await saver.Completion; // 等待整个流水线结束
输出示例
下载 a.com
下载 b.com
下载 c.com
解析 html-of-a.com
保存长度 13
...
4. 总结速查
类型 | 作用层 | 关键字/接口 | 典型场景 |
---|---|---|---|
HTTP 管道 | Web 服务器 | UseMiddleware , UseWhen | 鉴权、日志、异常 |
MediatR 管道 | 进程内业务 | IPipelineBehavior<T,R> | 验证、缓存、事务 |
Dataflow 管道 | 进程内数据流 | TransformBlock , ActionBlock | ETL、爬虫、流水线 |
记住一句话:
HTTP 管请求 → MediatR 管业务 → Dataflow 管数据流。