Comprendere il middleware
Lo scopo di un'applicazione Web è ricevere e rispondere alle richieste HTTP. Viene ricevuta una richiesta e quindi il server genera la risposta appropriata. Tutto ciò che si trova in ASP.NET Core riguarda questo ciclo di richiesta/risposta.
Quando un'app ASP.NET Core riceve una richiesta HTTP, passa attraverso una serie di componenti per generare la risposta. Questi componenti vengono definiti middleware. Il middleware può essere considerato come una pipeline attraverso cui scorre la richiesta e ogni livello di middleware può eseguire codice prima e dopo il livello successivo della pipeline.
Middleware e delegati
Il middleware viene implementato come delegato che accetta un oggetto HttpContext e restituisce un Task. L'oggetto HttpContext rappresenta la richiesta e la risposta correnti. Il delegato è una funzione che elabora la richiesta e la risposta.
Si consideri il codice di esempio seguente:
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
app.Run(async context =>
{
await context.Response.WriteAsync("Hello world!");
});
app.Run();
Nel codice precedente:
WebApplication.CreateBuilder(args)crea un nuovo oggettoWebApplicationBuilder.builder.Build()crea un nuovo oggettoWebApplication.- Il primo
app.Run()definisce un delegato che accetta un oggettoTaske restituisce unHttpContext. Il delegato scrive "Hello world!" nella risposta. - Il secondo
app.Run()avvia l'app.
Quando l'app riceve una richiesta HTTP, viene chiamato il delegato. Il delegato scrive "Hello world!" nella risposta e completa la richiesta.
Middleware di concatenamento
Nella maggior parte delle app sono presenti più componenti middleware eseguiti in sequenza. L'ordine in cui si aggiungono componenti middleware alla pipeline è importante. I componenti vengono eseguiti nell'ordine in cui sono stati aggiunti.
Middleware terminale e non terminale
Ogni middleware può essere considerato come terminale o non terminale. Il middleware non terminale elabora la richiesta e quindi chiama il middleware successivo nella pipeline. Il middleware del terminale è l'ultimo middleware nella pipeline e non ha un middleware successivo da chiamare.
I delegati aggiunti con app.Use() possono essere middleware terminale o non terminale. Questi delegati prevedono un oggetto HttpContext e un oggetto RequestDelegate come parametri. In genere il delegato include await next.Invoke();. Questo passa il controllo al middleware successivo nella pipeline. ll codice prima di questa riga viene eseguito prima del middleware successivo e il codice dopo questa riga viene eseguito dopo il middleware successivo. Un delegato aggiunto con app.Use() ottiene due opportunità per agire su una richiesta prima che la risposta venga inviata al client; una volta prima che la risposta venga generata dal middleware del terminale e di nuovo dopo che la risposta viene generata dal middleware del terminale.
I delegati aggiunti con app.Run() sono sempre middleware del terminale. Non chiamano il middleware successivo nella pipeline. Sono l'ultimo componente middleware eseguito. Si aspettano solo un oggetto HttpContext come parametro. app.Run() è un collegamento per l'aggiunta del middleware del terminale.
Si consideri l'esempio seguente:
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
app.Use(async (context, next) =>
{
await context.Response.WriteAsync("Hello from middleware 1. Passing to the next middleware!\r\n");
// Call the next middleware in the pipeline
await next.Invoke();
await context.Response.WriteAsync("Hello from middleware 1 again!\r\n");
});
app.Run(async context =>
{
await context.Response.WriteAsync("Hello from middleware 2!\r\n");
});
app.Run();
Nel codice precedente:
app.Use()definisce un componente middleware che:- scrive "Hello from middleware 1. passando al middleware successivo!" alla risposta.
- Passa la richiesta al componente middleware successivo nella pipeline e attende che venga completato con
await next.Invoke(). - Quando il componente successivo nella pipeline è stato completato, scrive "Hello from middleware 1 again!"
- Il primo
app.Run()definisce un componente middleware che scrive "Hello from middleware 2!" nella risposta. - Il secondo
app.Run()avvia l'app.
In fase di esecuzione, quando un Web browser invia una richiesta a questa app, i componenti middleware vengono eseguiti nell'ordine in cui sono stati aggiunti alla pipeline. L'app restituisce la risposta seguente:
Hello from middleware 1. Passing to the next middleware!
Hello from middleware 2!
Hello from middleware 1 again!
Middleware incorporato
ASP.NET Core fornisce un set di componenti middleware predefiniti che possono essere usati per aggiungere funzionalità comuni all'app. Oltre ai componenti middleware aggiunti in modo esplicito, alcuni middleware vengono aggiunti in modo implicito per impostazione predefinita. Ad esempio, WebApplication.CreateBuilder() restituisce un WebApplicationBuilder che aggiunge il middleware di routing della pagina delle eccezioni per gli sviluppatori, aggiunge in modo condizionale il middleware di autenticazione e autorizzazione se i servizi correlati sono configurati e aggiunge il middleware di routing degli endpoint.
Si consideri ad esempio il file di Program.cs seguente:
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddRazorComponents()
.AddInteractiveServerComponents();
var app = builder.Build();
// Configure the HTTP request pipeline.
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error", createScopeForErrors: true);
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseAntiforgery();
app.MapStaticAssets();
app.MapRazorComponents<App>()
.AddInteractiveServerRenderMode();
app.Run();
Nel codice precedente:
app.UseExceptionHandler()aggiunge un componente middleware che intercetta le eccezioni e restituisce una pagina di errore.app.UseHsts()aggiunge un componente middleware che imposta l'intestazione Strict-Transport-Security.app.UseHttpsRedirection()aggiunge un componente middleware che reindirizza le richieste HTTP a HTTPS.app.UseAntiforgery()aggiunge un componente middleware che impedisce attacchi di richiesta intersito falsa (CSRF).app.MapStaticAssets()eapp.MapRazorComponents<App>()eseguono il mapping delle route agli endpoint, che vengono quindi gestiti dal middleware di routing degli endpoint. Il middleware di routing degli endpoint viene aggiunto in modo implicito dalWebApplicationBuilder.
Esistono molti altri componenti middleware predefiniti che si possono usare nell'app a seconda del tipo di app e delle esigenze personali. Controllare la documentazione per l'elenco completo.
Suggerimento
In questo contesto, i metodi che iniziano con Use sono in genere per il middleware di mapping. I metodi che iniziano con Map sono in genere per gli endpoint di mapping.
Importante
I componenti middleware dell'ordine vengono aggiunti alla pipeline. Alcuni componenti middleware devono essere eseguiti prima di altri per funzionare correttamente. Controllare la documentazione relativa a ogni componente middleware per determinare l'ordine corretto.
