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 .NET- und .NET Core-Supportrichtlinie. Die aktuelle Version finden Sie in der .NET 9-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 Rick Anderson und Steve Smith
Middleware ist Software, die zu einer Anwendungspipeline zusammengesetzt wird, um Anforderungen und Antworten zu verarbeiten. Jede Komponente kann Folgendes ausführen:
- Entscheiden, ob die Anforderung an die nächste Komponente in der Pipeline übergeben werden soll.
- Ausführen von Arbeiten, bevor oder nachdem die nächste Komponente in der Pipeline aufgerufen wird.
Anforderungsdelegaten werden verwendet, um die Anforderungspipeline zu erstellen. Die Anforderungsdelegaten behandeln jede HTTP-Anforderung.
Anforderungsdelegaten werden mit den Erweiterungsmethoden Run, Map und Use konfiguriert. Ein einzelner Anforderungsdelegat kann inline als anonyme Methode angegeben werden (sogenannte Inline-Middleware), oder er kann in einer wiederverwendbaren Klasse definiert werden. Diese wiederverwendbaren Klassen und anonymen Inline-Methoden sind Middleware bzw. Middlewarekomponenten. Jede Middlewarekomponente in der Anforderungspipeline ist für das Aufrufen der jeweils nächsten Komponente in der Pipeline oder, wenn nötig, für das Kurzschließen der Pipeline zuständig. Wenn eine Middleware einen Kurzschluss verursacht, wird diese als Terminalmiddleware bezeichnet, da sie verhindert, dass weitere Middleware die Anforderung verarbeiten kann.
Unter Migrieren von HTTP-Handlern und -Modulen zu ASP.NET Core-Middleware wird der Unterschied zwischen Anforderungspipelines in ASP.NET Core und ASP.NET 4.x erläutert, und es werden zusätzliche Beispiele für Middleware bereitgestellt.
Die Rolle von Middleware nach App-Typ
Blazor Web Apps, Razor Pages und MVC verarbeiten Anfragen von Browsern auf dem Server mit Middleware. Die Anleitungen in diesem Artikel gelten für diese Arten von Apps.
Unabhängige Blazor WebAssembly-Apps werden vollständig auf dem Client ausgeführt und verarbeiten keine Anforderungen mit einer Middleware-Pipeline. Die Anleitung in diesem Artikel gilt nicht für eigenständige Blazor WebAssembly-Apps.
Middleware-Codeanalyse
ASP.NET Core enthält zahlreiche Compilerplattform-Analysetools zum Überprüfen der Qualität des Anwendungscodes. Weitere Informationen finden Sie unter Codeanalyse in ASP.NET Core-Apps.
Erstellen einer Middlewarepipeline mit WebApplication
Die ASP.NET Core-Anforderungspipeline besteht aus einer Sequenz von Anforderungsdelegaten, die nacheinander aufgerufen werden. Das Konzept wird im folgenden Diagramm veranschaulicht. Der Ausführungsthread folgt den schwarzen Pfeilen.
Jeder Delegat kann Vorgänge vor und nach dem nächsten Delegaten ausführen. Die Ausnahmebehandlungsdelegaten müssen am Anfang der Pipeline aufgerufen werden, sodass sie Ausnahmen abfangen können, die zu einem späteren Zeitpunkt in der Pipeline ausgelöst werden.
Die einfachste mögliche ASP.NET Core-App enthält einen einzigen Anforderungsdelegaten, der alle Anforderungen verarbeitet. In diesem Fall ist keine tatsächliche Anforderungspipeline vorhanden. Stattdessen wird eine einzelne anonyme Funktion als Antwort auf jede HTTP-Anforderung aufgerufen.
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
app.Run(async context =>
{
await context.Response.WriteAsync("Hello world!");
});
app.Run();
Mit Use können Sie mehrere Anforderungedelegate miteinander verknüpfen. Der Parameter next
steht für den nächsten Delegaten in der Pipeline. Sie können die Pipeline kurzschließen, indem Sie den Parameter next
aufrufen. Normalerweise können Sie Aktionen sowohl vor als auch nach dem next
-Delegaten durchführen. Dies wird in folgendem Beispiel veranschaulicht:
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
app.Use(async (context, next) =>
{
// Do work that can write to the Response.
await next.Invoke();
// Do logging or other work that doesn't write to the Response.
});
app.Run(async context =>
{
await context.Response.WriteAsync("Hello from 2nd delegate.");
});
app.Run();
Kurzschluss der Anforderungspipeline
Wenn ein keine Anforderung an den nächsten Delegaten übergibt, wird dies als Kurzschluss der Anforderungspipeline bezeichnet. Das Kurzschließen ist oft sinnvoll, da es unnötige Arbeit verhindert. Die Middleware für statische Dateien kann beispielsweise als Terminalmiddleware fungieren, indem sie eine Anforderung für eine statische Datei zurückgibt und den rest der Pipeline kurzschließt. Middleware, die noch vor der Middleware, die die weitere Verarbeitung beendet, zur Pipeline hinzugefügt wird, verarbeitet Code noch nach den next.Invoke
-Anweisungen weiter. Sehen Sie sich allerdings die folgende Warnung zum Versuch an, in eine Antwort zu schreiben, die bereits gesendet wurde.
Warnung
Rufen Sie next.Invoke
nicht auf, während und nachdem die Antwort an den Client gesendet wurde. Nachdem ein HttpResponse gestartet wurde, führen Änderungen zu einer Ausnahme. Wenn Sie beispielsweise Kopfzeilen und einen Statuscode festlegen, wird nach dem Start der Antwort eine Ausnahme ausgelöst. Wenn Sie nach dem Aufruf von next
in den Antworttext schreiben, kann dies:
- Kann zu einer Protokollverletzung führen, z. B. das Schreiben von mehr als der angegebenen
Content-Length
. - Kann das Textkörperformat beschädigt werden, z. B. das Schreiben einer HTML-Fußzeile in eine CSS-Datei.
HasStarted ist ein nützlicher Hinweis, der angibt, ob Header gesendet wurden oder ob in den Text geschrieben wurde.
Weitere Informationen finden Sie unter Kurzschluss der Middleware nach dem Routing.
Run
-Delegaten
Run-Delegaten erhalten keinen next
-Parameter. Der erste Run
-Delegat beendet immer die Pipeline. Run
ist eine Konvention. Einige Middlewarekomponenten machen möglicherweise Run[Middleware]
-Methoden verfügbar, die am Ende einer Pipeline ausgeführt werden:
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
app.Use(async (context, next) =>
{
// Do work that can write to the Response.
await next.Invoke();
// Do logging or other work that doesn't write to the Response.
});
app.Run(async context =>
{
await context.Response.WriteAsync("Hello from 2nd delegate.");
});
app.Run();
Wenn Sie möchten, dass Codekommentare in anderen Sprachen als Englisch angezeigt werden, informieren Sie uns in diesem GitHub-Issue.
Im vorherigen Beispiel schreibt der Run
-Delegat "Hello from 2nd delegate."
zur Antwort und beendet dann die Pipeline. Wenn ein anderer Use
- oder Run
-Delegat nach dem Run
-Delegaten hinzugefügt wird, wird dieser nicht aufgerufen.
App bevorzugen: Verwenden einer Überladung, die die Übergabe des Kontexts erfordert
Die app.Use-Erweiterungsmethode ohne Zuordnung:
- Erfordert die Übergabe des Kontexts an
next
- Speichert zwei interne Zuordnungen pro Anforderung, die bei Verwendung der anderen Überladung erforderlich sind
Weitere Informationen finden Sie in diesem GitHub-Issue.
Middlewarereihenfolge
In der folgenden Abbildung wird die gesamte Anforderungsverarbeitungspipeline für MVC- und Razor Pages-Apps in ASP.NET Core dargestellt. Es ist zu sehen, wie vorhandene Middleware in einer typischen App sortiert ist und an welcher Stelle benutzerdefinierte Middleware hinzugefügt wird. Sie haben vollständige Kontrolle darüber, wie vorhandene Middleware neu angeordnet oder neue benutzerdefinierte Middleware nach Bedarf eingefügt wird.
Der Endpunktmiddleware in der vorangehenden Abbildung führt die Filterpipeline für den entsprechenden App-Typ aus (MVC oder Razor Pages).
Die Routing-Middleware im vorherigen Diagramm ist im Anschluss an statische Dateien dargestellt. Dies ist die Reihenfolge, die die Projektvorlagen implementieren, indem sie explizit app.UseRouting aufrufen. Wenn Sie nicht app.UseRouting
aufrufen, wird die Routing-Middleware standardmäßig am Anfang der Pipeline ausgeführt. Weitere Informationen finden Sie unter Routing.
Die Reihenfolge, in der Middlewarekomponenten in der Program.cs
-Datei hinzugefügt werden, legt die Reihenfolge fest, in der die Middlewarekomponenten bei Anforderungen aufgerufen werden. Bei Antworten gilt die umgekehrte Reihenfolge. Die Reihenfolge ist in Bezug auf Sicherheit, Leistung und Funktionalität entscheidend.
Der folgende hervorgehobene Code in Program.cs
fügt sicherheitsbezogene Middlewarekomponenten in der typischen empfohlenen Reihenfolge hinzu:
using Microsoft.AspNetCore.Identity;
using Microsoft.EntityFrameworkCore;
using WebMiddleware.Data;
var builder = WebApplication.CreateBuilder(args);
var connectionString = builder.Configuration.GetConnectionString("DefaultConnection")
?? throw new InvalidOperationException("Connection string 'DefaultConnection' not found.");
builder.Services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(connectionString));
builder.Services.AddDatabaseDeveloperPageExceptionFilter();
builder.Services.AddDefaultIdentity<IdentityUser>(options => options.SignIn.RequireConfirmedAccount = true)
.AddEntityFrameworkStores<ApplicationDbContext>();
builder.Services.AddRazorPages();
builder.Services.AddControllersWithViews();
var app = builder.Build();
if (app.Environment.IsDevelopment())
{
app.UseMigrationsEndPoint();
}
else
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
// app.UseCookiePolicy();
app.UseRouting();
// app.UseRateLimiter();
// app.UseRequestLocalization();
// app.UseCors();
app.UseAuthentication();
app.UseAuthorization();
// app.UseSession();
// app.UseResponseCompression();
// app.UseResponseCaching();
app.MapRazorPages();
app.MapDefaultControllerRoute();
app.Run();
Für den Code oben gilt:
- Middleware, die beim Erstellen einer neuen Web-App mit einzelnen Benutzerkonten nicht hinzugefügt wird, wird auskommentiert.
- Die exakte Reihenfolge ist nicht für jede Middleware vorgeschrieben (dies ist jedoch meistens der Fall). Beispiel:
UseCors
,UseAuthentication
undUseAuthorization
müssen in der angezeigten Reihenfolge stehen.UseCors
muss derzeit aufgrund vorUseResponseCaching
stehen. Diese Anforderung wird im GitHub-Issue zu dotnet/aspnetcore, Nr. 23218, erläutert.UseRequestLocalization
muss vor jeder Middleware stehen, die u. U. die Anforderungskultur überprüft (z. B.app.UseStaticFiles()
).- UseRateLimiter muss nach
UseRouting
aufgerufen werden, wenn endpunktspezifische APIs für die Ratenbegrenzung verwendet werden. Wenn zum Beispiel das Attribut[EnableRateLimiting]
verwendet wird, mussUseRateLimiter
nachUseRouting
aufgerufen werden. Wenn nur globale Begrenzungen aufgerufen werden,UseRateLimiter
kann vorUseRouting
aufgerufen werden.
In einigen Szenarien weist die Middleware eine andere Reihenfolge auf. Die Reihenfolge für Zwischenspeicherung und Komprimierung beispielsweise ist szenariospezifisch, und es gibt verschiedene gültige Reihenfolgen. Beispiel:
app.UseResponseCaching();
app.UseResponseCompression();
Mit dem obigen Code könnte durch Zwischenspeichern der komprimierten Antwort die CPU-Auslastung verringert werden, dies könnte aber dazu führen, dass mehrere Darstellungen einer Ressource mithilfe verschiedener Komprimierungsalgorithmen wie z. B. Gzip oder Brotli zwischengespeichert werden.
Die folgende Reihenfolge kombiniert statische Dateien, um eine Zwischenspeicherung komprimierter statischer Dateien zuzulassen:
app.UseResponseCaching();
app.UseResponseCompression();
app.UseStaticFiles();
Der folgende Program.cs
-Code fügt Middlewarekomponenten für allgemeine App-Szenarios hinzu:
- Ausnahme-/Fehlerbehandlung
- Bei Ausführung der App in der Entwicklungsumgebung:
- Middleware der Seite mit Ausnahmen für Entwickler (UseDeveloperExceptionPage) meldet App-Laufzeitfehler.
- Middleware der Seite mit Datenbankfehlern (UseDatabaseErrorPage) meldet Datenbanklaufzeitfehler.
- Bei Ausführung der App in der Produktionsumgebung:
- Middleware für Ausnahmehandler (UseExceptionHandler) fängt Ausnahmen ab, die in den folgenden Middlewarekomponenten ausgelöst werden.
- HTTP Strict Transport Security Protocol-Middleware (HSTS) (UseHsts) fügt den
Strict-Transport-Security
-Header hinzu.
- Bei Ausführung der App in der Entwicklungsumgebung:
- Middleware zur HTTPS-Umleitung (UseHttpsRedirection) leitet HTTP-Anforderungen an HTTPS um.
- Middleware für statische Dateien (UseStaticFiles) gibt statische Dateien zurück und umgeht die weitere Anforderungsverarbeitung.
- Middleware für Cookierichtlinien (UseCookiePolicy) sorgt dafür, dass die App die Anforderungen der europäischen Datenschutzgrundverordnung (DSGVO) erfüllt.
- Routingmiddleware (UseRouting) zum Weiterleiten von Anforderungen.
- Middleware für die Authentifizierung (UseAuthentication) versucht, den Benutzer zu authentifizieren, bevor der Zugriff auf sichere Ressourcen zugelassen wird.
- Autorisierungsmiddleware (UseAuthorization) wird zum Autorisieren des Zugriffs auf sichere Ressourcen eines Benutzers verwendet.
- Middleware für Sitzungen (UseSession) richtet einen Sitzungsstatus ein und erhält diesen aufrecht. Wenn die App den Sitzungsstatus verwendet, rufen Sie die Middleware für Sitzungen nach der Middleware für Cookierichtlinien und vor der MVC-Middleware auf.
- Endpunktroutingmiddleware (UseEndpoints mit MapRazorPages) zum Hinzufügen von Razor Pages-Endpunkten zur Anforderungspipeline.
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
app.UseDatabaseErrorPage();
}
else
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseCookiePolicy();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseSession();
app.MapRazorPages();
Im vorhergehenden Beispielcode wird jede Middleware-Erweiterungsmethode in WebApplicationBuilder über den Microsoft.AspNetCore.Builder-Namespace verfügbar gemacht.
UseExceptionHandler ist die erste Middlewarekomponente, die der Pipeline hinzugefügt wird. Aus diesem Grund fängt die Middleware für den Ausnahmehandler alle Ausnahmen ab, die in späteren Aufrufen auftreten.
Die Middleware für statische Dateien wird am Anfang der Pipeline aufgerufen, damit sie Anforderungen und Kurzschlüsse verarbeiten kann, ohne dass die verbleibenden Komponenten durchlaufen werden müssen. Die Middleware für statische Dateien stellt keine Autorisierungsüberprüfungen bereit. Alle Dateien, die von Middleware für statische Dateien unterstützt werden, einschließlich der Dateien unter wwwroot, sind öffentlich verfügbar. Im Artikel zu statischen Dateien in ASP.NET Core erfahren Sie, wie Sie statische Dateien schützen können.
Wenn die Anforderung nicht von der Middleware für statische Dateien verarbeitet wird, wird sie an die Authentifizierungsmiddleware (UseAuthentication) übergeben, welche die Authentifizierung durchführt. Die Authentifizierung schließt nicht authentifizierte Anforderungen nicht kurz. Auch wenn die Authentifizierungsmiddleware Anforderungen authentifiziert, erfolgt die Autorisierung (und Ablehnung) erst dann, wenn MVC eine spezifische Razor Page oder einen MVC-Controller und eine Aktion ausgewählt hat.
Im folgenden Beispiel wird eine Middlewarereihenfolge veranschaulicht, bei der Anforderungen statischer Dateien von der Middleware für statische Dateien vor der Middleware für die Antwortkomprimierung verarbeitet werden. Die statischen Dateien werden bei dieser Middlewarereihenfolge nicht komprimiert. Die Razor Pages-Antworten können komprimiert werden.
// Static files aren't compressed by Static File Middleware.
app.UseStaticFiles();
app.UseRouting();
app.UseResponseCompression();
app.MapRazorPages();
Informationen zu Einzelseitenanwendungen finden Sie unter Übersicht über Single Page Apps (SPAs) in ASP.NET Core.
Reihenfolge von UseCors und UseStaticFiles
Die Reihenfolge der Aufrufe von UseCors
und UseStaticFiles
hängt von der App ab. Weitere Informationen finden Sie unter Reihenfolge von UseCors und UseStaticFiles
Middleware für weitergeleitete Header: Auftrag
Middleware für weitergeleitete Header muss vor anderen Middlewarekomponenten ausgeführt werden. Mit dieser Reihenfolge wird sichergestellt, dass die auf Informationen von weitergeleiteten Headern basierende Middleware die zu verarbeitenden Headerwerte nutzen kann. Unter Middleware für weitergeleitete Header: Auftrag finden Sie Informationen zum Ausführen der Middleware für weitergeleitete Header nach der diagnostischen Middleware und der Middleware für die Fehlerbehandlung.
Branchen der Middlewarepipeline
Map-Erweiterungen werden als Konvention zum Branchen der Pipeline verwendet. Map
brancht die Anforderungspipeline auf Grundlage von Übereinstimmungen des angegebenen Anforderungspfads. Wenn der Anforderungspfad mit dem angegebenen Pfad beginnt, wird der Branch ausgeführt.
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
app.Map("/map1", HandleMapTest1);
app.Map("/map2", HandleMapTest2);
app.Run(async context =>
{
await context.Response.WriteAsync("Hello from non-Map delegate.");
});
app.Run();
static void HandleMapTest1(IApplicationBuilder app)
{
app.Run(async context =>
{
await context.Response.WriteAsync("Map Test 1");
});
}
static void HandleMapTest2(IApplicationBuilder app)
{
app.Run(async context =>
{
await context.Response.WriteAsync("Map Test 2");
});
}
In der folgenden Tabelle sind die Anforderungen und Antworten von http://localhost:1234
mit dem oben stehenden Code aufgelistet.
Anforderung | Antwort |
---|---|
localhost:1234 | Hello from non-Map delegate. |
localhost:1234/map1 | Map Test 1 |
localhost:1234/map2 | Map Test 2 |
localhost:1234/map3 | Hello from non-Map delegate. |
Bei Verwendung von Map
werden die übereinstimmenden Pfadsegmente aus HttpRequest.Path
entfernt und für jede Anforderung an HttpRequest.PathBase
angehängt.
Map
unterstützt das Schachteln, wie z.B. in folgendem Code:
app.Map("/level1", level1App => {
level1App.Map("/level2a", level2AApp => {
// "/level1/level2a" processing
});
level1App.Map("/level2b", level2BApp => {
// "/level1/level2b" processing
});
});
Map
kann auch mehrere Segmente auf einmal zuordnen:
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
app.Map("/map1/seg1", HandleMultiSeg);
app.Run(async context =>
{
await context.Response.WriteAsync("Hello from non-Map delegate.");
});
app.Run();
static void HandleMultiSeg(IApplicationBuilder app)
{
app.Run(async context =>
{
await context.Response.WriteAsync("Map Test 1");
});
}
MapWhen brancht die Anforderungspipeline auf Grundlage des Ergebnisses des angegebenen Prädikats. Jedes Prädikat vom Typ Func<HttpContext, bool>
kann verwendet werden, um Anforderungen einem neuen Branch der Pipeline zuzuordnen. Im folgenden Beispiel wird ein Prädikat verwendet, um das Vorhandensein der Abfragezeichenfolgenvariablen branch
zu ermitteln:
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
app.MapWhen(context => context.Request.Query.ContainsKey("branch"), HandleBranch);
app.Run(async context =>
{
await context.Response.WriteAsync("Hello from non-Map delegate.");
});
app.Run();
static void HandleBranch(IApplicationBuilder app)
{
app.Run(async context =>
{
var branchVer = context.Request.Query["branch"];
await context.Response.WriteAsync($"Branch used = {branchVer}");
});
}
In der folgenden Tabelle sind die Anforderungen und Antworten von http://localhost:1234
mit dem oben stehenden Code aufgelistet:
Anforderung | Antwort |
---|---|
localhost:1234 |
Hello from non-Map delegate. |
localhost:1234/?branch=main |
Branch used = main |
UseWhen brancht auch die Anforderungspipeline auf Grundlage des Ergebnisses des angegebenen Prädikats. Anders als bei MapWhen
wird dieser Branch wieder mit der Hauptpipeline verbunden, wenn er nicht kurzgeschlossen wird oder eine Terminalmiddleware enthält:
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
app.UseWhen(context => context.Request.Query.ContainsKey("branch"),
appBuilder => HandleBranchAndRejoin(appBuilder));
app.Run(async context =>
{
await context.Response.WriteAsync("Hello from non-Map delegate.");
});
app.Run();
void HandleBranchAndRejoin(IApplicationBuilder app)
{
var logger = app.ApplicationServices.GetRequiredService<ILogger<Program>>();
app.Use(async (context, next) =>
{
var branchVer = context.Request.Query["branch"];
logger.LogInformation("Branch used = {branchVer}", branchVer);
// Do work that doesn't write to the Response.
await next();
// Do other work that doesn't write to the Response.
});
}
Im vorherigen Beispiel wird die Antwort Hello from non-Map delegate.
für alle Anforderungen ausgegeben. Wenn die Anforderung eine Abfragezeichenfolgevariable branch
enthält, wird der Wert der Pipeline protokolliert, bevor eine neue Verbindung hergestellt wird.
Integrierte Middleware
Die folgenden Middlewarekomponenten sind im Lieferumfang von ASP.NET Core enthalten. Die Spalte Reihenfolge enthält Hinweise zur Platzierung der Middleware in der Pipeline, die die Anforderung verarbeitet, und zu den Bedingungen, unter denen die Middleware die Anforderungsverarbeitung möglicherweise beendet. Wenn eine Middleware einen Kurzschluss in der Anforderungsverarbeitungspipeline verursacht und verhindert, dass Downstreammiddleware eine Anforderung verarbeitet, wird diese als Terminalmiddleware bezeichnet. Weitere Informationen zu Kurzschlüssen finden Sie im Abschnitt Erstellen einer Middlewarepipeline mit WebApplication.
Middleware | Beschreibung | Auftrag |
---|---|---|
Authentifizierung | Bietet Unterstützung für Authentifizierungen. | Bevor HttpContext.User erforderlich ist. Terminal für OAuth-Rückrufe. |
Autorisierung | Bietet Unterstützung für Authentifizierungen | Direkt nach der Authentifizierungsmiddleware |
Cookierichtlinie | Verfolgt die Zustimmung von Benutzern zum Speichern persönlicher Informationen und erzwingt die Mindeststandards für cookiefelder, z. B. secure und SameSite . |
Befindet sich vor der Middleware, die Cookies ausstellt. Beispiele: Authentifizierung, Sitzung, MVC (TempData). |
CORS | Konfiguriert die Ressourcenfreigabe zwischen verschiedenen Ursprüngen (Cross-Origin Resource Sharing, CORS). | Vor Komponenten, die CORS verwenden. UseCors muss sich derzeit aufgrund UseResponseCaching vor befinden. |
DeveloperExceptionPage | Diese generiert eine Seite mit Fehlerinformationen, die nur für die Verwendung in der Entwicklungsumgebung vorgesehen sind. | Vor Komponenten, die Fehler erzeugen. Die Projektvorlagen registrieren diese Middleware automatisch als erste Middleware in der Pipeline, wenn die Umgebung Entwicklung ist. |
Diagnose | Mehrere separate Middlewares, die Entwicklern eine Ausnahmeseite, Ausnahmebehandlung, Statuscodeseiten und die Standardwebseite für neue Apps bereitstellen. | Vor Komponenten, die Fehler erzeugen. Terminal für Ausnahmen oder zum Bereitstellen der Standardwebseite für neue Apps. |
Weitergeleitete Header | Leitet Proxyheader an die aktuelle Anforderung weiter. | Vor Komponenten, die die aktualisierten Felder nutzen. Beispiele: Schema, Host, Client-IP, Methode. |
Integritätsprüfung | Überprüft die Integrität der ASP.NET Core-App und ihrer Abhängigkeiten, z. B. Überprüfung der Datenbankverfügbarkeit. | Abschließend, wenn eine Anforderung mit einem Integritätsprüfungs-Endpunkt übereinstimmt. |
Headerweitergabe | Überträgt HTTP-Header aus der eingehenden Anforderung zu ausgehenden HTTP-Clientanforderungen | |
HTTP-Protokollierung | Hiermit werden HTTP-Anforderungen und -Antworten protokolliert. | Am Anfang der Middlewarepipeline. |
Außerkraftsetzung der HTTP-Methode | Ermöglicht es eingehenden POST-Anforderungen, die Methode außer Kraft zu setzen. | Vor Komponenten, die die aktualisierte Methode nutzen. |
HTTPS-Umleitung | Leitet alle HTTP-Anforderungen an HTTPS um. | Vor Komponenten, die die URL nutzen. |
HTTP Strict Transport Security (HSTS) | Middleware für erweiterte Sicherheit, die einen besonderen Antwortheader hinzufügt. | Bevor Antworten gesendet werden und nach Komponenten, die Anforderungen ändern. Beispiele: weitergeleitete Header, URL-Umschreibung. |
MVC | Verarbeitet Anforderungen mit MVC/Razor Pages. | Abschließend, wenn eine Anforderung mit einer Route übereinstimmt. |
OWIN | Interoperabilität mit auf OWIN basierten Apps, Servern und Middleware. | Abschließend, wenn die OWIN-Middleware die Anforderung vollständig verarbeitet. |
Ausgabezwischenspeicherung | Bietet Unterstützung für das Zwischenspeichern von Antworten basierend auf der Konfiguration. | Vor Komponenten, für die das Zwischenspeichern erforderlich ist. UseRouting muss sich vor UseOutputCaching befinden. UseCORS muss sich vor UseOutputCaching befinden. |
Zwischenspeichern von Antworten | Bietet Unterstützung für das Zwischenspeichern von Antworten. Dies erfordert die Teilnahme des Clients, um zu funktionieren. Verwenden Sie Ausgabezwischenspeicherung für vollständige Serversteuerung. | Vor Komponenten, für die das Zwischenspeichern erforderlich ist. UseCORS muss sich vor UseResponseCaching befinden. Ist in der Regel nicht vorteilhaft für Benutzeroberflächen-Apps wie Razor Pages, da Browser im Allgemeinen Anforderungsheader festlegen, die das Zwischenspeichern verhindern. Benutzeroberflächen-Apps profitieren von Ausgabezwischenspeicherung. |
Anforderungsdekomprimierung | Bietet Unterstützung für das Dekomprimieren von Anforderungen. | Vor Komponenten, die den Anforderungstext lesen. |
Antwortkomprimierung | Bietet Unterstützung für das Komprimieren von Antworten. | Vor Komponenten, für die das Komprimieren erforderlich ist. |
Lokalisierung von Anforderungen | Bietet Unterstützung für die Lokalisierung. | Vor der Lokalisierung vertraulicher Komponenten. Muss hinter Routing-Middleware stehen, wenn RouteDataRequestCultureProvider verwendet wird. |
Anforderungstimeouts | Bietet Unterstützung beim Konfigurieren von Anforderungstimeouts, global und pro Endpunkt. | UseRequestTimeouts muss nach UseExceptionHandler , UseDeveloperExceptionPage und UseRouting kommen. |
Endpunktrouting | Definiert Anforderungsrouten und schränkt diese ein. | Terminal für entsprechende Routen. |
SPA | Verarbeitet alle Anforderungen ab diesem Punkt in der Middlewarekette, indem die Standardseite für die Single-Page-Anwendung zurückgegeben wird. | Kommt spät in der Kette, sodass andere Middleware, z. B. die zum Bereitstellen von statischen Dateien oder MVC-Aktionen, Vorrang hat. |
Sitzung | Bietet Unterstützung für das Verwalten von Benutzersitzungen. | Vor Komponenten, für die Sitzungen erforderlich sind. |
Statische Dateien | Bietet Unterstützung für das Verarbeiten statischer Dateien und das Durchsuchen des Verzeichnisses. | Abschließend, wenn eine Anforderung mit einer Datei übereinstimmt. |
Umschreiben einer URL | Bietet Unterstützung für das Umschreiben von URLs und das Umleiten von Anforderungen. | Vor Komponenten, die die URL nutzen. |
W3CLogging | Hiermit werden Serverzugriffsprotokolle im erweiterten W3C-Protokolldateiformat generiert. | Am Anfang der Middlewarepipeline. |
WebSockets | Aktiviert das WebSockets-Protokoll. | Vor Komponenten, die WebSocket-Anforderungen annehmen müssen. |
Zusätzliche Ressourcen
- Die Lebensdauer und Registrierungsoptionen enthalten ein vollständiges Beispiel der Middleware mit Diensten mit bereichsbezogener und vorübergehender Lebensdauer sowie Singletonlebensdauer.
- Schreiben von benutzerdefinierter ASP.NET Core-Middleware
- Testen von ASP.NET Core-Middleware
- Konfigurieren von gRPC-Web in ASP.NET Core
- 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. Jede Komponente kann Folgendes ausführen:
- Entscheiden, ob die Anforderung an die nächste Komponente in der Pipeline übergeben werden soll.
- Ausführen von Arbeiten, bevor oder nachdem die nächste Komponente in der Pipeline aufgerufen wird.
Anforderungsdelegaten werden verwendet, um die Anforderungspipeline zu erstellen. Die Anforderungsdelegaten behandeln jede HTTP-Anforderung.
Anforderungsdelegaten werden mit den Erweiterungsmethoden Run, Map und Use konfiguriert. Ein einzelner Anforderungsdelegat kann inline als anonyme Methode angegeben werden (sogenannte Inline-Middleware), oder er kann in einer wiederverwendbaren Klasse definiert werden. Diese wiederverwendbaren Klassen und anonymen Inline-Methoden sind Middleware bzw. Middlewarekomponenten. Jede Middlewarekomponente in der Anforderungspipeline ist für das Aufrufen der jeweils nächsten Komponente in der Pipeline oder, wenn nötig, für das Kurzschließen der Pipeline zuständig. Wenn eine Middleware einen Kurzschluss verursacht, wird diese als Terminalmiddleware bezeichnet, da sie verhindert, dass weitere Middleware die Anforderung verarbeiten kann.
Unter Migrieren von HTTP-Handlern und -Modulen zu ASP.NET Core-Middleware wird der Unterschied zwischen Anforderungspipelines in ASP.NET Core und ASP.NET 4.x erläutert, und es werden zusätzliche Beispiele für Middleware bereitgestellt.
Die Rolle von Middleware nach App-Typ
Razor Pages, MVC, Blazor Server und das serverseitige Projekt einer gehosteten Blazor WebAssembly-Lösung verarbeiten Browser-Anforderungen auf dem Server mit Middleware. Die Anleitungen in diesem Artikel gelten für diese Arten von Apps.
Eigenständige Blazor WebAssembly-Apps werden vollständig auf dem Client ausgeführt und verarbeiten keine Anforderungen über eine Middleware-Pipeline. Die Anleitung in diesem Artikel gilt nicht für eigenständige Blazor WebAssembly-Apps.
Middleware-Codeanalyse
ASP.NET Core enthält zahlreiche Compilerplattform-Analysetools zum Überprüfen der Qualität des Anwendungscodes. Weitere Informationen finden Sie unter Codeanalyse in ASP.NET Core-Apps.
Erstellen einer Middlewarepipeline mit WebApplication
Die ASP.NET Core-Anforderungspipeline besteht aus einer Sequenz von Anforderungsdelegaten, die nacheinander aufgerufen werden. Das Konzept wird im folgenden Diagramm veranschaulicht. Der Ausführungsthread folgt den schwarzen Pfeilen.
Jeder Delegat kann Vorgänge vor und nach dem nächsten Delegaten ausführen. Die Ausnahmebehandlungsdelegaten müssen am Anfang der Pipeline aufgerufen werden, sodass sie Ausnahmen abfangen können, die zu einem späteren Zeitpunkt in der Pipeline ausgelöst werden.
Die einfachste mögliche ASP.NET Core-App enthält einen einzigen Anforderungsdelegaten, der alle Anforderungen verarbeitet. In diesem Fall ist keine tatsächliche Anforderungspipeline vorhanden. Stattdessen wird eine einzelne anonyme Funktion als Antwort auf jede HTTP-Anforderung aufgerufen.
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
app.Run(async context =>
{
await context.Response.WriteAsync("Hello world!");
});
app.Run();
Mit Use können Sie mehrere Anforderungedelegate miteinander verknüpfen. Der Parameter next
steht für den nächsten Delegaten in der Pipeline. Sie können die Pipeline kurzschließen, indem Sie den Parameter next
aufrufen. Normalerweise können Sie Aktionen sowohl vor als auch nach dem next
-Delegaten durchführen. Dies wird in folgendem Beispiel veranschaulicht:
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
app.Use(async (context, next) =>
{
// Do work that can write to the Response.
await next.Invoke();
// Do logging or other work that doesn't write to the Response.
});
app.Run(async context =>
{
await context.Response.WriteAsync("Hello from 2nd delegate.");
});
app.Run();
Wenn ein keine Anforderung an den nächsten Delegaten übergibt, wird dies als Kurzschluss der Anforderungspipeline bezeichnet. Das Kurzschließen ist oft sinnvoll, da es unnötige Arbeit verhindert. Die Middleware für statische Dateien kann beispielsweise als Terminalmiddleware fungieren, indem sie eine Anforderung für eine statische Datei zurückgibt und den rest der Pipeline kurzschließt. Middleware, die noch vor der Middleware, die die weitere Verarbeitung beendet, zur Pipeline hinzugefügt wird, verarbeitet Code noch nach den next.Invoke
-Anweisungen weiter. Sehen Sie sich allerdings die folgende Warnung zum Versuch an, in eine Antwort zu schreiben, die bereits gesendet wurde.
Warnung
Rufen Sie next.Invoke
nicht auf, nachdem die Antwort an den Client gesendet wurde. An HttpResponse vorgenommene Änderungen lösen nach dem Start der Antwort eine Ausnahme aus. Das Festlegen von Headern und einem Statuscode lösen beispielsweise eine Ausnahme aus. Wenn Sie nach dem Aufruf von next
in den Antworttext schreiben, kann dies:
- einen Protokollverstoß verursachen, wenn Sie z.B. mehr als das genannte
Content-Length
-Objekt schreiben. - Fehler im Textformat auslösen, wenn Sie z.B. eine HTML-Fußzeile in eine CSS-Datei schreiben.
HasStarted ist ein nützlicher Hinweis, der angibt, ob Header gesendet wurden oder ob in den Text geschrieben wurde.
Run-Delegaten erhalten keinen next
-Parameter. Der erste Run
-Delegat beendet immer die Pipeline. Run
ist eine Konvention. Einige Middlewarekomponenten machen möglicherweise Run[Middleware]
-Methoden verfügbar, die am Ende einer Pipeline ausgeführt werden:
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
app.Use(async (context, next) =>
{
// Do work that can write to the Response.
await next.Invoke();
// Do logging or other work that doesn't write to the Response.
});
app.Run(async context =>
{
await context.Response.WriteAsync("Hello from 2nd delegate.");
});
app.Run();
Wenn Sie möchten, dass Codekommentare in anderen Sprachen als Englisch angezeigt werden, informieren Sie uns in diesem GitHub-Issue.
Im vorherigen Beispiel schreibt der Run
-Delegat "Hello from 2nd delegate."
zur Antwort und beendet dann die Pipeline. Wenn ein anderer Use
- oder Run
-Delegat nach dem Run
-Delegaten hinzugefügt wird, wird dieser nicht aufgerufen.
App bevorzugen: Verwenden einer Überladung, die die Übergabe des Kontexts erfordert
Die app.Use-Erweiterungsmethode ohne Zuordnung:
- Erfordert die Übergabe des Kontexts an
next
- Speichert zwei interne Zuordnungen pro Anforderung, die bei Verwendung der anderen Überladung erforderlich sind
Weitere Informationen finden Sie in diesem GitHub-Issue.
Middlewarereihenfolge
In der folgenden Abbildung wird die gesamte Anforderungsverarbeitungspipeline für MVC- und Razor Pages-Apps in ASP.NET Core dargestellt. Es ist zu sehen, wie vorhandene Middleware in einer typischen App sortiert ist und an welcher Stelle benutzerdefinierte Middleware hinzugefügt wird. Sie haben vollständige Kontrolle darüber, wie vorhandene Middleware neu angeordnet oder neue benutzerdefinierte Middleware nach Bedarf eingefügt wird.
Der Endpunktmiddleware in der vorangehenden Abbildung führt die Filterpipeline für den entsprechenden App-Typ aus (MVC oder Razor Pages).
Die Routing-Middleware im vorherigen Diagramm ist im Anschluss an statische Dateien dargestellt. Dies ist die Reihenfolge, die die Projektvorlagen implementieren, indem sie explizit app.UseRouting aufrufen. Wenn Sie nicht app.UseRouting
aufrufen, wird die Routing-Middleware standardmäßig am Anfang der Pipeline ausgeführt. Weitere Informationen finden Sie unter Routing.
Die Reihenfolge, in der Middlewarekomponenten in der Program.cs
-Datei hinzugefügt werden, legt die Reihenfolge fest, in der die Middlewarekomponenten bei Anforderungen aufgerufen werden. Bei Antworten gilt die umgekehrte Reihenfolge. Die Reihenfolge ist in Bezug auf Sicherheit, Leistung und Funktionalität entscheidend.
Der folgende hervorgehobene Code in Program.cs
fügt sicherheitsbezogene Middlewarekomponenten in der typischen empfohlenen Reihenfolge hinzu:
using Microsoft.AspNetCore.Identity;
using Microsoft.EntityFrameworkCore;
using WebMiddleware.Data;
var builder = WebApplication.CreateBuilder(args);
var connectionString = builder.Configuration.GetConnectionString("DefaultConnection")
?? throw new InvalidOperationException("Connection string 'DefaultConnection' not found.");
builder.Services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(connectionString));
builder.Services.AddDatabaseDeveloperPageExceptionFilter();
builder.Services.AddDefaultIdentity<IdentityUser>(options => options.SignIn.RequireConfirmedAccount = true)
.AddEntityFrameworkStores<ApplicationDbContext>();
builder.Services.AddRazorPages();
builder.Services.AddControllersWithViews();
var app = builder.Build();
if (app.Environment.IsDevelopment())
{
app.UseMigrationsEndPoint();
}
else
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
// app.UseCookiePolicy();
app.UseRouting();
// app.UseRateLimiter();
// app.UseRequestLocalization();
// app.UseCors();
app.UseAuthentication();
app.UseAuthorization();
// app.UseSession();
// app.UseResponseCompression();
// app.UseResponseCaching();
app.MapRazorPages();
app.MapDefaultControllerRoute();
app.Run();
Für den Code oben gilt:
- Middleware, die beim Erstellen einer neuen Web-App mit einzelnen Benutzerkonten nicht hinzugefügt wird, wird auskommentiert.
- Die exakte Reihenfolge ist nicht für jede Middleware vorgeschrieben (dies ist jedoch meistens der Fall). Beispiel:
UseCors
,UseAuthentication
undUseAuthorization
müssen in der angezeigten Reihenfolge stehen.UseCors
muss derzeit aufgrund vorUseResponseCaching
stehen. Diese Anforderung wird im GitHub-Issue zu dotnet/aspnetcore, Nr. 23218, erläutert.UseRequestLocalization
muss vor jeder Middleware stehen, die u. U. die Anforderungskultur überprüft (z. B.app.UseStaticFiles()
).- UseRateLimiter muss nach
UseRouting
aufgerufen werden, wenn endpunktspezifische APIs für die Ratenbegrenzung verwendet werden. Wenn zum Beispiel das Attribut[EnableRateLimiting]
verwendet wird, mussUseRateLimiter
nachUseRouting
aufgerufen werden. Wenn nur globale Begrenzungen aufgerufen werden,UseRateLimiter
kann vorUseRouting
aufgerufen werden.
In einigen Szenarien weist die Middleware eine andere Reihenfolge auf. Die Reihenfolge für Zwischenspeicherung und Komprimierung beispielsweise ist szenariospezifisch, und es gibt verschiedene gültige Reihenfolgen. Beispiel:
app.UseResponseCaching();
app.UseResponseCompression();
Mit dem obigen Code könnte durch Zwischenspeichern der komprimierten Antwort die CPU-Auslastung verringert werden, dies könnte aber dazu führen, dass mehrere Darstellungen einer Ressource mithilfe verschiedener Komprimierungsalgorithmen wie z. B. Gzip oder Brotli zwischengespeichert werden.
Die folgende Reihenfolge kombiniert statische Dateien, um eine Zwischenspeicherung komprimierter statischer Dateien zuzulassen:
app.UseResponseCaching();
app.UseResponseCompression();
app.UseStaticFiles();
Der folgende Program.cs
-Code fügt Middlewarekomponenten für allgemeine App-Szenarios hinzu:
- Ausnahme-/Fehlerbehandlung
- Bei Ausführung der App in der Entwicklungsumgebung:
- Middleware der Seite mit Ausnahmen für Entwickler (UseDeveloperExceptionPage) meldet App-Laufzeitfehler.
- Middleware der Seite mit Datenbankfehlern (UseDatabaseErrorPage) meldet Datenbanklaufzeitfehler.
- Bei Ausführung der App in der Produktionsumgebung:
- Middleware für Ausnahmehandler (UseExceptionHandler) fängt Ausnahmen ab, die in den folgenden Middlewarekomponenten ausgelöst werden.
- HTTP Strict Transport Security Protocol-Middleware (HSTS) (UseHsts) fügt den
Strict-Transport-Security
-Header hinzu.
- Bei Ausführung der App in der Entwicklungsumgebung:
- Middleware zur HTTPS-Umleitung (UseHttpsRedirection) leitet HTTP-Anforderungen an HTTPS um.
- Middleware für statische Dateien (UseStaticFiles) gibt statische Dateien zurück und umgeht die weitere Anforderungsverarbeitung.
- Middleware für Cookierichtlinien (UseCookiePolicy) sorgt dafür, dass die App die Anforderungen der europäischen Datenschutzgrundverordnung (DSGVO) erfüllt.
- Routingmiddleware (UseRouting) zum Weiterleiten von Anforderungen.
- Middleware für die Authentifizierung (UseAuthentication) versucht, den Benutzer zu authentifizieren, bevor der Zugriff auf sichere Ressourcen zugelassen wird.
- Autorisierungsmiddleware (UseAuthorization) wird zum Autorisieren des Zugriffs auf sichere Ressourcen eines Benutzers verwendet.
- Middleware für Sitzungen (UseSession) richtet einen Sitzungsstatus ein und erhält diesen aufrecht. Wenn die App den Sitzungsstatus verwendet, rufen Sie die Middleware für Sitzungen nach der Middleware für Cookierichtlinien und vor der MVC-Middleware auf.
- Endpunktroutingmiddleware (UseEndpoints mit MapRazorPages) zum Hinzufügen von Razor Pages-Endpunkten zur Anforderungspipeline.
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
app.UseDatabaseErrorPage();
}
else
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseCookiePolicy();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseSession();
app.MapRazorPages();
Im vorhergehenden Beispielcode wird jede Middleware-Erweiterungsmethode in WebApplicationBuilder über den Microsoft.AspNetCore.Builder-Namespace verfügbar gemacht.
UseExceptionHandler ist die erste Middlewarekomponente, die der Pipeline hinzugefügt wird. Aus diesem Grund fängt die Middleware für den Ausnahmehandler alle Ausnahmen ab, die in späteren Aufrufen auftreten.
Die Middleware für statische Dateien wird am Anfang der Pipeline aufgerufen, damit sie Anforderungen und Kurzschlüsse verarbeiten kann, ohne dass die verbleibenden Komponenten durchlaufen werden müssen. Die Middleware für statische Dateien stellt keine Autorisierungsüberprüfungen bereit. Alle Dateien, die von Middleware für statische Dateien unterstützt werden, einschließlich der Dateien unter wwwroot, sind öffentlich verfügbar. Im Artikel zu statischen Dateien in ASP.NET Core erfahren Sie, wie Sie statische Dateien schützen können.
Wenn die Anforderung nicht von der Middleware für statische Dateien verarbeitet wird, wird sie an die Authentifizierungsmiddleware (UseAuthentication) übergeben, welche die Authentifizierung durchführt. Die Authentifizierung schließt nicht authentifizierte Anforderungen nicht kurz. Auch wenn die Authentifizierungsmiddleware Anforderungen authentifiziert, erfolgt die Autorisierung (und Ablehnung) erst dann, wenn MVC eine spezifische Razor Page oder einen MVC-Controller und eine Aktion ausgewählt hat.
Im folgenden Beispiel wird eine Middlewarereihenfolge veranschaulicht, bei der Anforderungen statischer Dateien von der Middleware für statische Dateien vor der Middleware für die Antwortkomprimierung verarbeitet werden. Die statischen Dateien werden bei dieser Middlewarereihenfolge nicht komprimiert. Die Razor Pages-Antworten können komprimiert werden.
// Static files aren't compressed by Static File Middleware.
app.UseStaticFiles();
app.UseRouting();
app.UseResponseCompression();
app.MapRazorPages();
Weitere Informationen zu Single-Page-Anwendungen finden Sie in den Anleitungen zu den React- und Angular-Projektvorlagen.
Reihenfolge von UseCors und UseStaticFiles
Die Reihenfolge der Aufrufe von UseCors
und UseStaticFiles
hängt von der App ab. Weitere Informationen finden Sie unter Reihenfolge von UseCors und UseStaticFiles
Middleware für weitergeleitete Header: Auftrag
Middleware für weitergeleitete Header muss vor anderen Middlewarekomponenten ausgeführt werden. Mit dieser Reihenfolge wird sichergestellt, dass die auf Informationen von weitergeleiteten Headern basierende Middleware die zu verarbeitenden Headerwerte nutzen kann. Unter Middleware für weitergeleitete Header: Auftrag finden Sie Informationen zum Ausführen der Middleware für weitergeleitete Header nach der diagnostischen Middleware und der Middleware für die Fehlerbehandlung.
Branchen der Middlewarepipeline
Map-Erweiterungen werden als Konvention zum Branchen der Pipeline verwendet. Map
brancht die Anforderungspipeline auf Grundlage von Übereinstimmungen des angegebenen Anforderungspfads. Wenn der Anforderungspfad mit dem angegebenen Pfad beginnt, wird der Branch ausgeführt.
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
app.Map("/map1", HandleMapTest1);
app.Map("/map2", HandleMapTest2);
app.Run(async context =>
{
await context.Response.WriteAsync("Hello from non-Map delegate.");
});
app.Run();
static void HandleMapTest1(IApplicationBuilder app)
{
app.Run(async context =>
{
await context.Response.WriteAsync("Map Test 1");
});
}
static void HandleMapTest2(IApplicationBuilder app)
{
app.Run(async context =>
{
await context.Response.WriteAsync("Map Test 2");
});
}
In der folgenden Tabelle sind die Anforderungen und Antworten von http://localhost:1234
mit dem oben stehenden Code aufgelistet.
Anforderung | Antwort |
---|---|
localhost:1234 | Hello from non-Map delegate. |
localhost:1234/map1 | Map Test 1 |
localhost:1234/map2 | Map Test 2 |
localhost:1234/map3 | Hello from non-Map delegate. |
Bei Verwendung von Map
werden die übereinstimmenden Pfadsegmente aus HttpRequest.Path
entfernt und für jede Anforderung an HttpRequest.PathBase
angehängt.
Map
unterstützt das Schachteln, wie z.B. in folgendem Code:
app.Map("/level1", level1App => {
level1App.Map("/level2a", level2AApp => {
// "/level1/level2a" processing
});
level1App.Map("/level2b", level2BApp => {
// "/level1/level2b" processing
});
});
Map
kann auch mehrere Segmente auf einmal zuordnen:
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
app.Map("/map1/seg1", HandleMultiSeg);
app.Run(async context =>
{
await context.Response.WriteAsync("Hello from non-Map delegate.");
});
app.Run();
static void HandleMultiSeg(IApplicationBuilder app)
{
app.Run(async context =>
{
await context.Response.WriteAsync("Map Test 1");
});
}
MapWhen brancht die Anforderungspipeline auf Grundlage des Ergebnisses des angegebenen Prädikats. Jedes Prädikat vom Typ Func<HttpContext, bool>
kann verwendet werden, um Anforderungen einem neuen Branch der Pipeline zuzuordnen. Im folgenden Beispiel wird ein Prädikat verwendet, um das Vorhandensein der Abfragezeichenfolgenvariablen branch
zu ermitteln:
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
app.MapWhen(context => context.Request.Query.ContainsKey("branch"), HandleBranch);
app.Run(async context =>
{
await context.Response.WriteAsync("Hello from non-Map delegate.");
});
app.Run();
static void HandleBranch(IApplicationBuilder app)
{
app.Run(async context =>
{
var branchVer = context.Request.Query["branch"];
await context.Response.WriteAsync($"Branch used = {branchVer}");
});
}
In der folgenden Tabelle sind die Anforderungen und Antworten von http://localhost:1234
mit dem oben stehenden Code aufgelistet:
Anforderung | Antwort |
---|---|
localhost:1234 |
Hello from non-Map delegate. |
localhost:1234/?branch=main |
Branch used = main |
UseWhen brancht auch die Anforderungspipeline auf Grundlage des Ergebnisses des angegebenen Prädikats. Anders als bei MapWhen
wird dieser Branch wieder mit der Hauptpipeline verbunden, wenn er nicht kurzgeschlossen wird oder eine Terminalmiddleware enthält:
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
app.UseWhen(context => context.Request.Query.ContainsKey("branch"),
appBuilder => HandleBranchAndRejoin(appBuilder));
app.Run(async context =>
{
await context.Response.WriteAsync("Hello from non-Map delegate.");
});
app.Run();
void HandleBranchAndRejoin(IApplicationBuilder app)
{
var logger = app.ApplicationServices.GetRequiredService<ILogger<Program>>();
app.Use(async (context, next) =>
{
var branchVer = context.Request.Query["branch"];
logger.LogInformation("Branch used = {branchVer}", branchVer);
// Do work that doesn't write to the Response.
await next();
// Do other work that doesn't write to the Response.
});
}
Im vorherigen Beispiel wird die Antwort Hello from non-Map delegate.
für alle Anforderungen ausgegeben. Wenn die Anforderung eine Abfragezeichenfolgevariable branch
enthält, wird der Wert der Pipeline protokolliert, bevor eine neue Verbindung hergestellt wird.
Integrierte Middleware
Die folgenden Middlewarekomponenten sind im Lieferumfang von ASP.NET Core enthalten. Die Spalte Reihenfolge enthält Hinweise zur Platzierung der Middleware in der Pipeline, die die Anforderung verarbeitet, und zu den Bedingungen, unter denen die Middleware die Anforderungsverarbeitung möglicherweise beendet. Wenn eine Middleware einen Kurzschluss in der Anforderungsverarbeitungspipeline verursacht und verhindert, dass Downstreammiddleware eine Anforderung verarbeitet, wird diese als Terminalmiddleware bezeichnet. Weitere Informationen zu Kurzschlüssen finden Sie im Abschnitt Erstellen einer Middlewarepipeline mit WebApplication.
Middleware | Beschreibung | Auftrag |
---|---|---|
Authentifizierung | Bietet Unterstützung für Authentifizierungen. | Bevor HttpContext.User erforderlich ist. Terminal für OAuth-Rückrufe. |
Autorisierung | Bietet Unterstützung für Authentifizierungen | Direkt nach der Authentifizierungsmiddleware |
Cookierichtlinie | Verfolgt die Zustimmung von Benutzern zum Speichern persönlicher Informationen und erzwingt die Mindeststandards für cookiefelder, z. B. secure und SameSite . |
Befindet sich vor der Middleware, die Cookies ausstellt. Beispiele: Authentifizierung, Sitzung, MVC (TempData). |
CORS | Konfiguriert die Ressourcenfreigabe zwischen verschiedenen Ursprüngen (Cross-Origin Resource Sharing, CORS). | Vor Komponenten, die CORS verwenden. UseCors muss sich derzeit aufgrund UseResponseCaching vor befinden. |
DeveloperExceptionPage | Diese generiert eine Seite mit Fehlerinformationen, die nur für die Verwendung in der Entwicklungsumgebung vorgesehen sind. | Vor Komponenten, die Fehler erzeugen. Die Projektvorlagen registrieren diese Middleware automatisch als erste Middleware in der Pipeline, wenn die Umgebung Entwicklung ist. |
Diagnose | Mehrere separate Middlewares, die Entwicklern eine Ausnahmeseite, Ausnahmebehandlung, Statuscodeseiten und die Standardwebseite für neue Apps bereitstellen. | Vor Komponenten, die Fehler erzeugen. Terminal für Ausnahmen oder zum Bereitstellen der Standardwebseite für neue Apps. |
Weitergeleitete Header | Leitet Proxyheader an die aktuelle Anforderung weiter. | Vor Komponenten, die die aktualisierten Felder nutzen. Beispiele: Schema, Host, Client-IP, Methode. |
Integritätsprüfung | Überprüft die Integrität der ASP.NET Core-App und ihrer Abhängigkeiten, z. B. Überprüfung der Datenbankverfügbarkeit. | Abschließend, wenn eine Anforderung mit einem Integritätsprüfungs-Endpunkt übereinstimmt. |
Headerweitergabe | Überträgt HTTP-Header aus der eingehenden Anforderung zu ausgehenden HTTP-Clientanforderungen | |
HTTP-Protokollierung | Hiermit werden HTTP-Anforderungen und -Antworten protokolliert. | Am Anfang der Middlewarepipeline. |
Außerkraftsetzung der HTTP-Methode | Ermöglicht es eingehenden POST-Anforderungen, die Methode außer Kraft zu setzen. | Vor Komponenten, die die aktualisierte Methode nutzen. |
HTTPS-Umleitung | Leitet alle HTTP-Anforderungen an HTTPS um. | Vor Komponenten, die die URL nutzen. |
HTTP Strict Transport Security (HSTS) | Middleware für erweiterte Sicherheit, die einen besonderen Antwortheader hinzufügt. | Bevor Antworten gesendet werden und nach Komponenten, die Anforderungen ändern. Beispiele: weitergeleitete Header, URL-Umschreibung. |
MVC | Verarbeitet Anforderungen mit MVC/Razor Pages. | Abschließend, wenn eine Anforderung mit einer Route übereinstimmt. |
OWIN | Interoperabilität mit auf OWIN basierten Apps, Servern und Middleware. | Abschließend, wenn die OWIN-Middleware die Anforderung vollständig verarbeitet. |
Ausgabezwischenspeicherung | Bietet Unterstützung für das Zwischenspeichern von Antworten basierend auf der Konfiguration. | Vor Komponenten, für die das Zwischenspeichern erforderlich ist. UseRouting muss sich vor UseOutputCaching befinden. UseCORS muss sich vor UseOutputCaching befinden. |
Zwischenspeichern von Antworten | Bietet Unterstützung für das Zwischenspeichern von Antworten. Dies erfordert die Teilnahme des Clients, um zu funktionieren. Verwenden Sie Ausgabezwischenspeicherung für vollständige Serversteuerung. | Vor Komponenten, für die das Zwischenspeichern erforderlich ist. UseCORS muss sich vor UseResponseCaching befinden. Ist in der Regel nicht vorteilhaft für Benutzeroberflächen-Apps wie Razor Pages, da Browser im Allgemeinen Anforderungsheader festlegen, die das Zwischenspeichern verhindern. Benutzeroberflächen-Apps profitieren von Ausgabezwischenspeicherung. |
Anforderungsdekomprimierung | Bietet Unterstützung für das Dekomprimieren von Anforderungen. | Vor Komponenten, die den Anforderungstext lesen. |
Antwortkomprimierung | Bietet Unterstützung für das Komprimieren von Antworten. | Vor Komponenten, für die das Komprimieren erforderlich ist. |
Lokalisierung von Anforderungen | Bietet Unterstützung für die Lokalisierung. | Vor der Lokalisierung vertraulicher Komponenten. Muss hinter Routing-Middleware stehen, wenn RouteDataRequestCultureProvider verwendet wird. |
Endpunktrouting | Definiert Anforderungsrouten und schränkt diese ein. | Terminal für entsprechende Routen. |
SPA | Verarbeitet alle Anforderungen ab diesem Punkt in der Middlewarekette, indem die Standardseite für die Single-Page-Anwendung zurückgegeben wird. | Kommt spät in der Kette, sodass andere Middleware, z. B. die zum Bereitstellen von statischen Dateien oder MVC-Aktionen, Vorrang hat. |
Sitzung | Bietet Unterstützung für das Verwalten von Benutzersitzungen. | Vor Komponenten, für die Sitzungen erforderlich sind. |
Statische Dateien | Bietet Unterstützung für das Verarbeiten statischer Dateien und das Durchsuchen des Verzeichnisses. | Abschließend, wenn eine Anforderung mit einer Datei übereinstimmt. |
Umschreiben einer URL | Bietet Unterstützung für das Umschreiben von URLs und das Umleiten von Anforderungen. | Vor Komponenten, die die URL nutzen. |
W3CLogging | Hiermit werden Serverzugriffsprotokolle im erweiterten W3C-Protokolldateiformat generiert. | Am Anfang der Middlewarepipeline. |
WebSockets | Aktiviert das WebSockets-Protokoll. | Vor Komponenten, die WebSocket-Anforderungen annehmen müssen. |
Zusätzliche Ressourcen
- Die Lebensdauer und Registrierungsoptionen enthalten ein vollständiges Beispiel der Middleware mit Diensten mit bereichsbezogener und vorübergehender Lebensdauer sowie Singletonlebensdauer.
- Schreiben von benutzerdefinierter ASP.NET Core-Middleware
- Testen von ASP.NET Core-Middleware
- Konfigurieren von gRPC-Web in ASP.NET Core
- 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. Jede Komponente kann Folgendes ausführen:
- Entscheiden, ob die Anforderung an die nächste Komponente in der Pipeline übergeben werden soll.
- Ausführen von Arbeiten, bevor oder nachdem die nächste Komponente in der Pipeline aufgerufen wird.
Anforderungsdelegaten werden verwendet, um die Anforderungspipeline zu erstellen. Die Anforderungsdelegaten behandeln jede HTTP-Anforderung.
Anforderungsdelegaten werden mit den Erweiterungsmethoden Run, Map und Use konfiguriert. Ein einzelner Anforderungsdelegat kann inline als anonyme Methode angegeben werden (sogenannte Inline-Middleware), oder er kann in einer wiederverwendbaren Klasse definiert werden. Diese wiederverwendbaren Klassen und anonymen Inline-Methoden sind Middleware bzw. Middlewarekomponenten. Jede Middlewarekomponente in der Anforderungspipeline ist für das Aufrufen der jeweils nächsten Komponente in der Pipeline oder, wenn nötig, für das Kurzschließen der Pipeline zuständig. Wenn eine Middleware einen Kurzschluss verursacht, wird diese als Terminalmiddleware bezeichnet, da sie verhindert, dass weitere Middleware die Anforderung verarbeiten kann.
Unter Migrieren von HTTP-Handlern und -Modulen zu ASP.NET Core-Middleware wird der Unterschied zwischen Anforderungspipelines in ASP.NET Core und ASP.NET 4.x erläutert, und es werden zusätzliche Beispiele für Middleware bereitgestellt.
Middleware-Codeanalyse
ASP.NET Core enthält zahlreiche Compilerplattform-Analysetools zum Überprüfen der Qualität des Anwendungscodes. Weitere Informationen finden Sie unter Codeanalyse in ASP.NET Core-Apps.
Erstellen einer Middlewarepipeline mit WebApplication
Die ASP.NET Core-Anforderungspipeline besteht aus einer Sequenz von Anforderungsdelegaten, die nacheinander aufgerufen werden. Das Konzept wird im folgenden Diagramm veranschaulicht. Der Ausführungsthread folgt den schwarzen Pfeilen.
Jeder Delegat kann Vorgänge vor und nach dem nächsten Delegaten ausführen. Die Ausnahmebehandlungsdelegaten müssen am Anfang der Pipeline aufgerufen werden, sodass sie Ausnahmen abfangen können, die zu einem späteren Zeitpunkt in der Pipeline ausgelöst werden.
Die einfachste mögliche ASP.NET Core-App enthält einen einzigen Anforderungsdelegaten, der alle Anforderungen verarbeitet. In diesem Fall ist keine tatsächliche Anforderungspipeline vorhanden. Stattdessen wird eine einzelne anonyme Funktion als Antwort auf jede HTTP-Anforderung aufgerufen.
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
app.Run(async context =>
{
await context.Response.WriteAsync("Hello world!");
});
app.Run();
Mit Use können Sie mehrere Anforderungedelegate miteinander verknüpfen. Der Parameter next
steht für den nächsten Delegaten in der Pipeline. Sie können die Pipeline kurzschließen, indem Sie den Parameter next
aufrufen. Normalerweise können Sie Aktionen sowohl vor als auch nach dem next
-Delegaten durchführen. Dies wird in folgendem Beispiel veranschaulicht:
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
app.Use(async (context, next) =>
{
// Do work that can write to the Response.
await next.Invoke();
// Do logging or other work that doesn't write to the Response.
});
app.Run(async context =>
{
await context.Response.WriteAsync("Hello from 2nd delegate.");
});
app.Run();
Wenn ein keine Anforderung an den nächsten Delegaten übergibt, wird dies als Kurzschluss der Anforderungspipeline bezeichnet. Das Kurzschließen ist oft sinnvoll, da es unnötige Arbeit verhindert. Die Middleware für statische Dateien kann beispielsweise als Terminalmiddleware fungieren, indem sie eine Anforderung für eine statische Datei zurückgibt und den rest der Pipeline kurzschließt. Middleware, die noch vor der Middleware, die die weitere Verarbeitung beendet, zur Pipeline hinzugefügt wird, verarbeitet Code noch nach den next.Invoke
-Anweisungen weiter. Sehen Sie sich allerdings die folgende Warnung zum Versuch an, in eine Antwort zu schreiben, die bereits gesendet wurde.
Warnung
Rufen Sie next.Invoke
nicht auf, nachdem die Antwort an den Client gesendet wurde. An HttpResponse vorgenommene Änderungen lösen nach dem Start der Antwort eine Ausnahme aus. Das Festlegen von Headern und einem Statuscode lösen beispielsweise eine Ausnahme aus. Wenn Sie nach dem Aufruf von next
in den Antworttext schreiben, kann dies:
- einen Protokollverstoß verursachen, wenn Sie z.B. mehr als das genannte
Content-Length
-Objekt schreiben. - Fehler im Textformat auslösen, wenn Sie z.B. eine HTML-Fußzeile in eine CSS-Datei schreiben.
HasStarted ist ein nützlicher Hinweis, der angibt, ob Header gesendet wurden oder ob in den Text geschrieben wurde.
Run-Delegaten erhalten keinen next
-Parameter. Der erste Run
-Delegat beendet immer die Pipeline. Run
ist eine Konvention. Einige Middlewarekomponenten machen möglicherweise Run[Middleware]
-Methoden verfügbar, die am Ende einer Pipeline ausgeführt werden:
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
app.Use(async (context, next) =>
{
// Do work that can write to the Response.
await next.Invoke();
// Do logging or other work that doesn't write to the Response.
});
app.Run(async context =>
{
await context.Response.WriteAsync("Hello from 2nd delegate.");
});
app.Run();
Wenn Sie möchten, dass Codekommentare in anderen Sprachen als Englisch angezeigt werden, informieren Sie uns in diesem GitHub-Issue.
Im vorherigen Beispiel schreibt der Run
-Delegat "Hello from 2nd delegate."
zur Antwort und beendet dann die Pipeline. Wenn ein anderer Use
- oder Run
-Delegat nach dem Run
-Delegaten hinzugefügt wird, wird dieser nicht aufgerufen.
App bevorzugen: Verwenden einer Überladung, die die Übergabe des Kontexts erfordert
Die app.Use-Erweiterungsmethode ohne Zuordnung:
- Erfordert die Übergabe des Kontexts an
next
- Speichert zwei interne Zuordnungen pro Anforderung, die bei Verwendung der anderen Überladung erforderlich sind
Weitere Informationen finden Sie in diesem GitHub-Issue.
Middlewarereihenfolge
In der folgenden Abbildung wird die gesamte Anforderungsverarbeitungspipeline für MVC- und Razor Pages-Apps in ASP.NET Core dargestellt. Es ist zu sehen, wie vorhandene Middleware in einer typischen App sortiert ist und an welcher Stelle benutzerdefinierte Middleware hinzugefügt wird. Sie haben vollständige Kontrolle darüber, wie vorhandene Middleware neu angeordnet oder neue benutzerdefinierte Middleware nach Bedarf eingefügt wird.
Der Endpunktmiddleware in der vorangehenden Abbildung führt die Filterpipeline für den entsprechenden App-Typ aus (MVC oder Razor Pages).
Die Routing-Middleware im vorherigen Diagramm ist im Anschluss an statische Dateien dargestellt. Dies ist die Reihenfolge, die die Projektvorlagen implementieren, indem sie explizit app.UseRouting aufrufen. Wenn Sie nicht app.UseRouting
aufrufen, wird die Routing-Middleware standardmäßig am Anfang der Pipeline ausgeführt. Weitere Informationen finden Sie unter Routing.
Die Reihenfolge, in der Middlewarekomponenten in der Program.cs
-Datei hinzugefügt werden, legt die Reihenfolge fest, in der die Middlewarekomponenten bei Anforderungen aufgerufen werden. Bei Antworten gilt die umgekehrte Reihenfolge. Die Reihenfolge ist in Bezug auf Sicherheit, Leistung und Funktionalität entscheidend.
Der folgende hervorgehobene Code in Program.cs
fügt sicherheitsbezogene Middlewarekomponenten in der typischen empfohlenen Reihenfolge hinzu:
using IndividualAccountsExample.Data;
using Microsoft.AspNetCore.Identity;
using Microsoft.EntityFrameworkCore;
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
var connectionString = builder.Configuration.GetConnectionString("DefaultConnection");
builder.Services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(connectionString));
builder.Services.AddDatabaseDeveloperPageExceptionFilter();
builder.Services.AddDefaultIdentity<IdentityUser>(options => options.SignIn.RequireConfirmedAccount = true)
.AddEntityFrameworkStores<ApplicationDbContext>();
builder.Services.AddRazorPages();
var app = builder.Build();
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
app.UseMigrationsEndPoint();
}
else
{
app.UseExceptionHandler("/Error");
// 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.UseStaticFiles();
// app.UseCookiePolicy();
app.UseRouting();
// app.UseRequestLocalization();
// app.UseCors();
app.UseAuthentication();
app.UseAuthorization();
// app.UseSession();
// app.UseResponseCompression();
// app.UseResponseCaching();
app.MapRazorPages();
app.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
app.Run();
Für den Code oben gilt:
- Middleware, die beim Erstellen einer neuen Web-App mit einzelnen Benutzerkonten nicht hinzugefügt wird, wird auskommentiert.
- Die exakte Reihenfolge ist nicht für jede Middleware vorgeschrieben (dies ist jedoch meistens der Fall). Beispiel:
UseCors
,UseAuthentication
undUseAuthorization
müssen in der angezeigten Reihenfolge stehen.UseCors
muss derzeit aufgrund vorUseResponseCaching
stehen. Diese Anforderung wird im GitHub-Issue zu dotnet/aspnetcore, Nr. 23218, erläutert.UseRequestLocalization
muss vor jeder Middleware stehen, die u. U. die Anforderungskultur überprüft (z. B.app.UseMvcWithDefaultRoute()
).
In einigen Szenarien weist die Middleware eine andere Reihenfolge auf. Die Reihenfolge für Zwischenspeicherung und Komprimierung beispielsweise ist szenariospezifisch, und es gibt verschiedene gültige Reihenfolgen. Beispiel:
app.UseResponseCaching();
app.UseResponseCompression();
Mit dem obigen Code könnte durch Zwischenspeichern der komprimierten Antwort die CPU-Auslastung verringert werden, dies könnte aber dazu führen, dass mehrere Darstellungen einer Ressource mithilfe verschiedener Komprimierungsalgorithmen wie z. B. Gzip oder Brotli zwischengespeichert werden.
Die folgende Reihenfolge kombiniert statische Dateien, um eine Zwischenspeicherung komprimierter statischer Dateien zuzulassen:
app.UseResponseCaching();
app.UseResponseCompression();
app.UseStaticFiles();
Der folgende Program.cs
-Code fügt Middlewarekomponenten für allgemeine App-Szenarios hinzu:
- Ausnahme-/Fehlerbehandlung
- Bei Ausführung der App in der Entwicklungsumgebung:
- Middleware der Seite mit Ausnahmen für Entwickler (UseDeveloperExceptionPage) meldet App-Laufzeitfehler.
- Middleware der Seite mit Datenbankfehlern (UseDatabaseErrorPage) meldet Datenbanklaufzeitfehler.
- Bei Ausführung der App in der Produktionsumgebung:
- Middleware für Ausnahmehandler (UseExceptionHandler) fängt Ausnahmen ab, die in den folgenden Middlewarekomponenten ausgelöst werden.
- HTTP Strict Transport Security Protocol-Middleware (HSTS) (UseHsts) fügt den
Strict-Transport-Security
-Header hinzu.
- Bei Ausführung der App in der Entwicklungsumgebung:
- Middleware zur HTTPS-Umleitung (UseHttpsRedirection) leitet HTTP-Anforderungen an HTTPS um.
- Middleware für statische Dateien (UseStaticFiles) gibt statische Dateien zurück und umgeht die weitere Anforderungsverarbeitung.
- Middleware für Cookierichtlinien (UseCookiePolicy) sorgt dafür, dass die App die Anforderungen der europäischen Datenschutzgrundverordnung (DSGVO) erfüllt.
- Routingmiddleware (UseRouting) zum Weiterleiten von Anforderungen.
- Middleware für die Authentifizierung (UseAuthentication) versucht, den Benutzer zu authentifizieren, bevor der Zugriff auf sichere Ressourcen zugelassen wird.
- Autorisierungsmiddleware (UseAuthorization) wird zum Autorisieren des Zugriffs auf sichere Ressourcen eines Benutzers verwendet.
- Middleware für Sitzungen (UseSession) richtet einen Sitzungsstatus ein und erhält diesen aufrecht. Wenn die App den Sitzungsstatus verwendet, rufen Sie die Middleware für Sitzungen nach der Middleware für Cookierichtlinien und vor der MVC-Middleware auf.
- Endpunktroutingmiddleware (UseEndpoints mit MapRazorPages) zum Hinzufügen von Razor Pages-Endpunkten zur Anforderungspipeline.
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
app.UseDatabaseErrorPage();
}
else
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseCookiePolicy();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseSession();
app.MapRazorPages();
Im vorhergehenden Beispielcode wird jede Middleware-Erweiterungsmethode in WebApplicationBuilder über den Microsoft.AspNetCore.Builder-Namespace verfügbar gemacht.
UseExceptionHandler ist die erste Middlewarekomponente, die der Pipeline hinzugefügt wird. Aus diesem Grund fängt die Middleware für den Ausnahmehandler alle Ausnahmen ab, die in späteren Aufrufen auftreten.
Die Middleware für statische Dateien wird am Anfang der Pipeline aufgerufen, damit sie Anforderungen und Kurzschlüsse verarbeiten kann, ohne dass die verbleibenden Komponenten durchlaufen werden müssen. Die Middleware für statische Dateien stellt keine Autorisierungsüberprüfungen bereit. Alle Dateien, die von Middleware für statische Dateien unterstützt werden, einschließlich der Dateien unter wwwroot, sind öffentlich verfügbar. Im Artikel zu statischen Dateien in ASP.NET Core erfahren Sie, wie Sie statische Dateien schützen können.
Wenn die Anforderung nicht von der Middleware für statische Dateien verarbeitet wird, wird sie an die Authentifizierungsmiddleware (UseAuthentication) übergeben, welche die Authentifizierung durchführt. Die Authentifizierung schließt nicht authentifizierte Anforderungen nicht kurz. Auch wenn die Authentifizierungsmiddleware Anforderungen authentifiziert, erfolgt die Autorisierung (und Ablehnung) erst dann, wenn MVC eine spezifische Razor Page oder einen MVC-Controller und eine Aktion ausgewählt hat.
Im folgenden Beispiel wird eine Middlewarereihenfolge veranschaulicht, bei der Anforderungen statischer Dateien von der Middleware für statische Dateien vor der Middleware für die Antwortkomprimierung verarbeitet werden. Die statischen Dateien werden bei dieser Middlewarereihenfolge nicht komprimiert. Die Razor Pages-Antworten können komprimiert werden.
// Static files aren't compressed by Static File Middleware.
app.UseStaticFiles();
app.UseRouting();
app.UseResponseCompression();
app.MapRazorPages();
Weitere Informationen zu Single-Page-Anwendungen finden Sie in den Anleitungen zu den React- und Angular-Projektvorlagen.
Reihenfolge von UseCors und UseStaticFiles
Die Reihenfolge der Aufrufe von UseCors
und UseStaticFiles
hängt von der App ab. Weitere Informationen finden Sie unter Reihenfolge von UseCors und UseStaticFiles
Middleware für weitergeleitete Header: Auftrag
Middleware für weitergeleitete Header muss vor anderen Middlewarekomponenten ausgeführt werden. Mit dieser Reihenfolge wird sichergestellt, dass die auf Informationen von weitergeleiteten Headern basierende Middleware die zu verarbeitenden Headerwerte nutzen kann. Unter Middleware für weitergeleitete Header: Auftrag finden Sie Informationen zum Ausführen der Middleware für weitergeleitete Header nach der diagnostischen Middleware und der Middleware für die Fehlerbehandlung.
Branchen der Middlewarepipeline
Map-Erweiterungen werden als Konvention zum Branchen der Pipeline verwendet. Map
brancht die Anforderungspipeline auf Grundlage von Übereinstimmungen des angegebenen Anforderungspfads. Wenn der Anforderungspfad mit dem angegebenen Pfad beginnt, wird der Branch ausgeführt.
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
app.Map("/map1", HandleMapTest1);
app.Map("/map2", HandleMapTest2);
app.Run(async context =>
{
await context.Response.WriteAsync("Hello from non-Map delegate.");
});
app.Run();
static void HandleMapTest1(IApplicationBuilder app)
{
app.Run(async context =>
{
await context.Response.WriteAsync("Map Test 1");
});
}
static void HandleMapTest2(IApplicationBuilder app)
{
app.Run(async context =>
{
await context.Response.WriteAsync("Map Test 2");
});
}
In der folgenden Tabelle sind die Anforderungen und Antworten von http://localhost:1234
mit dem oben stehenden Code aufgelistet.
Anforderung | Antwort |
---|---|
localhost:1234 | Hello from non-Map delegate. |
localhost:1234/map1 | Map Test 1 |
localhost:1234/map2 | Map Test 2 |
localhost:1234/map3 | Hello from non-Map delegate. |
Bei Verwendung von Map
werden die übereinstimmenden Pfadsegmente aus HttpRequest.Path
entfernt und für jede Anforderung an HttpRequest.PathBase
angehängt.
Map
unterstützt das Schachteln, wie z.B. in folgendem Code:
app.Map("/level1", level1App => {
level1App.Map("/level2a", level2AApp => {
// "/level1/level2a" processing
});
level1App.Map("/level2b", level2BApp => {
// "/level1/level2b" processing
});
});
Map
kann auch mehrere Segmente auf einmal zuordnen:
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
app.Map("/map1/seg1", HandleMultiSeg);
app.Run(async context =>
{
await context.Response.WriteAsync("Hello from non-Map delegate.");
});
app.Run();
static void HandleMultiSeg(IApplicationBuilder app)
{
app.Run(async context =>
{
await context.Response.WriteAsync("Map Test 1");
});
}
MapWhen brancht die Anforderungspipeline auf Grundlage des Ergebnisses des angegebenen Prädikats. Jedes Prädikat vom Typ Func<HttpContext, bool>
kann verwendet werden, um Anforderungen einem neuen Branch der Pipeline zuzuordnen. Im folgenden Beispiel wird ein Prädikat verwendet, um das Vorhandensein der Abfragezeichenfolgenvariablen branch
zu ermitteln:
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
app.MapWhen(context => context.Request.Query.ContainsKey("branch"), HandleBranch);
app.Run(async context =>
{
await context.Response.WriteAsync("Hello from non-Map delegate.");
});
app.Run();
static void HandleBranch(IApplicationBuilder app)
{
app.Run(async context =>
{
var branchVer = context.Request.Query["branch"];
await context.Response.WriteAsync($"Branch used = {branchVer}");
});
}
In der folgenden Tabelle sind die Anforderungen und Antworten von http://localhost:1234
mit dem oben stehenden Code aufgelistet:
Anforderung | Antwort |
---|---|
localhost:1234 |
Hello from non-Map delegate. |
localhost:1234/?branch=main |
Branch used = main |
UseWhen brancht auch die Anforderungspipeline auf Grundlage des Ergebnisses des angegebenen Prädikats. Anders als bei MapWhen
wird dieser Branch wieder mit der Hauptpipeline verbunden, wenn er nicht kurzgeschlossen wird oder eine Terminalmiddleware enthält:
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
app.UseWhen(context => context.Request.Query.ContainsKey("branch"),
appBuilder => HandleBranchAndRejoin(appBuilder));
app.Run(async context =>
{
await context.Response.WriteAsync("Hello from non-Map delegate.");
});
app.Run();
void HandleBranchAndRejoin(IApplicationBuilder app)
{
var logger = app.ApplicationServices.GetRequiredService<ILogger<Program>>();
app.Use(async (context, next) =>
{
var branchVer = context.Request.Query["branch"];
logger.LogInformation("Branch used = {branchVer}", branchVer);
// Do work that doesn't write to the Response.
await next();
// Do other work that doesn't write to the Response.
});
}
Im vorherigen Beispiel wird die Antwort Hello from non-Map delegate.
für alle Anforderungen ausgegeben. Wenn die Anforderung eine Abfragezeichenfolgevariable branch
enthält, wird der Wert der Pipeline protokolliert, bevor eine neue Verbindung hergestellt wird.
Integrierte Middleware
Die folgenden Middlewarekomponenten sind im Lieferumfang von ASP.NET Core enthalten. Die Spalte Reihenfolge enthält Hinweise zur Platzierung der Middleware in der Pipeline, die die Anforderung verarbeitet, und zu den Bedingungen, unter denen die Middleware die Anforderungsverarbeitung möglicherweise beendet. Wenn eine Middleware einen Kurzschluss in der Anforderungsverarbeitungspipeline verursacht und verhindert, dass Downstreammiddleware eine Anforderung verarbeitet, wird diese als Terminalmiddleware bezeichnet. Weitere Informationen zu Kurzschlüssen finden Sie im Abschnitt Erstellen einer Middlewarepipeline mit WebApplication.
Middleware | Beschreibung | Auftrag |
---|---|---|
Authentifizierung | Bietet Unterstützung für Authentifizierungen. | Bevor HttpContext.User erforderlich ist. Terminal für OAuth-Rückrufe. |
Autorisierung | Bietet Unterstützung für Authentifizierungen | Direkt nach der Authentifizierungsmiddleware |
Cookierichtlinie | Verfolgt die Zustimmung von Benutzern zum Speichern persönlicher Informationen und erzwingt die Mindeststandards für cookiefelder, z. B. secure und SameSite . |
Befindet sich vor der Middleware, die Cookies ausstellt. Beispiele: Authentifizierung, Sitzung, MVC (TempData). |
CORS | Konfiguriert die Ressourcenfreigabe zwischen verschiedenen Ursprüngen (Cross-Origin Resource Sharing, CORS). | Vor Komponenten, die CORS verwenden. UseCors muss sich derzeit aufgrund UseResponseCaching vor befinden. |
DeveloperExceptionPage | Diese generiert eine Seite mit Fehlerinformationen, die nur für die Verwendung in der Entwicklungsumgebung vorgesehen sind. | Vor Komponenten, die Fehler erzeugen. Die Projektvorlagen registrieren diese Middleware automatisch als erste Middleware in der Pipeline, wenn die Umgebung Entwicklung ist. |
Diagnose | Mehrere separate Middlewares, die Entwicklern eine Ausnahmeseite, Ausnahmebehandlung, Statuscodeseiten und die Standardwebseite für neue Apps bereitstellen. | Vor Komponenten, die Fehler erzeugen. Terminal für Ausnahmen oder zum Bereitstellen der Standardwebseite für neue Apps. |
Weitergeleitete Header | Leitet Proxyheader an die aktuelle Anforderung weiter. | Vor Komponenten, die die aktualisierten Felder nutzen. Beispiele: Schema, Host, Client-IP, Methode. |
Integritätsprüfung | Überprüft die Integrität der ASP.NET Core-App und ihrer Abhängigkeiten, z. B. Überprüfung der Datenbankverfügbarkeit. | Abschließend, wenn eine Anforderung mit einem Integritätsprüfungs-Endpunkt übereinstimmt. |
Headerweitergabe | Überträgt HTTP-Header aus der eingehenden Anforderung zu ausgehenden HTTP-Clientanforderungen | |
HTTP-Protokollierung | Hiermit werden HTTP-Anforderungen und -Antworten protokolliert. | Am Anfang der Middlewarepipeline. |
Außerkraftsetzung der HTTP-Methode | Ermöglicht es eingehenden POST-Anforderungen, die Methode außer Kraft zu setzen. | Vor Komponenten, die die aktualisierte Methode nutzen. |
HTTPS-Umleitung | Leitet alle HTTP-Anforderungen an HTTPS um. | Vor Komponenten, die die URL nutzen. |
HTTP Strict Transport Security (HSTS) | Middleware für erweiterte Sicherheit, die einen besonderen Antwortheader hinzufügt. | Bevor Antworten gesendet werden und nach Komponenten, die Anforderungen ändern. Beispiele: weitergeleitete Header, URL-Umschreibung. |
MVC | Verarbeitet Anforderungen mit MVC/Razor Pages. | Abschließend, wenn eine Anforderung mit einer Route übereinstimmt. |
OWIN | Interoperabilität mit auf OWIN basierten Apps, Servern und Middleware. | Abschließend, wenn die OWIN-Middleware die Anforderung vollständig verarbeitet. |
Anforderungsdekomprimierung | Bietet Unterstützung für das Dekomprimieren von Anforderungen. | Vor Komponenten, die den Anforderungstext lesen. |
Zwischenspeichern von Antworten | Bietet Unterstützung für das Zwischenspeichern von Antworten. | Vor Komponenten, für die das Zwischenspeichern erforderlich ist. UseCORS muss sich vor UseResponseCaching befinden. |
Antwortkomprimierung | Bietet Unterstützung für das Komprimieren von Antworten. | Vor Komponenten, für die das Komprimieren erforderlich ist. |
Lokalisierung von Anforderungen | Bietet Unterstützung für die Lokalisierung. | Vor der Lokalisierung vertraulicher Komponenten. Muss hinter Routing-Middleware stehen, wenn RouteDataRequestCultureProvider verwendet wird. |
Endpunktrouting | Definiert Anforderungsrouten und schränkt diese ein. | Terminal für entsprechende Routen. |
SPA | Verarbeitet alle Anforderungen ab diesem Punkt in der Middlewarekette, indem die Standardseite für die Single-Page-Anwendung zurückgegeben wird. | Kommt spät in der Kette, sodass andere Middleware, z. B. die zum Bereitstellen von statischen Dateien oder MVC-Aktionen, Vorrang hat. |
Sitzung | Bietet Unterstützung für das Verwalten von Benutzersitzungen. | Vor Komponenten, für die Sitzungen erforderlich sind. |
Statische Dateien | Bietet Unterstützung für das Verarbeiten statischer Dateien und das Durchsuchen des Verzeichnisses. | Abschließend, wenn eine Anforderung mit einer Datei übereinstimmt. |
Umschreiben einer URL | Bietet Unterstützung für das Umschreiben von URLs und das Umleiten von Anforderungen. | Vor Komponenten, die die URL nutzen. |
W3CLogging | Hiermit werden Serverzugriffsprotokolle im erweiterten W3C-Protokolldateiformat generiert. | Am Anfang der Middlewarepipeline. |
WebSockets | Aktiviert das WebSockets-Protokoll. | Vor Komponenten, die WebSocket-Anforderungen annehmen müssen. |
Zusätzliche Ressourcen
- Die Lebensdauer und Registrierungsoptionen enthalten ein vollständiges Beispiel der Middleware mit Diensten mit bereichsbezogener und vorübergehender Lebensdauer sowie Singletonlebensdauer.
- Schreiben von benutzerdefinierter ASP.NET Core-Middleware
- Testen von ASP.NET Core-Middleware
- Konfigurieren von gRPC-Web in ASP.NET Core
- 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. Jede Komponente kann Folgendes ausführen:
- Entscheiden, ob die Anforderung an die nächste Komponente in der Pipeline übergeben werden soll.
- Ausführen von Arbeiten, bevor oder nachdem die nächste Komponente in der Pipeline aufgerufen wird.
Anforderungsdelegaten werden verwendet, um die Anforderungspipeline zu erstellen. Die Anforderungsdelegaten behandeln jede HTTP-Anforderung.
Anforderungsdelegaten werden mit den Erweiterungsmethoden Run, Map und Use konfiguriert. Ein einzelner Anforderungsdelegat kann inline als anonyme Methode angegeben werden (sogenannte Inline-Middleware), oder er kann in einer wiederverwendbaren Klasse definiert werden. Diese wiederverwendbaren Klassen und anonymen Inline-Methoden sind Middleware bzw. Middlewarekomponenten. Jede Middlewarekomponente in der Anforderungspipeline ist für das Aufrufen der jeweils nächsten Komponente in der Pipeline oder, wenn nötig, für das Kurzschließen der Pipeline zuständig. Wenn eine Middleware einen Kurzschluss verursacht, wird diese als Terminalmiddleware bezeichnet, da sie verhindert, dass weitere Middleware die Anforderung verarbeiten kann.
Unter Migrieren von HTTP-Handlern und -Modulen zu ASP.NET Core-Middleware wird der Unterschied zwischen Anforderungspipelines in ASP.NET Core und ASP.NET 4.x erläutert, und es werden zusätzliche Beispiele für Middleware bereitgestellt.
Erstellen einer Middlewarepipeline mit IApplicationBuilder
Die ASP.NET Core-Anforderungspipeline besteht aus einer Sequenz von Anforderungsdelegaten, die nacheinander aufgerufen werden. Das Konzept wird im folgenden Diagramm veranschaulicht. Der Ausführungsthread folgt den schwarzen Pfeilen.
Jeder Delegat kann Vorgänge vor und nach dem nächsten Delegaten ausführen. Die Ausnahmebehandlungsdelegaten müssen am Anfang der Pipeline aufgerufen werden, sodass sie Ausnahmen abfangen können, die zu einem späteren Zeitpunkt in der Pipeline ausgelöst werden.
Die einfachste mögliche ASP.NET Core-App enthält einen einzigen Anforderungsdelegaten, der alle Anforderungen verarbeitet. In diesem Fall ist keine tatsächliche Anforderungspipeline vorhanden. Stattdessen wird eine einzelne anonyme Funktion als Antwort auf jede HTTP-Anforderung aufgerufen.
public class Startup
{
public void Configure(IApplicationBuilder app)
{
app.Run(async context =>
{
await context.Response.WriteAsync("Hello, World!");
});
}
}
Mit Use können Sie mehrere Anforderungedelegate miteinander verknüpfen. Der Parameter next
steht für den nächsten Delegaten in der Pipeline. Sie können die Pipeline kurzschließen, indem Sie den Parameter nextnicht aufrufen. Normalerweise können Sie Aktionen sowohl vor als auch nach dem nächsten Delegaten durchführen. Dies wird in folgendem Beispiel veranschaulicht:
public class Startup
{
public void Configure(IApplicationBuilder app)
{
app.Use(async (context, next) =>
{
// Do work that doesn't write to the Response.
await next.Invoke();
// Do logging or other work that doesn't write to the Response.
});
app.Run(async context =>
{
await context.Response.WriteAsync("Hello from 2nd delegate.");
});
}
}
Wenn ein keine Anforderung an den nächsten Delegaten übergibt, wird dies als Kurzschluss der Anforderungspipeline bezeichnet. Das Kurzschließen ist oft sinnvoll, da es unnötige Arbeit verhindert. Die Middleware für statische Dateien kann beispielsweise als Terminalmiddleware fungieren, indem sie eine Anforderung für eine statische Datei zurückgibt und den rest der Pipeline kurzschließt. Middleware, die noch vor der Middleware, die die weitere Verarbeitung beendet, zur Pipeline hinzugefügt wird, verarbeitet Code noch nach den next.Invoke
-Anweisungen weiter. Sehen Sie sich allerdings die folgende Warnung zum Versuch an, in eine Antwort zu schreiben, die bereits gesendet wurde.
Warnung
Rufen Sie next.Invoke
nicht auf, nachdem die Antwort an den Client gesendet wurde. An HttpResponse vorgenommene Änderungen lösen nach dem Start der Antwort eine Ausnahme aus. Das Festlegen von Headern und einem Statuscode lösen beispielsweise eine Ausnahme aus. Wenn Sie nach dem Aufruf von next
in den Antworttext schreiben, kann dies:
- einen Protokollverstoß verursachen, wenn Sie z.B. mehr als das genannte
Content-Length
-Objekt schreiben. - Fehler im Textformat auslösen, wenn Sie z.B. eine HTML-Fußzeile in eine CSS-Datei schreiben.
HasStarted ist ein nützlicher Hinweis, der angibt, ob Header gesendet wurden oder ob in den Text geschrieben wurde.
Run-Delegaten erhalten keinen next
-Parameter. Der erste Run
-Delegat beendet immer die Pipeline. Run
ist eine Konvention. Einige Middlewarekomponenten machen möglicherweise Run[Middleware]
-Methoden verfügbar, die am Ende einer Pipeline ausgeführt werden:
public class Startup
{
public void Configure(IApplicationBuilder app)
{
app.Use(async (context, next) =>
{
// Do work that doesn't write to the Response.
await next.Invoke();
// Do logging or other work that doesn't write to the Response.
});
app.Run(async context =>
{
await context.Response.WriteAsync("Hello from 2nd delegate.");
});
}
}
Wenn Sie möchten, dass Codekommentare in anderen Sprachen als Englisch angezeigt werden, informieren Sie uns in diesem GitHub-Issue.
Im vorherigen Beispiel schreibt der Run
-Delegat "Hello from 2nd delegate."
zur Antwort und beendet dann die Pipeline. Wenn ein anderer Use
- oder Run
-Delegat nach dem Run
-Delegaten hinzugefügt wird, wird dieser nicht aufgerufen.
Middlewarereihenfolge
In der folgenden Abbildung wird die gesamte Anforderungsverarbeitungspipeline für MVC- und Razor Pages-Apps in ASP.NET Core dargestellt. Es ist zu sehen, wie vorhandene Middleware in einer typischen App sortiert ist und an welcher Stelle benutzerdefinierte Middleware hinzugefügt wird. Sie haben vollständige Kontrolle darüber, wie vorhandene Middleware neu angeordnet oder neue benutzerdefinierte Middleware nach Bedarf eingefügt wird.
Der Endpunktmiddleware in der vorangehenden Abbildung führt die Filterpipeline für den entsprechenden App-Typ aus (MVC oder Razor Pages).
Die Reihenfolge, in der Middlewarekomponenten in der Startup.Configure
-Methode hinzugefügt werden, legt die Reihenfolge fest, in der die Middlewarekomponenten bei Anforderungen aufgerufen werden. Bei Antworten gilt die umgekehrte Reihenfolge. Die Reihenfolge ist in Bezug auf Sicherheit, Leistung und Funktionalität entscheidend.
Die folgende Startup.Configure
-Methode fügt sicherheitsbezogene Middlewarekomponenten in der typischen empfohlenen Reihenfolge hinzu:
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
app.UseDatabaseErrorPage();
}
else
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
// app.UseCookiePolicy();
app.UseRouting();
// app.UseRequestLocalization();
// app.UseCors();
app.UseAuthentication();
app.UseAuthorization();
// app.UseSession();
// app.UseResponseCompression();
// app.UseResponseCaching();
app.UseEndpoints(endpoints =>
{
endpoints.MapRazorPages();
endpoints.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
});
}
Für den Code oben gilt:
- Middleware, die beim Erstellen einer neuen Web-App mit einzelnen Benutzerkonten nicht hinzugefügt wird, wird auskommentiert.
- Die exakte Reihenfolge ist nicht für jede Middleware vorgeschrieben (dies ist jedoch meistens der Fall). Beispiel:
In einigen Szenarien weist die Middleware eine andere Reihenfolge auf. Die Reihenfolge für Zwischenspeicherung und Komprimierung beispielsweise ist szenariospezifisch, und es gibt verschiedene gültige Reihenfolgen. Beispiel:
app.UseResponseCaching();
app.UseResponseCompression();
Mit dem obigen Code könnte durch Zwischenspeichern der komprimierten Antwort die CPU-Auslastung verringert werden, dies könnte aber dazu führen, dass mehrere Darstellungen einer Ressource mithilfe verschiedener Komprimierungsalgorithmen wie z. B. Gzip oder Brotli zwischengespeichert werden.
Die folgende Reihenfolge kombiniert statische Dateien, um eine Zwischenspeicherung komprimierter statischer Dateien zuzulassen:
app.UseResponseCaching();
app.UseResponseCompression();
app.UseStaticFiles();
Die folgenden Startup.Configure
-Methode fügt Middlewarekomponenten für allgemeine App-Szenarien hinzu:
- Ausnahme-/Fehlerbehandlung
- Bei Ausführung der App in der Entwicklungsumgebung:
- Middleware der Seite mit Ausnahmen für Entwickler (UseDeveloperExceptionPage) meldet App-Laufzeitfehler.
- Middleware der Seite mit Datenbankfehlern meldet Datenbanklaufzeitfehler.
- Bei Ausführung der App in der Produktionsumgebung:
- Middleware für Ausnahmehandler (UseExceptionHandler) fängt Ausnahmen ab, die in den folgenden Middlewarekomponenten ausgelöst werden.
- HTTP Strict Transport Security Protocol-Middleware (HSTS) (UseHsts) fügt den
Strict-Transport-Security
-Header hinzu.
- Bei Ausführung der App in der Entwicklungsumgebung:
- Middleware zur HTTPS-Umleitung (UseHttpsRedirection) leitet HTTP-Anforderungen an HTTPS um.
- Middleware für statische Dateien (UseStaticFiles) gibt statische Dateien zurück und umgeht die weitere Anforderungsverarbeitung.
- Middleware für Cookierichtlinien (UseCookiePolicy) sorgt dafür, dass die App die Anforderungen der europäischen Datenschutzgrundverordnung (DSGVO) erfüllt.
- Routingmiddleware (UseRouting) zum Weiterleiten von Anforderungen.
- Middleware für die Authentifizierung (UseAuthentication) versucht, den Benutzer zu authentifizieren, bevor der Zugriff auf sichere Ressourcen zugelassen wird.
- Autorisierungsmiddleware (UseAuthorization) wird zum Autorisieren des Zugriffs auf sichere Ressourcen eines Benutzers verwendet.
- Middleware für Sitzungen (UseSession) richtet einen Sitzungsstatus ein und erhält diesen aufrecht. Wenn die App den Sitzungsstatus verwendet, rufen Sie die Middleware für Sitzungen nach der Middleware für Cookierichtlinien und vor der MVC-Middleware auf.
- Endpunktroutingmiddleware (UseEndpoints mit MapRazorPages) zum Hinzufügen von Razor Pages-Endpunkten zur Anforderungspipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
app.UseDatabaseErrorPage();
}
else
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseCookiePolicy();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseSession();
app.UseEndpoints(endpoints =>
{
endpoints.MapRazorPages();
});
}
Im vorhergehenden Beispielcode wird jede Middleware-Erweiterungsmethode in IApplicationBuilder über den Microsoft.AspNetCore.Builder-Namespace verfügbar gemacht.
UseExceptionHandler ist die erste Middlewarekomponente, die der Pipeline hinzugefügt wird. Aus diesem Grund fängt die Middleware für den Ausnahmehandler alle Ausnahmen ab, die in späteren Aufrufen auftreten.
Die Middleware für statische Dateien wird am Anfang der Pipeline aufgerufen, damit sie Anforderungen und Kurzschlüsse verarbeiten kann, ohne dass die verbleibenden Komponenten durchlaufen werden müssen. Die Middleware für statische Dateien stellt keine Autorisierungsüberprüfungen bereit. Alle Dateien, die von Middleware für statische Dateien unterstützt werden, einschließlich der Dateien unter wwwroot, sind öffentlich verfügbar. Im Artikel zu statischen Dateien in ASP.NET Core erfahren Sie, wie Sie statische Dateien schützen können.
Wenn die Anforderung nicht von der Middleware für statische Dateien verarbeitet wird, wird sie an die Authentifizierungsmiddleware (UseAuthentication) übergeben, welche die Authentifizierung durchführt. Die Authentifizierung schließt nicht authentifizierte Anforderungen nicht kurz. Auch wenn die Authentifizierungsmiddleware Anforderungen authentifiziert, erfolgt die Autorisierung (und Ablehnung) erst dann, wenn MVC eine spezifische Razor Page oder einen MVC-Controller und eine Aktion ausgewählt hat.
Im folgenden Beispiel wird eine Middlewarereihenfolge veranschaulicht, bei der Anforderungen statischer Dateien von der Middleware für statische Dateien vor der Middleware für die Antwortkomprimierung verarbeitet werden. Die statischen Dateien werden bei dieser Middlewarereihenfolge nicht komprimiert. Die Razor Pages-Antworten können komprimiert werden.
public void Configure(IApplicationBuilder app)
{
// Static files aren't compressed by Static File Middleware.
app.UseStaticFiles();
app.UseRouting();
app.UseResponseCompression();
app.UseEndpoints(endpoints =>
{
endpoints.MapRazorPages();
});
}
Bei Single-Page-Webanwendungen (Single-Page Applications, SPAs) ist die entsprechende SPA-Middleware UseSpaStaticFiles in der Regel der letzte Teil der Middlewarepipeline. Die SPA-Middleware kommt zuletzt, damit:
- Jede andere Middleware zuerst auf entsprechende Anforderungen reagieren können.
- SPAs mit clientseitigem Routing für alle Routen ausgeführt werden können, die von der Server-App nicht erkannt werden.
Weitere Informationen zu SPAs finden Sie in den Anleitungen zu den React- und Angular-Projektvorlagen.
Middleware für weitergeleitete Header: Auftrag
Middleware für weitergeleitete Header muss vor anderen Middlewarekomponenten ausgeführt werden. Mit dieser Reihenfolge wird sichergestellt, dass die auf Informationen von weitergeleiteten Headern basierende Middleware die zu verarbeitenden Headerwerte nutzen kann. Unter Middleware für weitergeleitete Header: Auftrag finden Sie Informationen zum Ausführen der Middleware für weitergeleitete Header nach der diagnostischen Middleware und der Middleware für die Fehlerbehandlung.
Branchen der Middlewarepipeline
Map-Erweiterungen werden als Konvention zum Branchen der Pipeline verwendet. Map
brancht die Anforderungspipeline auf Grundlage von Übereinstimmungen des angegebenen Anforderungspfads. Wenn der Anforderungspfad mit dem angegebenen Pfad beginnt, wird der Branch ausgeführt.
public class Startup
{
private static void HandleMapTest1(IApplicationBuilder app)
{
app.Run(async context =>
{
await context.Response.WriteAsync("Map Test 1");
});
}
private static void HandleMapTest2(IApplicationBuilder app)
{
app.Run(async context =>
{
await context.Response.WriteAsync("Map Test 2");
});
}
public void Configure(IApplicationBuilder app)
{
app.Map("/map1", HandleMapTest1);
app.Map("/map2", HandleMapTest2);
app.Run(async context =>
{
await context.Response.WriteAsync("Hello from non-Map delegate.");
});
}
}
In der folgenden Tabelle sind die Anforderungen und Antworten von http://localhost:1234
mit dem oben stehenden Code aufgelistet.
Anforderung | Antwort |
---|---|
localhost:1234 | Hello from non-Map delegate. |
localhost:1234/map1 | Map Test 1 |
localhost:1234/map2 | Map Test 2 |
localhost:1234/map3 | Hello from non-Map delegate. |
Bei Verwendung von Map
werden die übereinstimmenden Pfadsegmente aus HttpRequest.Path
entfernt und für jede Anforderung an HttpRequest.PathBase
angehängt.
Map
unterstützt das Schachteln, wie z.B. in folgendem Code:
app.Map("/level1", level1App => {
level1App.Map("/level2a", level2AApp => {
// "/level1/level2a" processing
});
level1App.Map("/level2b", level2BApp => {
// "/level1/level2b" processing
});
});
Map
kann auch mehrere Segmente auf einmal zuordnen:
public class Startup
{
private static void HandleMultiSeg(IApplicationBuilder app)
{
app.Run(async context =>
{
await context.Response.WriteAsync("Map multiple segments.");
});
}
public void Configure(IApplicationBuilder app)
{
app.Map("/map1/seg1", HandleMultiSeg);
app.Run(async context =>
{
await context.Response.WriteAsync("Hello from non-Map delegate.");
});
}
}
MapWhen brancht die Anforderungspipeline auf Grundlage des Ergebnisses des angegebenen Prädikats. Jedes Prädikat vom Typ Func<HttpContext, bool>
kann verwendet werden, um Anforderungen einem neuen Branch der Pipeline zuzuordnen. Im folgenden Beispiel wird ein Prädikat verwendet, um das Vorhandensein der Abfragezeichenfolgenvariablen branch
zu ermitteln:
public class Startup
{
private static void HandleBranch(IApplicationBuilder app)
{
app.Run(async context =>
{
var branchVer = context.Request.Query["branch"];
await context.Response.WriteAsync($"Branch used = {branchVer}");
});
}
public void Configure(IApplicationBuilder app)
{
app.MapWhen(context => context.Request.Query.ContainsKey("branch"),
HandleBranch);
app.Run(async context =>
{
await context.Response.WriteAsync("Hello from non-Map delegate.");
});
}
}
In der folgenden Tabelle sind die Anforderungen und Antworten von http://localhost:1234
mit dem oben stehenden Code aufgelistet:
Anforderung | Antwort |
---|---|
localhost:1234 | Hello from non-Map delegate. |
localhost:1234/?branch=main | Branch used = main |
UseWhen brancht auch die Anforderungspipeline auf Grundlage des Ergebnisses des angegebenen Prädikats. Anders als bei MapWhen
wird dieser Branch wieder mit der Hauptpipeline verbunden, wenn er nicht kurzgeschlossen wird oder eine Terminalmiddleware enthält:
public class Startup
{
private void HandleBranchAndRejoin(IApplicationBuilder app, ILogger<Startup> logger)
{
app.Use(async (context, next) =>
{
var branchVer = context.Request.Query["branch"];
logger.LogInformation("Branch used = {branchVer}", branchVer);
// Do work that doesn't write to the Response.
await next();
// Do other work that doesn't write to the Response.
});
}
public void Configure(IApplicationBuilder app, ILogger<Startup> logger)
{
app.UseWhen(context => context.Request.Query.ContainsKey("branch"),
appBuilder => HandleBranchAndRejoin(appBuilder, logger));
app.Run(async context =>
{
await context.Response.WriteAsync("Hello from main pipeline.");
});
}
}
Im vorherigen Beispiel wird die Antwort „Hello from main pipeline“ für alle Anforderungen ausgegeben. Wenn die Anforderung eine Abfragezeichenfolgevariable branch
enthält, wird der Wert der Pipeline protokolliert, bevor eine neue Verbindung hergestellt wird.
Integrierte Middleware
Die folgenden Middlewarekomponenten sind im Lieferumfang von ASP.NET Core enthalten. Die Spalte Reihenfolge enthält Hinweise zur Platzierung der Middleware in der Pipeline, die die Anforderung verarbeitet, und zu den Bedingungen, unter denen die Middleware die Anforderungsverarbeitung möglicherweise beendet. Wenn eine Middleware einen Kurzschluss in der Anforderungsverarbeitungspipeline verursacht und verhindert, dass Downstreammiddleware eine Anforderung verarbeitet, wird diese als Terminalmiddleware bezeichnet. Weitere Informationen zu Kurzschlüssen finden Sie im Abschnitt Erstellen einer Middlewarepipeline mit IApplicationBuilder.
Middleware | Beschreibung | Auftrag |
---|---|---|
Authentifizierung | Bietet Unterstützung für Authentifizierungen. | Bevor HttpContext.User erforderlich ist. Terminal für OAuth-Rückrufe. |
Autorisierung | Bietet Unterstützung für Authentifizierungen | Direkt nach der Authentifizierungsmiddleware |
Cookierichtlinie | Verfolgt die Zustimmung von Benutzern zum Speichern persönlicher Informationen und erzwingt die Mindeststandards für cookiefelder, z. B. secure und SameSite . |
Befindet sich vor der Middleware, die Cookies ausstellt. Beispiele: Authentifizierung, Sitzung, MVC (TempData). |
CORS | Konfiguriert die Ressourcenfreigabe zwischen verschiedenen Ursprüngen (Cross-Origin Resource Sharing, CORS). | Vor Komponenten, die CORS verwenden. UseCors muss sich derzeit aufgrund UseResponseCaching vor befinden. |
Diagnose | Mehrere separate Middlewares, die Entwicklern eine Ausnahmeseite, Ausnahmebehandlung, Statuscodeseiten und die Standardwebseite für neue Apps bereitstellen. | Vor Komponenten, die Fehler erzeugen. Terminal für Ausnahmen oder zum Bereitstellen der Standardwebseite für neue Apps. |
Weitergeleitete Header | Leitet Proxyheader an die aktuelle Anforderung weiter. | Vor Komponenten, die die aktualisierten Felder nutzen. Beispiele: Schema, Host, Client-IP, Methode. |
Integritätsprüfung | Überprüft die Integrität der ASP.NET Core-App und ihrer Abhängigkeiten, z. B. Überprüfung der Datenbankverfügbarkeit. | Abschließend, wenn eine Anforderung mit einem Integritätsprüfungs-Endpunkt übereinstimmt. |
Headerweitergabe | Überträgt HTTP-Header aus der eingehenden Anforderung zu ausgehenden HTTP-Clientanforderungen | |
Außerkraftsetzung der HTTP-Methode | Ermöglicht es eingehenden POST-Anforderungen, die Methode außer Kraft zu setzen. | Vor Komponenten, die die aktualisierte Methode nutzen. |
HTTPS-Umleitung | Leitet alle HTTP-Anforderungen an HTTPS um. | Vor Komponenten, die die URL nutzen. |
HTTP Strict Transport Security (HSTS) | Middleware für erweiterte Sicherheit, die einen besonderen Antwortheader hinzufügt. | Bevor Antworten gesendet werden und nach Komponenten, die Anforderungen ändern. Beispiele: weitergeleitete Header, URL-Umschreibung. |
MVC | Verarbeitet Anforderungen mit MVC/Razor Pages. | Abschließend, wenn eine Anforderung mit einer Route übereinstimmt. |
OWIN | Interoperabilität mit auf OWIN basierten Apps, Servern und Middleware. | Abschließend, wenn die OWIN-Middleware die Anforderung vollständig verarbeitet. |
Zwischenspeichern von Antworten | Bietet Unterstützung für das Zwischenspeichern von Antworten. | Vor Komponenten, für die das Zwischenspeichern erforderlich ist. UseCORS muss sich vor UseResponseCaching befinden. |
Antwortkomprimierung | Bietet Unterstützung für das Komprimieren von Antworten. | Vor Komponenten, für die das Komprimieren erforderlich ist. |
Lokalisierung von Anforderungen | Bietet Unterstützung für die Lokalisierung. | Vor der Lokalisierung vertraulicher Komponenten. Muss hinter Routing-Middleware stehen, wenn RouteDataRequestCultureProvider verwendet wird. |
Endpunktrouting | Definiert Anforderungsrouten und schränkt diese ein. | Terminal für entsprechende Routen. |
SPA | Verarbeitet alle Anforderungen ab diesem Punkt in der Middlewarekette, indem die Standardseite für die Single-Page-Anwendung zurückgegeben wird. | Kommt spät in der Kette, sodass andere Middleware, z. B. die zum Bereitstellen von statischen Dateien oder MVC-Aktionen, Vorrang hat. |
Sitzung | Bietet Unterstützung für das Verwalten von Benutzersitzungen. | Vor Komponenten, für die Sitzungen erforderlich sind. |
Statische Dateien | Bietet Unterstützung für das Verarbeiten statischer Dateien und das Durchsuchen des Verzeichnisses. | Abschließend, wenn eine Anforderung mit einer Datei übereinstimmt. |
Umschreiben einer URL | Bietet Unterstützung für das Umschreiben von URLs und das Umleiten von Anforderungen. | Vor Komponenten, die die URL nutzen. |
WebSockets | Aktiviert das WebSocket-Protokoll. | Vor Komponenten, die WebSocket-Anforderungen annehmen müssen. |
Zusätzliche Ressourcen
- Die Lebensdauer und Registrierungsoptionen enthalten ein vollständiges Beispiel der Middleware mit Diensten mit bereichsbezogener und vorübergehender Lebensdauer sowie Singletonlebensdauer.
- Schreiben von benutzerdefinierter 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