C# Academy · 课时

ASP.NET Core 管道概览

了解请求如何流经中间件管道和 HttpContext,以及响应如何逐步构建。

第 1 / 4 课12 个步骤

ASP.NET Core 管道概览 是 CoddyKit 上的免费 C# Academy 课时。 这是第 1 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 C# Academy 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 C# Academy 课程共包含 4 节课。

请求管道

ASP.NET Core 中的每个 HTTP 请求都会流经一个中间件管道。每个中间件都可以检查、修改、短路请求,或将请求转发给下一个组件。理解这个管道是构建 ASP.NET Core 应用的基础。

HttpContext:请求的封装对象

HttpContext 携带请求和响应的所有信息:标头、Cookie、正文、用户声明、连接信息以及取消令牌。所有中间件都在它上面运行。

app.Use(async (context, next) =>
{
    // Read request info
    var method  = context.Request.Method;
    var path    = context.Request.Path;
    var headers = context.Request.Headers;
    var user    = context.User.Identity?.Name;

    // Write to response
    context.Response.Headers.Append("X-Processed-By", "MyMiddleware");

    await next(context); // forward to next middleware
});

中间件注册顺序

中间件按照注册顺序运行。响应则按相反顺序展开(类似栈)。顺序至关重要:身份验证必须在授权之前运行;路由必须在端点匹配之前运行。

// Typical order for an ASP.NET Core app:
app.UseExceptionHandler("/error"); // outermost — catches everything
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseCors("policy");
app.UseAuthentication();  // must be before Authorization
app.UseAuthorization();
app.UseRateLimiter();
app.UseOutputCache();
// MapHub, MapControllers, MapGet etc.
app.Run();

Use、Run 和 Map

三种方法可以添加中间件:Use(调用下一个组件)、Run(终止管道,绝不调用下一个组件)和 Map(根据路径进行分支)。

// Use: passes to next
app.Use(async (ctx, next) =>
{
    Console.WriteLine("Before");
    await next(ctx);
    Console.WriteLine("After");
});

// Run: terminal — no next
app.Run(async ctx =>
    await ctx.Response.WriteAsync("Terminal"));

// Map: branch on path prefix
app.Map("/api", apiApp =>
    apiApp.Run(async ctx =>
        await ctx.Response.WriteAsync("API branch")));

请求正文与响应正文

请求正文和响应正文都是流。请求正文只能读取一次——如果需要多次读取(例如在多个中间件中读取),请启用请求正文缓冲。

app.Use(async (ctx, next) =>
{
    // Enable buffering so body can be read multiple times
    ctx.Request.EnableBuffering();

    using var reader = new StreamReader(
        ctx.Request.Body,
        leaveOpen: true);
    var body = await reader.ReadToEndAsync();
    ctx.Request.Body.Position = 0; // rewind for next middleware

    Console.WriteLine($"Body: {body}");
    await next(ctx);
});

让管道短路

中间件可以通过写入响应且不调用 next 来让管道短路。这适用于身份验证入口、运行状况检查或维护页面。

app.Use(async (ctx, next) =>
{
    if (ctx.Request.Path == "/maintenance")
    {
        ctx.Response.StatusCode = 503;
        await ctx.Response.WriteAsync("Service under maintenance");
        return; // short-circuit — next is NOT called
    }
    await next(ctx);
});

IMiddleware 接口

对于需要 DI 的基于类的中间件,请实现 IMiddleware。在 DI 中注册该实现,然后使用 app.UseMiddleware<T>()。

public class RequestTimingMiddleware : IMiddleware
{
    private readonly ILogger<RequestTimingMiddleware> _logger;
    public RequestTimingMiddleware(ILogger<RequestTimingMiddleware> l) => _logger = l;

    public async Task InvokeAsync(HttpContext ctx, RequestDelegate next)
    {
        var sw = System.Diagnostics.Stopwatch.StartNew();
        await next(ctx);
        _logger.LogInformation("{Method} {Path}: {Ms}ms",
            ctx.Request.Method, ctx.Request.Path, sw.ElapsedMilliseconds);
    }
}

// Register:
builder.Services.AddTransient<RequestTimingMiddleware>();
app.UseMiddleware<RequestTimingMiddleware>();

约定式中间件类

另一种方式是创建一个包含 InvokeAsync(HttpContext, RequestDelegate) 方法的类。框架会通过构造函数注入依赖项(包括下一个委托)。

public class ApiKeyMiddleware
{
    private readonly RequestDelegate _next;
    private readonly string _key;

    // RequestDelegate injected by framework
    public ApiKeyMiddleware(RequestDelegate next, IConfiguration cfg)
    {
        _next = next;
        _key = cfg["ApiKey"] ?? "";
    }

    public async Task InvokeAsync(HttpContext ctx)
    {
        if (ctx.Request.Headers["X-Api-Key"] != _key)
        {
            ctx.Response.StatusCode = 401;
            return;
        }
        await _next(ctx);
    }
}

调用下一个组件后修改响应

await next(ctx) 之后的代码会在响应开始写入后运行。您可以在调用 next 之前添加响应标头,但之后不能再修改状态码或正文。

app.Use(async (ctx, next) =>
{
    // Before: add response headers (safe)
    ctx.Response.OnStarting(() =>
    {
        ctx.Response.Headers.Append("X-Request-Id",
            Guid.NewGuid().ToString("N"));
        return Task.CompletedTask;
    });

    await next(ctx);

    // After: response may already be sent
    // SAFE: logging, metrics
    // UNSAFE: changing status code or writing body
    Console.WriteLine($"Response status: {ctx.Response.StatusCode}");
});

实际案例:关联 ID 中间件

生产环境中的关联 ID 中间件会为每个请求添加跟踪 ID,用于分布式跟踪和日志记录。

public class CorrelationIdMiddleware
{
    private readonly RequestDelegate _next;
    private const string Header = "X-Correlation-Id";

    public CorrelationIdMiddleware(RequestDelegate next) => _next = next;

    public async Task InvokeAsync(HttpContext ctx)
    {
        var correlationId = ctx.Request.Headers[Header].FirstOrDefault()
            ?? Guid.NewGuid().ToString("N");

        ctx.Items["CorrelationId"] = correlationId;

        ctx.Response.OnStarting(() =>
        {
            ctx.Response.Headers.Append(Header, correlationId);
            return Task.CompletedTask;
        });

        using (Serilog.Context.LogContext.PushProperty("CorrelationId", correlationId))
            await _next(ctx);
    }
}

快速检查

添加中间件时,app.Use() 和 app.Run() 有什么区别?

回顾:ASP.NET Core 管道概览

关键要点:

  • 中间件按照注册顺序运行;响应按相反顺序展开
  • Use → 调用下一个组件;Run → 终止管道;Map → 基于路径进行分支
  • HttpContext 包含请求、响应、用户和取消令牌
  • 启用缓冲,以便多次读取请求正文
  • IMiddleware 接口支持适合 DI 的基于类的中间件
  • 通过 OnStarting() 添加响应标头;调用 next 后不要更改状态
免费开始

用 AI 导师学习 C# — 免费

在浏览器中编写并运行真实代码,获得全天候 AI 导师的即时帮助,并在网页或应用中继续学习。

课程
93
课程
346

常见问题解答

「ASP.NET Core 管道概览」课时是免费的吗?

是的 — 「ASP.NET Core 管道概览」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 C# Academy 课程的其余内容,请升级到 CoddyKit PRO。 C# Academy 课程共包含 4 节课。

「ASP.NET Core 管道概览」这节课中我会学到什么?

了解请求如何流经中间件管道和 HttpContext,以及响应如何逐步构建。 你通过在浏览器中直接运行的动手代码来练习 C# Academy,全天候 AI 导师会在你学习这节课的过程中回答你的问题。

学习 C# Academy 需要有经验吗?

无需任何先前经验。CoddyKit 上的 C# Academy 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 1 节课,共 4 节。

「ASP.NET Core 管道概览」课时需要多长时间?

大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。

我能在这节 C# Academy 课中编写并运行代码吗?

能。每节 C# Academy 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。

此课程中的所有课时

  1. ASP.NET Core 管道概览
  2. 编写自定义中间件
  3. 短路与分支
  4. 中间件顺序与内置中间件
← 返回 C# Academy