Scrittura di middleware personalizzati
Crei middleware inline con Use/Run/Map e middleware basati su classi con InvokeAsync per ottenere componenti riutilizzabili.
Scrittura di middleware personalizzati è una lezione C# Academy gratuita su CoddyKit. Questa è la lezione 2 di 4. Puoi leggere la lezione completa qui gratuitamente — poi esercitati direttamente nel browser con un editor di codice integrato e un tutor IA disponibile 24/7. Fa parte del percorso di apprendimento C# Academy, e i tuoi progressi si sincronizzano tra il web e l'app CoddyKit. Il corso C# Academy include 4 lezioni in totale.
Perché creare middleware personalizzati?
Il middleware personalizzato gestisce aspetti trasversali che si applicano a molte richieste: registrazione dei log, misurazione dei tempi, gestione degli errori, autenticazione, compressione e caching. Scriverlo una sola volta fa sì che la logica venga eseguita automaticamente per ogni richiesta corrispondente.
Middleware inline con Use
Il modo più rapido per aggiungere un middleware consiste nel passare un delegato a app.Use(). È una soluzione adatta alla prototipazione o a una logica veramente semplice.
app.Use(async (context, next) =>
{
var start = DateTimeOffset.UtcNow;
await next(context);
var elapsed = DateTimeOffset.UtcNow - start;
context.Response.Headers.Append(
"X-Elapsed", elapsed.TotalMilliseconds.ToString("F0") + "ms");
});Middleware basato su classi (convenzionale)
Una classe di middleware convenzionale ha un costruttore che riceve RequestDelegate e un metodo pubblico InvokeAsync. Ulteriori parametri del costruttore possono essere inseriti tramite DI.
public class SecurityHeadersMiddleware
{
private readonly RequestDelegate _next;
public SecurityHeadersMiddleware(RequestDelegate next) => _next = next;
public async Task InvokeAsync(HttpContext context)
{
var headers = context.Response.Headers;
headers.Append("X-Content-Type-Options", "nosniff");
headers.Append("X-Frame-Options", "DENY");
headers.Append("X-XSS-Protection", "1; mode=block");
headers.Append("Referrer-Policy", "strict-origin-when-cross-origin");
await _next(context);
}
}
// Extension method for clean registration:
public static class SecurityHeadersExtensions
{
public static IApplicationBuilder UseSecurityHeaders(
this IApplicationBuilder app) =>
app.UseMiddleware<SecurityHeadersMiddleware>();
}IMiddleware per le dipendenze con ambito Scoped
Se il middleware necessita di servizi con ambito Scoped, come DbContext, implementi IMiddleware. Lo registri come Scoped: il framework lo risolverà nuovamente per ogni richiesta.
public class AuditMiddleware : IMiddleware
{
private readonly AuditDbContext _db;
private readonly IHttpContextAccessor _http;
public AuditMiddleware(AuditDbContext db, IHttpContextAccessor http)
{
_db = db;
_http = http;
}
public async Task InvokeAsync(HttpContext ctx, RequestDelegate next)
{
await next(ctx);
if (ctx.Request.Method != "GET")
{
_db.AuditLogs.Add(new AuditLog
{
User = ctx.User.Identity?.Name,
Path = ctx.Request.Path,
Status = ctx.Response.StatusCode,
At = DateTime.UtcNow
});
await _db.SaveChangesAsync();
}
}
}
builder.Services.AddScoped<AuditMiddleware>();
app.UseMiddleware<AuditMiddleware>();Middleware con Options
Passi la configurazione al middleware tramite un oggetto options nel costruttore. Registri le options nel contenitore DI oppure le passi inline durante la registrazione del middleware.
public class ThrottleOptions
{
public int MaxRequestsPerSecond { get; set; } = 100;
public string[] ExcludedPaths { get; set; } = Array.Empty<string>();
}
public class ThrottleMiddleware
{
private readonly RequestDelegate _next;
private readonly ThrottleOptions _options;
public ThrottleMiddleware(RequestDelegate next, ThrottleOptions options)
{
_next = next;
_options = options;
}
// ...
}
// Registration with options:
app.UseMiddleware<ThrottleMiddleware>(new ThrottleOptions
{
MaxRequestsPerSecond = 50
});Middleware per la gestione delle eccezioni
Un middleware personalizzato per la gestione delle eccezioni intercetta tutte le eccezioni non gestite e restituisce risposte di errore strutturate.
public class GlobalExceptionMiddleware
{
private readonly RequestDelegate _next;
private readonly ILogger<GlobalExceptionMiddleware> _logger;
public GlobalExceptionMiddleware(RequestDelegate next, ILogger<GlobalExceptionMiddleware> l)
{
_next = next;
_logger = l;
}
public async Task InvokeAsync(HttpContext ctx)
{
try { await _next(ctx); }
catch (NotFoundException ex)
{
ctx.Response.StatusCode = 404;
await ctx.Response.WriteAsJsonAsync(new { error = ex.Message });
}
catch (Exception ex)
{
_logger.LogError(ex, "Unhandled exception");
ctx.Response.StatusCode = 500;
await ctx.Response.WriteAsJsonAsync(new { error = "Internal server error" });
}
}
}Middleware per la registrazione delle richieste
Un middleware strutturato per la registrazione di richieste e risposte memorizza metodo, percorso, codice di stato e tempo trascorso per ogni richiesta.
public class RequestLoggingMiddleware
{
private readonly RequestDelegate _next;
private readonly ILogger<RequestLoggingMiddleware> _log;
public RequestLoggingMiddleware(RequestDelegate n, ILogger<RequestLoggingMiddleware> l)
{ _next = n; _log = l; }
public async Task InvokeAsync(HttpContext ctx)
{
var sw = System.Diagnostics.Stopwatch.StartNew();
await _next(ctx);
sw.Stop();
_log.LogInformation(
"{Method} {Path} -> {Status} in {Ms}ms",
ctx.Request.Method,
ctx.Request.Path,
ctx.Response.StatusCode,
sw.ElapsedMilliseconds);
}
}Middleware condizionale con UseWhen
UseWhen crea una diramazione condizionale della pipeline in base a un predicato, senza dividerla in modo permanente. Al termine, la diramazione si ricongiunge alla pipeline principale.
// Apply authentication middleware only to /api/* routes
app.UseWhen(
ctx => ctx.Request.Path.StartsWithSegments("/api"),
apiApp =>
{
apiApp.UseAuthentication();
apiApp.UseAuthorization();
});
// Public routes (/public/*) bypass authentication
app.MapGet("/public/health", () => "OK");
app.MapGet("/api/data", [Authorize] async (DataService s) => await s.GetAsync());Middleware per il caching delle risposte
Il middleware integrato per il caching delle risposte memorizza in memoria le risposte complete. Configuri i criteri di caching per ogni endpoint tramite intestazioni o attributi.
builder.Services.AddResponseCaching();
app.UseResponseCaching();
app.MapGet("/products", async (AppDbContext db) =>
{
var products = await db.Products.AsNoTracking().ToListAsync();
return Results.Ok(products);
})
.CacheOutput(p => p.Expire(TimeSpan.FromMinutes(2)).Tag("products"));Caso reale: middleware per la modalità di manutenzione
Un middleware per la modalità di manutenzione legge un flag dalla configurazione, supportando il ricaricamento a caldo tramite IOptionsMonitor, e rifiuta le richieste diverse dai controlli di integrità durante la manutenzione.
public class MaintenanceMiddleware
{
private readonly RequestDelegate _next;
private readonly IOptionsMonitor<MaintenanceOptions> _options;
public MaintenanceMiddleware(RequestDelegate next,
IOptionsMonitor<MaintenanceOptions> opts)
{ _next = next; _options = opts; }
public async Task InvokeAsync(HttpContext ctx)
{
if (_options.CurrentValue.IsEnabled
&& !ctx.Request.Path.StartsWithSegments("/health"))
{
ctx.Response.StatusCode = 503;
ctx.Response.Headers.Append("Retry-After", "300");
await ctx.Response.WriteAsJsonAsync(
new { message = "Service under maintenance" });
return;
}
await _next(ctx);
}
}Verifica rapida
Perché dovrebbe implementare IMiddleware invece dell'approccio basato sulle convenzioni quando necessita di un servizio Scoped, come DbContext?
Riepilogo: scrivere middleware personalizzati
Punti chiave:
- Inline, con un delegato Use: rapido, adatto a una riga; basato su classi: riutilizzabile e verificabile
- Classe convenzionale: il costruttore riceve RequestDelegate; InvokeAsync(HttpContext)
- IMiddleware: risoluzione DI per richiesta, necessaria per le dipendenze Scoped
- UseWhen: diramazione condizionale che si ricongiunge alla pipeline principale
- Scriva per primo il middleware di gestione delle eccezioni, nella posizione più esterna, per intercettare tutti gli errori
- Crei metodi di estensione (UseXxx) per una registrazione chiara e facilmente individuabile
Impara C# con un tutor IA — gratis
Scrivi ed esegui vero codice nel tuo browser, ricevi aiuto istantaneo da un tutor IA disponibile 24/7, e riprendi da dove hai lasciato sul web o nell'app.
- Corsi
- 93
- Lezioni
- 346
Domande Frequenti
La lezione «Scrittura di middleware personalizzati» è gratuita?
Sì — il testo completo di «Scrittura di middleware personalizzati» è gratuito qui sul web. Per esercitarvi in modo interattivo (un editor di codice integrato e un tutor IA 24/7) e sbloccare il resto del corso C# Academy, passa a CoddyKit PRO. Il corso C# Academy include 4 lezioni in totale.
Cosa imparerò in «Scrittura di middleware personalizzati»?
Crei middleware inline con Use/Run/Map e middleware basati su classi con InvokeAsync per ottenere componenti riutilizzabili. Eserciti C# Academy con codice pratico che esegui direttamente nel browser, e un tutor IA 24/7 risponde alle tue domande mentre lavori sulla lezione.
Ho bisogno di esperienza per iniziare C# Academy?
Non è richiesta alcuna esperienza precedente. C# Academy su CoddyKit è strutturato per principianti e studenti avanzati, quindi puoi iniziare da qui o dall'inizio e procedere al tuo ritmo. Questa è la lezione 2 di 4.
Quanto tempo richiede la lezione «Scrittura di middleware personalizzati»?
La maggior parte delle lezioni CoddyKit richiede circa 5–10 minuti. Ogni lezione è breve e interattiva, quindi fai progressi costanti e riprendi esattamente da dove hai lasciato su web e app.
Posso scrivere ed eseguire codice in questa lezione C# Academy?
Sì. Ogni lezione C# Academy include un editor di codice integrato, quindi scrivi ed esegui codice reale direttamente nel tuo browser e ricevi feedback istantaneo dall'IA — nessuna configurazione locale necessaria.
Tutte le lezioni di questo corso
- Panoramica della pipeline di ASP.NET Core
- Scrittura di middleware personalizzati
- Interruzione anticipata e ramificazione
- Ordine dei middleware e middleware integrati