Scrivere middleware di ASP.NET Core personalizzato
Nota
Questa non è la versione più recente di questo articolo. Per la versione corrente, vedere la versione .NET 9 di questo articolo.
Avviso
Questa versione di ASP.NET Core non è più supportata. Per altre informazioni, vedere Criteri di supporto di .NET e .NET Core. Per la versione corrente, vedere la versione .NET 8 di questo articolo.
Importante
Queste informazioni si riferiscono a un prodotto non definitive che può essere modificato in modo sostanziale prima che venga rilasciato commercialmente. Microsoft non riconosce alcuna garanzia, espressa o implicita, in merito alle informazioni qui fornite.
Per la versione corrente, vedere la versione .NET 9 di questo articolo.
Di Fiyaz Hasan, Rick Anderson e Steve Smith
Il middleware è un software che viene assemblato in una pipeline dell'app per gestire richieste e risposte. ASP.NET Core offre un ampio set di componenti middleware integrati, ma in alcuni scenari si potrebbe voler scrivere un middleware personalizzato.
In questo argomento viene descritto come scrivere middleware basato su convenzioni. Per un approccio che usa la digitazione avanzata e l'attivazione per richiesta, vedere Attivazione middleware basata su factory in ASP.NET Core.
Classe middleware
Il middleware è in genere incapsulato in una classe ed esposto con un metodo di estensione. Si consideri il middleware inline seguente, che imposta le impostazioni cultura per la richiesta corrente da una stringa di query:
using System.Globalization;
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
app.UseHttpsRedirection();
app.Use(async (context, next) =>
{
var cultureQuery = context.Request.Query["culture"];
if (!string.IsNullOrWhiteSpace(cultureQuery))
{
var culture = new CultureInfo(cultureQuery);
CultureInfo.CurrentCulture = culture;
CultureInfo.CurrentUICulture = culture;
}
// Call the next delegate/middleware in the pipeline.
await next(context);
});
app.Run(async (context) =>
{
await context.Response.WriteAsync(
$"CurrentCulture.DisplayName: {CultureInfo.CurrentCulture.DisplayName}");
});
app.Run();
Il middleware inline evidenziato precedente viene usato per illustrare la creazione di un componente middleware chiamando Microsoft.AspNetCore.Builder.UseExtensions.Use. Il metodo di estensione precedente Use
aggiunge un delegato middleware definito inline alla pipeline di richiesta dell'applicazione.
Sono disponibili due overload per l'estensione Use
:
- Uno accetta un HttpContext e un .
Func<Task>
Func<Task>
Richiamare senza parametri. - L'altro accetta un
HttpContext
oggetto e un oggetto RequestDelegate. Richiamare l'oggettoRequestDelegate
passando l'oggettoHttpContext
.
Preferire l'uso dell'overload successivo perché salva due allocazioni interne per richiesta necessarie quando si usa l'altro overload.
Testare il middleware passando le impostazioni cultura. Ad esempio, richiedere https://localhost:5001/?culture=es-es
.
Per il supporto di localizzazione predefinito di ASP.NET Core, vedere Globalizzazione e localizzazione in ASP.NET Core.
Il codice seguente sposta il delegato middleware in una classe:
using System.Globalization;
namespace Middleware.Example;
public class RequestCultureMiddleware
{
private readonly RequestDelegate _next;
public RequestCultureMiddleware(RequestDelegate next)
{
_next = next;
}
public async Task InvokeAsync(HttpContext context)
{
var cultureQuery = context.Request.Query["culture"];
if (!string.IsNullOrWhiteSpace(cultureQuery))
{
var culture = new CultureInfo(cultureQuery);
CultureInfo.CurrentCulture = culture;
CultureInfo.CurrentUICulture = culture;
}
// Call the next delegate/middleware in the pipeline.
await _next(context);
}
}
La classe middleware deve includere:
- Un costruttore pubblico con un parametro di tipo RequestDelegate.
- Un metodo pubblico denominato
Invoke
oInvokeAsync
. Questo metodo deve:- Restituire
Task
. - Accettare un primo parametro di tipo HttpContext.
- Restituire
I parametri aggiuntivi per il costruttore e Invoke
/InvokeAsync
vengono popolati dall'inserimento delle dipendenze.
In genere, viene creato un metodo di estensione per esporre il middleware tramite IApplicationBuilder:
using System.Globalization;
namespace Middleware.Example;
public class RequestCultureMiddleware
{
private readonly RequestDelegate _next;
public RequestCultureMiddleware(RequestDelegate next)
{
_next = next;
}
public async Task InvokeAsync(HttpContext context)
{
var cultureQuery = context.Request.Query["culture"];
if (!string.IsNullOrWhiteSpace(cultureQuery))
{
var culture = new CultureInfo(cultureQuery);
CultureInfo.CurrentCulture = culture;
CultureInfo.CurrentUICulture = culture;
}
// Call the next delegate/middleware in the pipeline.
await _next(context);
}
}
public static class RequestCultureMiddlewareExtensions
{
public static IApplicationBuilder UseRequestCulture(
this IApplicationBuilder builder)
{
return builder.UseMiddleware<RequestCultureMiddleware>();
}
}
Il codice seguente chiama il middleware da Program.cs
:
using Middleware.Example;
using System.Globalization;
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
app.UseHttpsRedirection();
app.UseRequestCulture();
app.Run(async (context) =>
{
await context.Response.WriteAsync(
$"CurrentCulture.DisplayName: {CultureInfo.CurrentCulture.DisplayName}");
});
app.Run();
Dipendenze del middleware
Il middleware deve seguire il principio delle dipendenze esplicite esponendo le dipendenze nel costruttore. Il middleware viene costruito una volta per ogni durata applicazione.
I componenti middleware possono risolvere le dipendenze dall'inserimento di dipendenze mediante i parametri del costruttore. UseMiddleware può anche accettare direttamente parametri aggiuntivi.
Dipendenze del middleware per richiesta
Il middleware viene costruito all'avvio dell'app e pertanto ha un tempo di vita dell'applicazione. I servizi di durata con ambito usati dai costruttori middleware non vengono condivisi con altri tipi inseriti da dipendenze durante ogni richiesta. Per condividere un servizio con ambito tra middleware e altri tipi, aggiungere questi servizi alla InvokeAsync
firma del metodo. Il metodo InvokeAsync
può accettare parametri aggiuntivi popolati dall'inserimento delle dipendenze:
namespace Middleware.Example;
public class MyCustomMiddleware
{
private readonly RequestDelegate _next;
public MyCustomMiddleware(RequestDelegate next)
{
_next = next;
}
// IMessageWriter is injected into InvokeAsync
public async Task InvokeAsync(HttpContext httpContext, IMessageWriter svc)
{
svc.Write(DateTime.Now.Ticks.ToString());
await _next(httpContext);
}
}
public static class MyCustomMiddlewareExtensions
{
public static IApplicationBuilder UseMyCustomMiddleware(
this IApplicationBuilder builder)
{
return builder.UseMiddleware<MyCustomMiddleware>();
}
}
Le opzioni di durata e registrazione contengono un campione completo di middleware con servizi di durata con ambito.
Il codice seguente viene usato per testare il middleware precedente:
using Middleware.Example;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddScoped<IMessageWriter, LoggingMessageWriter>();
var app = builder.Build();
app.UseHttpsRedirection();
app.UseMyCustomMiddleware();
app.MapGet("/", () => "Hello World!");
app.Run();
Interfaccia IMessageWriter
e implementazione:
namespace Middleware.Example;
public interface IMessageWriter
{
void Write(string message);
}
public class LoggingMessageWriter : IMessageWriter
{
private readonly ILogger<LoggingMessageWriter> _logger;
public LoggingMessageWriter(ILogger<LoggingMessageWriter> logger) =>
_logger = logger;
public void Write(string message) =>
_logger.LogInformation(message);
}
Risorse aggiuntive
- Codice di esempio usato in questo articolo
- Origine UseExtensions in GitHub
- Le opzioni di durata e registrazione contengono un esempio completo di middleware con servizi di durata con ambito, temporanei e singleton.
- APPROFONDIMENTO: HOW IS THE ASP.NET CORE MIDDLEWARE PIPELINE BUILT (APPROFONDIMENTO: HOW IS THE ASP.NET CORE MIDDLEWARE PIPELINE BUILT
- Middleware di ASP.NET Core
- Testare middleware di ASP.NET Core
- Eseguire la migrazione di gestori e moduli HTTP a middleware di ASP.NET Core
- Avvio dell'app in ASP.NET Core
- Funzionalità di richiesta in ASP.NET Core
- Attivazione middleware basata su factory in ASP.NET Core
- Attivazione del middleware con un contenitore di terze parti in ASP.NET Core
Il middleware è un software che viene assemblato in una pipeline dell'app per gestire richieste e risposte. ASP.NET Core offre un ampio set di componenti middleware integrati, ma in alcuni scenari si potrebbe voler scrivere un middleware personalizzato.
Nota
In questo argomento viene descritto come scrivere middleware basato su convenzioni. Per un approccio che usa la digitazione avanzata e l'attivazione per richiesta, vedere Attivazione middleware basata su factory in ASP.NET Core.
Classe middleware
Il middleware è in genere incapsulato in una classe ed esposto con un metodo di estensione. Si consideri il middleware seguente, che specifica le impostazioni cultura per la richiesta corrente da una stringa di query:
public class Startup
{
public void Configure(IApplicationBuilder app)
{
app.Use(async (context, next) =>
{
var cultureQuery = context.Request.Query["culture"];
if (!string.IsNullOrWhiteSpace(cultureQuery))
{
var culture = new CultureInfo(cultureQuery);
CultureInfo.CurrentCulture = culture;
CultureInfo.CurrentUICulture = culture;
}
// Call the next delegate/middleware in the pipeline
await next();
});
app.Run(async (context) =>
{
await context.Response.WriteAsync(
$"Hello {CultureInfo.CurrentCulture.DisplayName}");
});
}
}
Il codice di esempio precedente viene usato per illustrare la creazione di un componente middleware. Per il supporto di localizzazione predefinito di ASP.NET Core, vedere Globalizzazione e localizzazione in ASP.NET Core.
Testare il middleware passando le impostazioni cultura. Ad esempio, richiedere https://localhost:5001/?culture=no
.
Il codice seguente sposta il delegato middleware in una classe:
using Microsoft.AspNetCore.Http;
using System.Globalization;
using System.Threading.Tasks;
namespace Culture
{
public class RequestCultureMiddleware
{
private readonly RequestDelegate _next;
public RequestCultureMiddleware(RequestDelegate next)
{
_next = next;
}
public async Task InvokeAsync(HttpContext context)
{
var cultureQuery = context.Request.Query["culture"];
if (!string.IsNullOrWhiteSpace(cultureQuery))
{
var culture = new CultureInfo(cultureQuery);
CultureInfo.CurrentCulture = culture;
CultureInfo.CurrentUICulture = culture;
}
// Call the next delegate/middleware in the pipeline
await _next(context);
}
}
}
La classe middleware deve includere:
- Un costruttore pubblico con un parametro di tipo RequestDelegate.
- Un metodo pubblico denominato
Invoke
oInvokeAsync
. Questo metodo deve:- Restituire
Task
. - Accettare un primo parametro di tipo HttpContext.
- Restituire
I parametri aggiuntivi per il costruttore e Invoke
/InvokeAsync
vengono popolati dall'inserimento delle dipendenze.
Dipendenze del middleware
Il middleware deve seguire il principio delle dipendenze esplicite esponendo le dipendenze nel costruttore. Il middleware viene costruito una volta per ogni durata applicazione. Se è necessario condividere servizi con il middleware all'interno di una richiesta, vedere la sezione Dipendenze del middleware per richiesta.
I componenti middleware possono risolvere le dipendenze dall'inserimento di dipendenze mediante i parametri del costruttore. UseMiddleware può anche accettare direttamente parametri aggiuntivi.
Dipendenze del middleware per richiesta
Poiché il middleware viene creato all'avvio dell'app e non per richiesta, i servizi di durata con ambito usati dai costruttori del middleware non vengono condivisi con altri tipi di inserimento di dipendenze durante ogni richiesta. Se è necessario condividere un servizio con ambito tra il proprio middleware e altri tipi, aggiungere i servizi alla firma del metodo InvokeAsync
. Il metodo InvokeAsync
può accettare parametri aggiuntivi popolati dall'inserimento delle dipendenze:
public class CustomMiddleware
{
private readonly RequestDelegate _next;
public CustomMiddleware(RequestDelegate next)
{
_next = next;
}
// IMyScopedService is injected into InvokeAsync
public async Task InvokeAsync(HttpContext httpContext, IMyScopedService svc)
{
svc.MyProperty = 1000;
await _next(httpContext);
}
}
Le opzioni di durata e registrazione contengono un campione completo di middleware con servizi di durata con ambito.
Metodo di estensione del middleware
Il metodo di estensione seguente espone il middleware tramite IApplicationBuilder:
using Microsoft.AspNetCore.Builder;
namespace Culture
{
public static class RequestCultureMiddlewareExtensions
{
public static IApplicationBuilder UseRequestCulture(
this IApplicationBuilder builder)
{
return builder.UseMiddleware<RequestCultureMiddleware>();
}
}
}
Il codice seguente chiama il middleware da Startup.Configure
:
public class Startup
{
public void Configure(IApplicationBuilder app)
{
app.UseRequestCulture();
app.Run(async (context) =>
{
await context.Response.WriteAsync(
$"Hello {CultureInfo.CurrentCulture.DisplayName}");
});
}
}
Risorse aggiuntive
- Le opzioni di durata e registrazione contengono un esempio completo di middleware con servizi di durata con ambito, temporanei e singleton.
- Middleware di ASP.NET Core
- Testare middleware di ASP.NET Core
- Eseguire la migrazione di gestori e moduli HTTP a middleware di ASP.NET Core
- Avvio dell'app in ASP.NET Core
- Funzionalità di richiesta in ASP.NET Core
- Attivazione middleware basata su factory in ASP.NET Core
- Attivazione del middleware con un contenitore di terze parti in ASP.NET Core