Schreiben von benutzerdefinierter ASP.NET Core-Middleware
Hinweis
Dies ist nicht die neueste Version dieses Artikels. Die aktuelle Version finden Sie in der .NET 9-Version dieses Artikels.
Warnung
Diese Version von ASP.NET Core wird nicht mehr unterstützt. Weitere Informationen finden Sie in der Supportrichtlinie für .NET und .NET Core. Informationen zum aktuellen Release finden Sie in der .NET 8-Version dieses Artikels.
Wichtig
Diese Informationen beziehen sich auf ein Vorabversionsprodukt, das vor der kommerziellen Freigabe möglicherweise noch wesentlichen Änderungen unterliegt. Microsoft gibt keine Garantie, weder ausdrücklich noch impliziert, hinsichtlich der hier bereitgestellten Informationen.
Die aktuelle Version finden Sie in der .NET 9-Version dieses Artikels.
Von Fiyaz Hasan, Rick Anderson und Steve Smith
Middleware ist Software, die zu einer Anwendungspipeline zusammengesetzt wird, um Anforderungen und Antworten zu verarbeiten. ASP.NET Core stellt in umfangreichem Maß integrierte Middlewarekomponenten zur Verfügung. In manchen Szenarios möchten Sie aber vielleicht selbst eine benutzerdefinierte Middleware schreiben.
In diesem Thema wird beschrieben, wie Sie auf Konventionen basierende Middleware schreiben. Informationen zu einem Ansatz, der eine starke Typisierung und eine anforderungsbasierte Aktivierung verwendet, finden Sie unter Factorybezogene Middlewareaktivierung in ASP.NET Core.
Middlewareklasse
Für gewöhnlich ist Middleware in einer Klasse gekapselt und wird mit einer Erweiterungsmethode verfügbar gemacht. Betrachten Sie die folgende Inline-Middleware, die die Kultur für die aktuelle Anforderung anhand einer Abfragezeichenfolge festlegt:
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();
Die oben hervorgehobene Inline-Middleware wird verwendet, um das Erstellen einer Middlewarekomponente durch einen Aufruf von Microsoft.AspNetCore.Builder.UseExtensions.Use zu veranschaulichen. Die vorangehende Use
-Erweiterungsmethode fügt der Anforderungspipeline der Anwendung einen inline definierten Middleware-Delegaten hinzu.
Für die Use
-Erweiterung sind zwei Überladungen verfügbar:
- Eine der Überladungen verwendet einen HttpContext und einen
Func<Task>
. Rufen SieFunc<Task>
ohne Parameter auf. - Die andere Überladung verwendet einen
HttpContext
und einen RequestDelegate. Rufen Sie denRequestDelegate
auf, indem Sie denHttpContext
übergeben.
Bevorzugen Sie die letztgenannte Überladung, da sie zwei interne Zuweisungen pro Anforderung einspart, die bei Verwendung der anderen Überladung benötigt werden.
Testen Sie die Middleware, indem Sie die Kultur übergeben. Fordern Sie beispielsweise https://localhost:5001/?culture=es-es
an.
Lesen Sie den Artikel Globalisierung und Lokalisierung in ASP.NET Core, um mehr über die integrierte Lokalisierungsunterstützung von ASP.NET Core zu erfahren.
Im folgenden Code wird der Middlewaredelegat in eine Klasse verschoben:
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);
}
}
Die Middlewareklasse muss Folgendes enthalten:
- Einen öffentlichen Konstruktor mit einem Parameter des Typs RequestDelegate.
- Eine öffentliche Methode mit dem Namen
Invoke
oderInvokeAsync
. Diese Methode muss Folgendes:- Eine
Task
zurückgeben. - Einen ersten Parameter des Typs HttpContext akzeptieren.
- Eine
Zusätzliche Parameter für den Konstruktor und Invoke
/InvokeAsync
werden mittels Abhängigkeitsinjektion aufgefüllt.
In der Regel wird eine Erweiterungsmethode erstellt, um die Middleware über IApplicationBuilder verfügbar zu machen:
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>();
}
}
Der folgende Code ruft die Methode von Program.cs
auf:
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();
Middlewareabhängigkeiten
Middleware sollte das Prinzip der expliziten Abhängigkeiten befolgen, indem sie ihre Abhängigkeiten in ihrem Konstruktor verfügbar macht. Middleware wird einmal während der Anwendungslebensdauer erstellt.
Middlewarekomponenten können Ihre Abhängigkeiten über Dependency Injection (DI) mit Konstruktorparametern auflösen. UseMiddleware kann auch direkt zusätzliche Parameter annehmen.
Voranforderungsbasierte Middlewareabhängigkeiten
Middleware wird beim Start der App erstellt und ist daher für die Lebensdauer der Anwendung gültig. Bereichsbezogene Lebensdauerdienste von Middlewarekonstruktoren in den einzelnen Anforderungen werden nicht gemeinsam mit anderen Typen mit Abhängigkeitsinjektion verwendet. Um einen bereichsbezogenen Dienst sowohl in Middleware als auch in anderen Typen zu verwenden, fügen Sie diese Dienste zur Signatur der InvokeAsync
-Methode hinzu. Die InvokeAsync
-Methode kann zusätzliche Parameter akzeptieren, die durch DI aufgefüllt werden:
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>();
}
}
Die Lebensdauer und Registrierungsoptionen enthalten ein vollständiges Beispiel der Middleware mit Diensten mit bereichsbezogener Lebensdauer.
Der folgende Code wird verwendet, um die vorherige Middleware zu testen:
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();
IMessageWriter
-Schnittstelle und Implementierung:
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);
}
Zusätzliche Ressourcen
- In diesem Artikel verwendeter Beispielcode
- UseExtensions-Quelle auf GitHub
- Die Lebensdauer und Registrierungsoptionen enthalten ein vollständiges Beispiel der Middleware mit Diensten mit bereichsbezogener und vorübergehender Lebensdauer sowie Singletonlebensdauer.
- DEEP DIVE: HOW IS THE ASP.NET CORE MIDDLEWARE PIPELINE BUILT
- ASP.NET Core-Middleware
- Testen von ASP.NET Core-Middleware
- Migrieren von HTTP-Handlern und -Modulen zu ASP.NET Core-Middleware
- Anwendungsstart in ASP.NET Core
- Anforderungsfeatures in ASP.NET Core
- Factorybezogene Middlewareaktivierung in ASP.NET Core
- Middlewareaktivierung mit einem Drittanbietercontainer in ASP.NET Core
Von Rick Anderson und Steve Smith
Middleware ist Software, die zu einer Anwendungspipeline zusammengesetzt wird, um Anforderungen und Antworten zu verarbeiten. ASP.NET Core stellt in umfangreichem Maß integrierte Middlewarekomponenten zur Verfügung. In manchen Szenarios möchten Sie aber vielleicht selbst eine benutzerdefinierte Middleware schreiben.
Hinweis
In diesem Thema wird beschrieben, wie Sie auf Konventionen basierende Middleware schreiben. Informationen zu einem Ansatz, der eine starke Typisierung und eine anforderungsbasierte Aktivierung verwendet, finden Sie unter Factorybezogene Middlewareaktivierung in ASP.NET Core.
Middlewareklasse
Für gewöhnlich ist Middleware in einer Klasse gekapselt und wird mit einer Erweiterungsmethode verfügbar gemacht. Sehen Sie sich folgende Middleware an, die die Kultur der aktuellen Anforderung über eine Abfragezeichenfolge festlegt:
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}");
});
}
}
Im vorhergehenden Beispielcode wird die Erstellung einer Middlewarekomponente veranschaulicht. Lesen Sie den Artikel Globalisierung und Lokalisierung in ASP.NET Core, um mehr über die integrierte Lokalisierungsunterstützung von ASP.NET Core zu erfahren.
Testen Sie die Middleware, indem Sie die Kultur übergeben. Fordern Sie beispielsweise https://localhost:5001/?culture=no
an.
Im folgenden Code wird der Middlewaredelegat in eine Klasse verschoben:
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);
}
}
}
Die Middlewareklasse muss Folgendes enthalten:
- Einen öffentlichen Konstruktor mit einem Parameter des Typs RequestDelegate.
- Eine öffentliche Methode mit dem Namen
Invoke
oderInvokeAsync
. Diese Methode muss Folgendes:- Eine
Task
zurückgeben. - Einen ersten Parameter des Typs HttpContext akzeptieren.
- Eine
Zusätzliche Parameter für den Konstruktor und Invoke
/InvokeAsync
werden mittels Abhängigkeitsinjektion aufgefüllt.
Middlewareabhängigkeiten
Middleware sollte das Prinzip der expliziten Abhängigkeiten befolgen, indem sie ihre Abhängigkeiten in ihrem Konstruktor verfügbar macht. Middleware wird einmal während der Anwendungslebensdauer erstellt. Lesen Sie den Abschnitt Voranforderungsbasierte Middlewareabhängigkeiten, wenn Sie Dienste für Middleware innerhalb einer Anforderung gemeinsam verwenden müssen.
Middlewarekomponenten können Ihre Abhängigkeiten über Dependency Injection (DI) mit Konstruktorparametern auflösen. UseMiddleware kann auch direkt zusätzliche Parameter annehmen.
Voranforderungsbasierte Middlewareabhängigkeiten
Weil Middleware zum Zeitpunkt des Anwendungsstarts erstellt wird (und nicht voranforderungsbasiert), werden bereichsbezogene Lebensdauerdienste von Middlewarekonstruktoren in den einzelnen Anforderungen nicht gemeinsam mit anderen Typen mit Dependency Injection verwendet. Wenn Sie einen bereichsbezogenen Dienst sowohl in Ihrer Middleware als auch in anderen Typen verwenden müssen, fügen Sie diese Dienste zur Signatur der InvokeAsync
-Methode hinzu. Die InvokeAsync
-Methode kann zusätzliche Parameter akzeptieren, die durch DI aufgefüllt werden:
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);
}
}
Die Lebensdauer und Registrierungsoptionen enthalten ein vollständiges Beispiel der Middleware mit Diensten mit bereichsbezogener Lebensdauer.
Erweiterungsmethode für die Middleware
Die folgende Erweiterungsmethode stellt die Middleware über IApplicationBuilder zur Verfügung:
using Microsoft.AspNetCore.Builder;
namespace Culture
{
public static class RequestCultureMiddlewareExtensions
{
public static IApplicationBuilder UseRequestCulture(
this IApplicationBuilder builder)
{
return builder.UseMiddleware<RequestCultureMiddleware>();
}
}
}
Der folgende Code ruft die Methode von Startup.Configure
auf:
public class Startup
{
public void Configure(IApplicationBuilder app)
{
app.UseRequestCulture();
app.Run(async (context) =>
{
await context.Response.WriteAsync(
$"Hello {CultureInfo.CurrentCulture.DisplayName}");
});
}
}
Zusätzliche Ressourcen
- Die Lebensdauer und Registrierungsoptionen enthalten ein vollständiges Beispiel der Middleware mit Diensten mit bereichsbezogener und vorübergehender Lebensdauer sowie Singletonlebensdauer.
- ASP.NET Core-Middleware
- Testen von ASP.NET Core-Middleware
- Migrieren von HTTP-Handlern und -Modulen zu ASP.NET Core-Middleware
- Anwendungsstart in ASP.NET Core
- Anforderungsfeatures in ASP.NET Core
- Factorybezogene Middlewareaktivierung in ASP.NET Core
- Middlewareaktivierung mit einem Drittanbietercontainer in ASP.NET Core