範例(順序決定行為)
app.Use(async (ctx, next) => { /* 前置邏輯 */ await next(); /* 後置邏輯 */ });
app.Map("/health", branch =>
{
branch.Run(async ctx => await ctx.Response.WriteAsync("OK"));
});
app.Run(async ctx => await ctx.Response.WriteAsync("Hello"));
建議順序(概念性)
慣用 Middleware:啟動時建立單一實例
public sealed class RequestTimingMiddleware
{
private readonly RequestDelegate _next;
private readonly ILogger<RequestTimingMiddleware> _log; // 可建構子注入(非 Scoped)
public RequestTimingMiddleware(RequestDelegate next, ILogger<RequestTimingMiddleware> log)
{ _next = next; _log = log; }
public async Task InvokeAsync(HttpContext ctx, MyDbContext db) // Scoped 服務透過參數注入
{
var sw = ValueStopwatch.StartNew();
await _next(ctx);
_log.LogInformation("Path={Path} {Elapsed}ms", ctx.Request.Path, sw.GetElapsedTime().TotalMilliseconds);
// 可在此使用 db(每請求獨立作用域)
}
}
app.UseMiddleware<RequestTimingMiddleware>();
IMiddleware:每請求由 DI 容器建立新實例
public sealed class DbAuditMiddleware : IMiddleware
{
private readonly MyDbContext _db; // 可建構子注入 Scoped
public DbAuditMiddleware(MyDbContext db) => _db = db;
public async Task InvokeAsync(HttpContext ctx, RequestDelegate next)
{
await next(ctx);
}
}
// 註冊:services.AddTransient<DbAuditMiddleware>();
app.UseMiddleware<DbAuditMiddleware>();
選擇指引
重要規則
BackgroundService 無自動請求作用域,需手動建立:
public sealed class Worker : BackgroundService
{
private readonly IServiceScopeFactory _sf;
public Worker(IServiceScopeFactory sf) => _sf = sf;
protected override async Task ExecuteAsync(CancellationToken token)
{
while (!token.IsCancellationRequested)
{
using var scope = _sf.CreateScope();
var db = scope.ServiceProvider.GetRequiredService<MyDbContext>();
await Task.Delay(TimeSpan.FromSeconds(10), token);
}
}
}
常見陷阱
簡單小結