返回 Skill 列表
extension
分类: 开发与工程无需 API Key

aspnet-middleware

ASP.NET Core自定义中间件、管道顺序、异常处理中间件以及请求/响应操作。使用时机:用户提到“中间件”、“请求管道”、“异常中间件”、“ASP.NET中间件”、“UseMiddleware”、“管道顺序”。不应用于:Express中间件 - 使用`express`,NestJS中间件 - 使用`nestjs`

person作者: jakexiaohubgithub

ASP.NET Core Middleware - Quick Reference

Deep Knowledge: Use mcp__documentation__fetch_docs with technology: aspnet-core, topic: middleware for comprehensive documentation.

Pipeline Order

Request → Exception Handler → HSTS → HTTPS Redirect → Static Files
→ CORS → Authentication → Authorization → Custom Middleware → Endpoint
var app = builder.Build();

// 1. Exception handling (first to catch all)
app.UseExceptionHandler("/error");
app.UseHsts();

// 2. HTTPS and static files
app.UseHttpsRedirection();
app.UseStaticFiles();

// 3. Routing
app.UseRouting();

// 4. CORS (before auth)
app.UseCors();

// 5. Auth
app.UseAuthentication();
app.UseAuthorization();

// 6. Custom middleware
app.UseMiddleware<RequestLoggingMiddleware>();

// 7. Endpoints
app.MapControllers();

Custom Middleware (Convention-based)

public class RequestLoggingMiddleware
{
    private readonly RequestDelegate _next;
    private readonly ILogger<RequestLoggingMiddleware> _logger;

    public RequestLoggingMiddleware(RequestDelegate next, ILogger<RequestLoggingMiddleware> logger)
    {
        _next = next;
        _logger = logger;
    }

    public async Task InvokeAsync(HttpContext context)
    {
        var sw = Stopwatch.StartNew();

        _logger.LogInformation("Request {Method} {Path}", context.Request.Method, context.Request.Path);

        await _next(context);

        sw.Stop();
        _logger.LogInformation("Response {StatusCode} in {Elapsed}ms",
            context.Response.StatusCode, sw.ElapsedMilliseconds);
    }
}

// Register
app.UseMiddleware<RequestLoggingMiddleware>();

Exception Handling Middleware

public class ExceptionMiddleware
{
    private readonly RequestDelegate _next;
    private readonly ILogger<ExceptionMiddleware> _logger;

    public ExceptionMiddleware(RequestDelegate next, ILogger<ExceptionMiddleware> logger)
    {
        _next = next;
        _logger = logger;
    }

    public async Task InvokeAsync(HttpContext context)
    {
        try
        {
            await _next(context);
        }
        catch (NotFoundException ex)
        {
            context.Response.StatusCode = StatusCodes.Status404NotFound;
            await context.Response.WriteAsJsonAsync(new { error = ex.Message });
        }
        catch (ValidationException ex)
        {
            context.Response.StatusCode = StatusCodes.Status400BadRequest;
            await context.Response.WriteAsJsonAsync(new { errors = ex.Errors });
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Unhandled exception");
            context.Response.StatusCode = StatusCodes.Status500InternalServerError;
            await context.Response.WriteAsJsonAsync(new { error = "An unexpected error occurred" });
        }
    }
}

Inline Middleware

// Simple Use
app.Use(async (context, next) =>
{
    context.Response.Headers.Append("X-Request-Id", Guid.NewGuid().ToString());
    await next(context);
});

// Terminal middleware (does not call next)
app.Map("/health", app => app.Run(async context =>
{
    await context.Response.WriteAsync("OK");
}));

Anti-Patterns

| Anti-Pattern | Why It's Bad | Correct Approach | |--------------|--------------|------------------| | Wrong middleware order | Auth bypassed, CORS fails | Follow documented order | | Exception handler not first | Misses early errors | Place at start of pipeline | | Reading body without buffering | Stream consumed once | Enable EnableBuffering() | | Blocking calls in middleware | Thread starvation | Use async Task InvokeAsync |

Quick Troubleshooting

| Issue | Likely Cause | Solution | |-------|--------------|----------| | CORS not working | Wrong order | Place UseCors() before UseAuth | | Middleware not executing | Registered after endpoints | Register before MapControllers() | | Body empty in middleware | Already read by binding | Use EnableBuffering() | | Static files not served | Wrong order | Place UseStaticFiles() early |