Poznámka
Přístup k této stránce vyžaduje autorizaci. Můžete se zkusit přihlásit nebo změnit adresáře.
Přístup k této stránce vyžaduje autorizaci. Můžete zkusit změnit adresáře.
Poznámka:
Toto není nejnovější verze tohoto článku. Pro aktuální verzi tohoto článku se podívejte na verzi .NET 9.
Varování
Tato verze ASP.NET Core se už nepodporuje. Další informace najdete v zásadách podpory .NET a .NET Core. Pro aktuální verzi tohoto článku se podívejte na verzi .NET 9.
Důležité
Tyto informace se týkají předběžného vydání produktu, který může být podstatně změněn před komerčním vydáním. Microsoft neposkytuje žádné záruky, výslovné ani předpokládané, týkající se zde uváděných informací.
Pro aktuální verzi tohoto článku se podívejte na verzi .NET 9.
Autor: Rick Anderson a Steve Smith
Middleware je software sestavený do kanálu aplikace pro zpracování požadavků a odpovědí. Každá komponenta:
- Určuje, jestli se má požadavek předat další součásti v potrubí.
- Může provádět práci před a po další komponentě v řetězci.
K sestavení kanálu požadavků se používají delegáti požadavků. Delegáti požadavků zpracovávají každý požadavek HTTP.
Delegáti požadavků jsou konfigurováni pomocí rozšiřujících metod Run, Map a Use. Jednotlivý delegát požadavku může být zadán na řádku jako anonymní metoda (tzv. in-line middleware) nebo může být definován v opakovaně použitelné třídě. Tyto opakovaně použitelné třídy a vložené anonymní metody jsou middleware, označované také jako komponenty middlewaru. Každá komponenta middlewaru v kanálu požadavků zodpovídá za vyvolání další komponenty v kanálu nebo zkratování kanálu. Když middleware způsobí zkrat, označuje se jako terminální middleware, protože brání další middleware ve zpracování požadavku.
Migrace modulů HTTP do middlewaru ASP.NET Core vysvětluje rozdíl mezi kanály požadavků v ASP.NET Core a ASP.NET 4.x a poskytuje další ukázky middlewaru.
Role middlewaru podle typu aplikace
Blazor Web Apps, Razor Pages a MVC zpracovávají požadavky prohlížeče na serveru pomocí middlewaru. Pokyny v tomto článku platí pro tyto typy aplikací.
Samostatné Blazor WebAssembly aplikace běží zcela na klientovi a nezpracují požadavky pomocí kanálu middlewaru. Pokyny v tomto článku se nevztahují na samostatné Blazor WebAssembly aplikace.
Analýza kódu middlewaru
ASP.NET Core obsahuje celou řadu analyzátorů Compile Platform, které kontrolují kód aplikace z hlediska kvality. Další informace najdete v tématu Analýza kódu v aplikacích ASP.NET Core.
Vytvoření kanálu middlewaru s využitím WebApplication
Kanál požadavků v ASP.NET Core se skládá z posloupnosti delegátů požadavků, kteří se volají postupně. Tento koncept demonstruje následující schéma. Vlákno spouštění postupuje podle černých šipek.
Každý delegát může provádět operace před a za dalším delegátem. Delegáti zpracování výjimek by se měli volat v počátečních fázích řetězce, aby mohli zachytit výjimky, ke kterým dochází v pozdějších fázích řetězce.
Nejjednodušší možná aplikace ASP.NET Core nastavuje jednoho delegáta požadavků, který zpracovává všechny požadavky. Tento případ nezahrnuje vlastní kanál požadavků. Místo toho se jako reakce na každý požadavek HTTP volá jedna anonymní funkce.
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
app.Run(async context =>
{
await context.Response.WriteAsync("Hello world!");
});
app.Run();
Propojte více delegátů požadavků pomocí Use. Parametr next
představuje dalšího delegáta v potrubí. Kanál můžete zkratovat tím, že nezavoláte parametr next
. Obvykle můžete provádět akce před delegátem next
i po něm, jak ukazuje následující příklad:
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();
Zkratování zpracovatelského kanálu požadavků
Pokud delegát nepředá požadavek dalšímu delegátovi, označuje se to jako přerušení kanálu požadavků. Zkratování je často žádoucí, protože zabraňuje zbytečné práci. Například middleware statického souboru může fungovat jako terminálový middleware zpracováním požadavku na statický soubor a přeskočením zbytku zpracování. Middleware přidaný do kanálu před middleware, který ukončí další zpracování, stále zpracovává kód po příslušných příkazech next.Invoke
. Ohledně pokusu o zápis do již odeslané odpovědi si však projděte následující upozornění.
Varování
Nevolejte next.Invoke
během odesílání odpovědi nebo po jejím odeslání klientovi. Po spuštění HttpResponse změny vyústí ve výjimku. Například nastavení hlaviček a stavového kódu vyvolá výjimku po spuštění odpovědi. Zápis do textu odpovědi po volání next
:
- Může způsobit porušení protokolu, například zapsání vyšší hodnoty, než je uvedeno
Content-Length
. - Může poškodit formát těla, například zápis zápatí HTML do souboru CSS.
HasStarted je užitečná nápověda indikující, jestli byly odeslány hlavičky nebo zapisováno do textu.
Další informace najdete v tématu Middleware s předčasným přerušením po směrování.
Run
delegáti
Delegáti Run neobdrží parametr next
. První delegát Run
je vždy terminální a ukončí zpracovatelský řetězec. Použití Run
je obvyklá konvence. Některé komponenty middlewaru můžou zpřístupnit metody Run[Middleware]
, které běží na konci kanálu:
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();
Pokud chcete zobrazit komentáře ke kódu přeložené do jiných jazyků, než je angličtina, dejte nám vědět v této diskuzi na GitHubu.
V předchozím příkladu delegát Run
zapíše "Hello from 2nd delegate."
do odpovědi a pak ukončí kanál. Pokud je za delegáta Use
přidán jiný delegát Run
nebo Run
, nevolá se.
Preferujte přetížení metody app.Use, které vyžaduje předání kontextu dalšímu kroku
Rozšiřující metoda app.Use bez přidělování:
- Vyžaduje předání kontextu do
next
. - Šetří dvě alokace paměti na jednotlivé požadavky, které jsou vyžadovány při použití jiné přetížené funkce.
Další informace najdete u tohoto problému na GitHubu.
Pořadí middlewaru
Následující diagram znázorňuje kompletní kanál zpracování požadavků pro aplikace ASP.NET Core MVC a Razor Pages. Můžete si prohlédnout, jak je v typické aplikaci uspořádané stávající middlewary seřazené a kde se přidávají vlastní middlewary. Máte plnou kontrolu nad tím, jak změnit pořadí stávajících middlewarů nebo vložit nové vlastní middlewary podle potřeby vašich scénářů.
Middleware Endpoint v předchozím diagramu spustí kanál filtru pro odpovídající typ aplikace – MVC nebo Razor Pages.
Middleware Routing v předchozím diagramu je zobrazený za statickými soubory. Toto je pořadí, které šablony projektů implementují explicitním voláním app.UseRouting. Pokud nezavoláte app.UseRouting
, ve výchozím nastavení se middleware Routing spustí na začátku kanálu. Další informace najdete v tématu Směrování.
Pořadí, ve kterém jsou komponenty middlewaru přidány do souboru Program.cs
, definuje pořadí, ve kterém se komponenty middlewaru vyvolávají pro požadavky, a obrácené pořadí pro odpovědi. Toto pořadí má zásadní důležitost pro zabezpečení, výkon a funkce.
Následující zvýrazněný kód v Program.cs
přidává komponenty middlewaru související se zabezpečením v typickém doporučeném pořadí:
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();
V předchozím kódu:
- Middleware, který se nepřidá při vytváření nové webové aplikace s účty jednotlivých uživatelů, je zakomentovaný.
- Ne každý middleware se objevuje přesně v tomto pořadí, ale mnoho z nich ano. Příklad:
-
UseCors
,UseAuthentication
aUseAuthorization
musí být v uvedeném pořadí. -
UseCors
musí aktuálně být předUseResponseCaching
. Tento požadavek je vysvětlený v problému s dotnet/aspnetcore #23218 na GitHubu. -
UseRequestLocalization
musí se objevit před jakýmkoli middlewarem, který může zkontrolovat jazykovou verzi požadavku, napříkladapp.UseStaticFiles()
. -
UseRateLimiter musí být volána po
UseRouting
, když se používají rozhraní API pro omezení rychlosti pro konkrétní koncové body. Pokud je například atribut[EnableRateLimiting]
použit,UseRateLimiter
musí být zavolána poUseRouting
. Při volání pouze globálních limiterůUseRateLimiter
může být volán předUseRouting
.
-
V některých scénářích má middleware jiné řazení. Například pořadí ukládání do mezipaměti a komprese je specifické pro daný scénář a existuje několik platných pořadí. Příklad:
app.UseResponseCaching();
app.UseResponseCompression();
V předchozím kódu by bylo možné snížit využití procesoru uložením komprimované odpovědi do mezipaměti, ale mohlo by se stát, že budete ukládat do mezipaměti více reprezentací prostředku pomocí různých kompresních algoritmů, jako jsou například Gzip nebo Brotli.
Následující pořadí kombinuje statické soubory, aby se umožnilo ukládání komprimovaných statických souborů do mezipaměti:
app.UseResponseCaching();
app.UseResponseCompression();
app.UseStaticFiles();
Následující kód Program.cs
přidá komponenty middlewaru pro běžné scénáře aplikací:
- Zpracování výjimek nebo chyb
- Když se aplikace spustí ve vývojovém prostředí:
- Middleware Developer Exception Page (UseDeveloperExceptionPage) hlásí běhové chyby aplikací.
- Middleware Database Error Page (UseDatabaseErrorPage) hlásí běhové chyby databází.
- Když se aplikace spustí v produkčním prostředí:
- Middleware Exception Handler (UseExceptionHandler) zachycuje výjimky vyvolané v následujících middlewarech.
- Middleware HSTS (HTTP Strict Transport Security Protocol) (UseHsts) přidává hlavičku
Strict-Transport-Security
.
- Když se aplikace spustí ve vývojovém prostředí:
- Middleware HTTPS Redirection (UseHttpsRedirection) přesměruje požadavky HTTP na HTTPS.
- Middleware pro statické soubory (UseStaticFiles) vrací statické soubory a přeruší další zpracování požadavků.
- Middleware Cookie Policy (UseCookiePolicy) zajišťuje soulad aplikace s Obecným nařízením EU o ochraně osobních údajů (GDPR).
- Routing Middleware (UseRouting) slouží ke směrování požadavků.
- Middleware Authentication (UseAuthentication) se pokusí ověřit uživatele předtím, než se mu povolí přístup k zabezpečeným prostředkům.
- Autorizační Middleware (UseAuthorization) opravňuje uživatele ke vstupu do zabezpečených prostředků.
- Session Middleware (UseSession) nastavuje a udržuje stav relace. Pokud aplikace používá stav relace, volejte middleware Session za middlewarem Cookie Policy a před middlewarem MVC.
- Middleware Endpoint Routing (UseEndpoints s MapRazorPages) slouží pro přidání koncových bodů Razor Pages do kanálu požadavků.
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();
V předchozím ukázkovém kódu je každá rozšiřující metoda middlewaru zpřístupněná v WebApplicationBuilder prostřednictvím oboru názvů Microsoft.AspNetCore.Builder.
UseExceptionHandler je první middleware komponenta přidaná do potrubí. Proto middleware Exception Handler zachycuje všechny výjimky, ke kterým dochází v pozdějších voláních.
Middleware Static File se volá v rané fázi zpracování kanálu, aby mohl zpracovávat požadavky a provést zkratování, aniž by se musely projít zbývající komponenty. Middleware Static File neposkytuje žádné kontroly autorizace. Všechny soubory obsluhované middlewarem Static File, včetně souborů pod wwwroot, jsou veřejně dostupné. Informace o přístupu k zabezpečení statických souborů najdete v tématu Statické soubory v ASP.NET Core.
Pokud požadavek nezpracuje middleware Static File, předá se do middlewaru Authentication (UseAuthentication), který provádí ověřování. Ověřování nezpůsobí přeskočení neověřených požadavků. I když Middleware Authentication ověřuje požadavky, autorizace (a zamítnutí) nastane až poté, co MVC vybere konkrétní Razor stránku nebo kontroler MVC a akci.
Následující příklad ukazuje pořadí middlewaru, ve kterém požadavky pro statické soubory zpracovává middleware Static File před middlewarem Response Compression. Statické soubory nejsou při tomto uspořádání middlewaru komprimovány. Odpovědi Razor Pages je možné komprimovat.
// Static files aren't compressed by Static File Middleware.
app.UseStaticFiles();
app.UseRouting();
app.UseResponseCompression();
app.MapRazorPages();
Informace o jednostrákových aplikacích najdete v tématu Přehled jednostrákových aplikací (SPA) v ASP.NET Core.
Pořadí UseCors a UseStaticFiles
Pořadí volání UseCors
a UseStaticFiles
závisí na aplikaci. Další informace najdete v pořadí UseCors a UseStaticFiles
Pořadí middlewaru Forwarded Headers
Middleware Forwarded Headers by měl běžet před ostatním middlewarem. Toto řazení zajišťuje, že middleware, který spoléhá na informace z dopředných hlaviček, může využívat jejich hodnoty pro zpracování. Pokud chcete middleware Forwarded Headers spustit po diagnostice a middlewaru pro zpracování chyb, přečtěte si téma Middleware Ordered Headers.
Rozvětvení middleware kanálu
Rozšíření Map se používají jako konvence pro větvení kanálu.
Map
rozvětví požadavkový kanál na základě shody dané cesty požadavku. Pokud cesta žádosti začíná zadanou cestou, větev se spustí.
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");
});
}
Následující tabulka ukazuje požadavky a odpovědi z http://localhost:1234
s využitím předchozího kódu.
Požadavek | Reakce |
---|---|
localhost:1234 | Zdravím vás od delegáta mimo Mapu. |
localhost:1234/map1 | Test mapy 1 |
localhost:1234/map2 | Test mapy 2 |
localhost:1234/map3 | Zdravím vás od delegáta mimo Mapu. |
Při použití Map
se odpovídající segmenty cest odeberou z HttpRequest.Path
a připojí ke HttpRequest.PathBase
pro každý požadavek.
Map
podporuje vnoření, například:
app.Map("/level1", level1App => {
level1App.Map("/level2a", level2AApp => {
// "/level1/level2a" processing
});
level1App.Map("/level2b", level2BApp => {
// "/level1/level2b" processing
});
});
Map
také může odpovídat více segmentům najednou:
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 rozvětví kanál požadavku na základě výsledku daného predikátu. K mapování požadavků na novou větev kanálu je možné použít jakýkoli predikát typu Func<HttpContext, bool>
. V následujícím příkladu se predikát používá ke zjištění přítomnosti proměnné řetězce dotazu branch
:
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}");
});
}
Následující tabulka ukazuje požadavky a odpovědi z http://localhost:1234
s využitím předchozího kódu:
Požadavek | Reakce |
---|---|
localhost:1234 |
Hello from non-Map delegate. |
localhost:1234/?branch=main |
Branch used = main |
UseWhen také rozvětví kanál požadavku na základě výsledku daného predikátu. Na rozdíl od MapWhen
se tato větev znovu připojí k hlavnímu potrubí, pokud neobsahuje terminální middleware.
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.
});
}
V předchozím příkladu se pro všechny požadavky zapíše odpověď Hello from non-Map delegate.
. Pokud požadavek obsahuje proměnnou řetězce dotazu branch
, před opětovným připojením k hlavnímu kanálu se zaprotokoluje její hodnota.
Integrovaný middleware
ASP.NET Core se dodává s následujícími komponentami middlewaru. Sloupec Pořadí obsahuje poznámky k umístění middlewaru v kanálu zpracování požadavků a to, za jakých podmínek může middleware ukončit zpracování požadavků. Když middleware zkratuje kanál zpracování požadavků a zabrání dalšímu navazujícímu middlewaru zpracovat požadavek, označuje se jako terminální middleware. Další informace o zkratování najdete v části Vytvoření middlewarového kanálu s WebApplication.
Middleware | Popis | Objednávka |
---|---|---|
Ochrana proti padělání | Poskytuje podporu pro ochranu proti falšování požadavků. | Po ověření a autorizaci, předtím než se přejde ke koncovým bodům. |
Autentizace | Poskytuje podporu ověřování. | Než bude potřeba HttpContext.User . Terminál pro zpětné volání OAuth. |
Autorizace | Poskytuje podporu při autorizaci. | Okamžitě po middlewaru Authentication. |
Cookie Politika | Sleduje souhlas uživatelů s ukládáním osobních údajů a vynucuje minimální standardy pro pole cookie, například secure a SameSite . |
Než middleware začne vydávat soubory cookie. Příklady: Authentication, Session, MVC (TempData). |
CORS | Provádí konfiguraci sdílení prostředků mezi zdroji (CORS). | Před komponentami, které používají CORS.
UseCors v současné době musí předcházet před UseResponseCaching , a to kvůli této chybě. |
DeveloperExceptionPage | Vygeneruje stránku s informacemi o chybách, které jsou určené jenom pro použití ve vývojovém prostředí. | Před komponentami, které generují chyby. Pokud je prostředí ve vývoji, šablony projektů automaticky zaregistrují tento middleware jako první middleware v pipeline. |
Diagnostika | Několik samostatných middlewarů, které poskytují stránku výjimek pro vývojáře, zpracování výjimek, stránky stavových kódů a výchozí webovou stránku pro nové aplikace. | Před komponentami, které generují chyby. Terminál pro výjimky nebo obsluhu výchozí webové stránky pro nové aplikace. |
Přesměrované hlavičky | Přesměruje přeposílané hlavičky na aktuální požadavek. | Před komponentami, které využívají aktualizovaná pole. Příklady: Schéma, hostitel, IP adresa klienta, metoda. |
Kontrola stavu | Kontroluje stav aplikace ASP.NET Core a jejích závislostí, jako je kontrola dostupnosti databáze. | Terminál, pokud požadavek odpovídá koncovému bodu kontroly stavu. |
Šíření protokolových hlaviček | Šíří hlavičky HTTP z příchozího požadavku do odchozích požadavků klienta HTTP. | |
Protokolování HTTP | Protokoluje požadavky HTTP a odpovědi. | Na začátku potrubí middlewaru. |
Přepsání metody HTTP | Umožňuje, aby příchozí požadavek POST změnil metodu. | Před komponentami, které využívají aktualizovanou metodu. |
Přesměrování HTTPS | Přesměruje všechny požadavky HTTP na HTTPS. | Před komponentami, které využívají danou adresu URL. |
Zabezpečení striktního přenosu HTTP (HSTS) | Middleware pro vylepšení zabezpečení, který přidává speciální hlavičku odpovědi. | Před odesláním odpovědí a po komponentách, které upravují požadavky. Příklady: Přeposílané hlavičky, přepsání adresy URL. |
MVC | Zpracovává požadavky s využitím MVC / Razor Pages. | Terminál, pokud požadavek odpovídá trase. |
OWIN | Interoperabilita s aplikacemi, servery a middlewarem založenými na OWIN. | Terminál, pokud middleware OWIN plně zpracuje daný požadavek. |
Ukládání výstupu do mezipaměti | Poskytuje podporu pro ukládání odpovědí do mezipaměti na základě konfigurace. | Před komponentami, které vyžadují cacheování. Je potřeba použít UseRouting před UseOutputCaching . Je potřeba použít UseCORS před UseOutputCaching . |
Ukládání odpovědí do mezipaměti | Poskytuje podporu pro ukládání odpovědí do mezipaměti. To vyžaduje, aby klientská účast fungovala. K úplnému řízení serveru použijte ukládání výstupu do mezipaměti. | Před komponentami, které vyžadují cacheování. Je potřeba použít UseCORS před UseResponseCaching . Aplikace uživatelského rozhraní, jako jsou například Razor Pages, obvykle nebývají užitečné, protože prohlížeče obvykle nastavují hlavičky požadavků, které brání ukládání do mezipaměti.
Ukládání výstupu do mezipaměti přináší výhody aplikací uživatelského rozhraní. |
Vyžádat dekompresi | Poskytuje podporu pro dekompresi požadavků. | Před komponentami, které čtou text požadavku. |
Komprese odpovědí | Poskytuje podporu pro kompresi odpovědí. | Před komponentami, které vyžadují kompresi. |
Žádost o lokalizaci | Poskytuje podporu lokalizace. | Před komponentami citlivými na lokalizaci. Při použití RouteDataRequestCultureProvider musí následovat po middlewaru Routing. |
Časové limity požadavků | Poskytuje podporu pro konfiguraci časových limitů požadavků, globálního a koncového bodu. |
UseRequestTimeouts musí přijít po UseExceptionHandler , UseDeveloperExceptionPage a UseRouting . |
Směrování koncového bodu | Definuje a omezuje trasy požadavků. | Terminál pro vyhovující trasy. |
LÁZNĚ | Zpracovává všechny požadavky od tohoto bodu v řetězci middlewaru vrácením výchozí stránky pro jednostránkovou aplikaci (SPA). | Na konci řetězce, aby mělo přednost ostatní middleware pro obsluhu statických souborů, akcí MVC atd. |
Sezení | Poskytuje podporu pro správu uživatelských relací. | Před komponentami, které vyžadují Session. |
Statické soubory | Poskytuje podporu pro obsluhu statických souborů a procházení adresářů. | Terminál, pokud požadavek odpovídá souboru. |
Přepsání adresy URL | Poskytuje podporu pro přepis adres URL a přesměrování požadavků. | Před komponentami, které využívají danou adresu URL. |
W3CLogging | Generuje protokoly přístupu k serveru v rozšířeném formátu souborů protokolu W3C. | Na začátku potrubí middlewaru. |
Webové sokety | Povoluje protokol WebSocket. | Před komponentami, které jsou nezbytné pro přijetí požadavků WebSocket. |
Další materiály
- Sekce Možnosti registrace a doba života obsahuje kompletní ukázku middlewaru se službami Scoped, Transient a Singleton.
- Psaní vlastního middlewaru ASP.NET Core
- Testování middlewaru ASP.NET Core
- Konfigurace gRPC-Web v ASP.NET Core
- Migrace modulů HTTP do middlewaru ASP.NET Core
- Spuštění aplikace v ASP.NET Core
- Funkce požadavků v ASP.NET Core
- Aktivace middlewaru na základě objektu pro vytváření v ASP.NET Core
- Aktivace middlewaru s využitím kontejneru třetí strany v ASP.NET Core
Autor: Rick Anderson a Steve Smith
Middleware je software sestavený do kanálu aplikace pro zpracování požadavků a odpovědí. Každá komponenta:
- Určuje, jestli se má požadavek předat další součásti v potrubí.
- Může provádět práci před a po další komponentě v řetězci.
K sestavení kanálu požadavků se používají delegáti požadavků. Delegáti požadavků zpracovávají každý požadavek HTTP.
Delegáti požadavků jsou konfigurováni pomocí rozšiřujících metod Run, Map a Use. Jednotlivý delegát požadavku může být zadán na řádku jako anonymní metoda (tzv. in-line middleware) nebo může být definován v opakovaně použitelné třídě. Tyto opakovaně použitelné třídy a vložené anonymní metody jsou middleware, označované také jako komponenty middlewaru. Každá komponenta middlewaru v kanálu požadavků zodpovídá za vyvolání další komponenty v kanálu nebo zkratování kanálu. Když middleware způsobí zkrat, označuje se jako terminální middleware, protože brání další middleware ve zpracování požadavku.
Migrace modulů HTTP do middlewaru ASP.NET Core vysvětluje rozdíl mezi kanály požadavků v ASP.NET Core a ASP.NET 4.x a poskytuje další ukázky middlewaru.
Role middlewaru podle typu aplikace
Razor Pages, MVC, Blazor Servera hostovaný projekt na straně serveru řešení Blazor WebAssembly, které zpracovává požadavky prohlížeče na serveru s middlewarem. Pokyny v tomto článku platí pro tyto typy aplikací.
Samostatné Blazor WebAssembly aplikace běží zcela na klientovi a nezpracují požadavky pomocí kanálu middlewaru. Pokyny v tomto článku se nevztahují na samostatné Blazor WebAssembly aplikace.
Analýza kódu middlewaru
ASP.NET Core obsahuje celou řadu analyzátorů Compile Platform, které kontrolují kód aplikace z hlediska kvality. Další informace najdete v tématu Analýza kódu v aplikacích ASP.NET Core.
Vytvoření kanálu middlewaru s využitím WebApplication
Kanál požadavků v ASP.NET Core se skládá z posloupnosti delegátů požadavků, kteří se volají postupně. Tento koncept demonstruje následující schéma. Vlákno spouštění postupuje podle černých šipek.
Každý delegát může provádět operace před a za dalším delegátem. Delegáti zpracování výjimek by se měli volat v počátečních fázích řetězce, aby mohli zachytit výjimky, ke kterým dochází v pozdějších fázích řetězce.
Nejjednodušší možná aplikace ASP.NET Core nastavuje jednoho delegáta požadavků, který zpracovává všechny požadavky. Tento případ nezahrnuje vlastní kanál požadavků. Místo toho se jako reakce na každý požadavek HTTP volá jedna anonymní funkce.
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
app.Run(async context =>
{
await context.Response.WriteAsync("Hello world!");
});
app.Run();
Propojte více delegátů požadavků pomocí Use. Parametr next
představuje dalšího delegáta v potrubí. Kanál můžete zkratovat tím, že nezavoláte parametr next
. Obvykle můžete provádět akce před delegátem next
i po něm, jak ukazuje následující příklad:
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();
Pokud delegát nepředá požadavek dalšímu delegátovi, označuje se to jako přerušení kanálu požadavků. Zkratování je často žádoucí, protože zabraňuje zbytečné práci. Například middleware statického souboru může fungovat jako terminálový middleware zpracováním požadavku na statický soubor a přeskočením zbytku zpracování. Middleware přidaný do kanálu před middleware, který ukončí další zpracování, stále zpracovává kód po příslušných příkazech next.Invoke
. Ohledně pokusu o zápis do již odeslané odpovědi si však projděte následující upozornění.
Varování
Po odeslání odpovědi klientovi nevolejte next.Invoke
. Změny v HttpResponse po spuštění odpovědi vyvolají výjimku. Například nastavení hlaviček a stavového kódu vyvolá výjimku. Zápis do textu odpovědi po volání next
:
- Může způsobit porušení protokolu. Příklad: Delší zápis, než je stanovená délka
Content-Length
. - Může poškodit formát textu. Příklad: Zápis zápatí HTML do souboru CSS.
HasStarted je užitečná nápověda indikující, jestli byly odeslány hlavičky nebo zapisováno do textu.
Delegáti Run neobdrží parametr next
. První delegát Run
je vždy terminální a ukončí zpracovatelský řetězec. Použití Run
je obvyklá konvence. Některé komponenty middlewaru můžou zpřístupnit metody Run[Middleware]
, které běží na konci kanálu:
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();
Pokud chcete zobrazit komentáře ke kódu přeložené do jiných jazyků, než je angličtina, dejte nám vědět v této diskuzi na GitHubu.
V předchozím příkladu delegát Run
zapíše "Hello from 2nd delegate."
do odpovědi a pak ukončí kanál. Pokud je za delegáta Use
přidán jiný delegát Run
nebo Run
, nevolá se.
Preferujte přetížení metody app.Use, které vyžaduje předání kontextu dalšímu kroku
Rozšiřující metoda app.Use bez přidělování:
- Vyžaduje předání kontextu do
next
. - Šetří dvě alokace paměti na jednotlivé požadavky, které jsou vyžadovány při použití jiné přetížené funkce.
Další informace najdete u tohoto problému na GitHubu.
Pořadí middlewaru
Následující diagram znázorňuje kompletní kanál zpracování požadavků pro aplikace ASP.NET Core MVC a Razor Pages. Můžete si prohlédnout, jak je v typické aplikaci uspořádané stávající middlewary seřazené a kde se přidávají vlastní middlewary. Máte plnou kontrolu nad tím, jak změnit pořadí stávajících middlewarů nebo vložit nové vlastní middlewary podle potřeby vašich scénářů.
Middleware Endpoint v předchozím diagramu spustí kanál filtru pro odpovídající typ aplikace – MVC nebo Razor Pages.
Middleware Routing v předchozím diagramu je zobrazený za statickými soubory. Toto je pořadí, které šablony projektů implementují explicitním voláním app.UseRouting. Pokud nezavoláte app.UseRouting
, ve výchozím nastavení se middleware Routing spustí na začátku kanálu. Další informace najdete v tématu Směrování.
Pořadí, ve kterém jsou komponenty middlewaru přidány do souboru Program.cs
, definuje pořadí, ve kterém se komponenty middlewaru vyvolávají pro požadavky, a obrácené pořadí pro odpovědi. Toto pořadí má zásadní důležitost pro zabezpečení, výkon a funkce.
Následující zvýrazněný kód v Program.cs
přidává komponenty middlewaru související se zabezpečením v typickém doporučeném pořadí:
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();
V předchozím kódu:
- Middleware, který se nepřidá při vytváření nové webové aplikace s účty jednotlivých uživatelů, je zakomentovaný.
- Ne každý middleware se objevuje přesně v tomto pořadí, ale mnoho z nich ano. Příklad:
-
UseCors
,UseAuthentication
aUseAuthorization
musí být v uvedeném pořadí. -
UseCors
musí aktuálně být předUseResponseCaching
. Tento požadavek je vysvětlený v problému s dotnet/aspnetcore #23218 na GitHubu. -
UseRequestLocalization
musí se objevit před jakýmkoli middlewarem, který může zkontrolovat jazykovou verzi požadavku, napříkladapp.UseStaticFiles()
. -
UseRateLimiter musí být volána po
UseRouting
, když se používají rozhraní API pro omezení rychlosti pro konkrétní koncové body. Pokud je například atribut[EnableRateLimiting]
použit,UseRateLimiter
musí být zavolána poUseRouting
. Při volání pouze globálních limiterůUseRateLimiter
může být volán předUseRouting
.
-
V některých scénářích má middleware jiné řazení. Například pořadí ukládání do mezipaměti a komprese je specifické pro daný scénář a existuje několik platných pořadí. Příklad:
app.UseResponseCaching();
app.UseResponseCompression();
V předchozím kódu by bylo možné snížit využití procesoru uložením komprimované odpovědi do mezipaměti, ale mohlo by se stát, že budete ukládat do mezipaměti více reprezentací prostředku pomocí různých kompresních algoritmů, jako jsou například Gzip nebo Brotli.
Následující pořadí kombinuje statické soubory, aby se umožnilo ukládání komprimovaných statických souborů do mezipaměti:
app.UseResponseCaching();
app.UseResponseCompression();
app.UseStaticFiles();
Následující kód Program.cs
přidá komponenty middlewaru pro běžné scénáře aplikací:
- Zpracování výjimek nebo chyb
- Když se aplikace spustí ve vývojovém prostředí:
- Middleware Developer Exception Page (UseDeveloperExceptionPage) hlásí běhové chyby aplikací.
- Middleware Database Error Page (UseDatabaseErrorPage) hlásí běhové chyby databází.
- Když se aplikace spustí v produkčním prostředí:
- Middleware Exception Handler (UseExceptionHandler) zachycuje výjimky vyvolané v následujících middlewarech.
- Middleware HSTS (HTTP Strict Transport Security Protocol) (UseHsts) přidává hlavičku
Strict-Transport-Security
.
- Když se aplikace spustí ve vývojovém prostředí:
- Middleware HTTPS Redirection (UseHttpsRedirection) přesměruje požadavky HTTP na HTTPS.
- Middleware pro statické soubory (UseStaticFiles) vrací statické soubory a přeruší další zpracování požadavků.
- Middleware Cookie Policy (UseCookiePolicy) zajišťuje soulad aplikace s Obecným nařízením EU o ochraně osobních údajů (GDPR).
- Routing Middleware (UseRouting) slouží ke směrování požadavků.
- Middleware Authentication (UseAuthentication) se pokusí ověřit uživatele předtím, než se mu povolí přístup k zabezpečeným prostředkům.
- Autorizační Middleware (UseAuthorization) opravňuje uživatele ke vstupu do zabezpečených prostředků.
- Session Middleware (UseSession) nastavuje a udržuje stav relace. Pokud aplikace používá stav relace, volejte middleware Session za middlewarem Cookie Policy a před middlewarem MVC.
- Middleware Endpoint Routing (UseEndpoints s MapRazorPages) slouží pro přidání koncových bodů Razor Pages do kanálu požadavků.
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();
V předchozím ukázkovém kódu je každá rozšiřující metoda middlewaru zpřístupněná v WebApplicationBuilder prostřednictvím oboru názvů Microsoft.AspNetCore.Builder.
UseExceptionHandler je první middleware komponenta přidaná do potrubí. Proto middleware Exception Handler zachycuje všechny výjimky, ke kterým dochází v pozdějších voláních.
Middleware Static File se volá v rané fázi zpracování kanálu, aby mohl zpracovávat požadavky a provést zkratování, aniž by se musely projít zbývající komponenty. Middleware Static File neposkytuje žádné kontroly autorizace. Všechny soubory obsluhované middlewarem Static File, včetně souborů pod wwwroot, jsou veřejně dostupné. Informace o přístupu k zabezpečení statických souborů najdete v tématu Statické soubory v ASP.NET Core.
Pokud požadavek nezpracuje middleware Static File, předá se do middlewaru Authentication (UseAuthentication), který provádí ověřování. Ověřování nezpůsobí přeskočení neověřených požadavků. I když Middleware Authentication ověřuje požadavky, autorizace (a zamítnutí) nastane až poté, co MVC vybere konkrétní Razor stránku nebo kontroler MVC a akci.
Následující příklad ukazuje pořadí middlewaru, ve kterém požadavky pro statické soubory zpracovává middleware Static File před middlewarem Response Compression. Statické soubory nejsou při tomto uspořádání middlewaru komprimovány. Odpovědi Razor Pages je možné komprimovat.
// Static files aren't compressed by Static File Middleware.
app.UseStaticFiles();
app.UseRouting();
app.UseResponseCompression();
app.MapRazorPages();
Informace o jednostránkových aplikacích najdete v průvodcích pro šablony projektů React a Angular.
Pořadí UseCors a UseStaticFiles
Pořadí volání UseCors
a UseStaticFiles
závisí na aplikaci. Další informace najdete v pořadí UseCors a UseStaticFiles
Pořadí middlewaru Forwarded Headers
Middleware Forwarded Headers by měl běžet před ostatním middlewarem. Toto řazení zajišťuje, že middleware, který spoléhá na informace z dopředných hlaviček, může využívat jejich hodnoty pro zpracování. Pokud chcete middleware Forwarded Headers spustit po diagnostice a middlewaru pro zpracování chyb, přečtěte si téma Middleware Ordered Headers.
Rozvětvení middleware kanálu
Rozšíření Map se používají jako konvence pro větvení kanálu.
Map
rozvětví požadavkový kanál na základě shody dané cesty požadavku. Pokud cesta žádosti začíná zadanou cestou, větev se spustí.
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");
});
}
Následující tabulka ukazuje požadavky a odpovědi z http://localhost:1234
s využitím předchozího kódu.
Požadavek | Reakce |
---|---|
localhost:1234 | Zdravím vás od delegáta mimo Mapu. |
localhost:1234/map1 | Test mapy 1 |
localhost:1234/map2 | Test mapy 2 |
localhost:1234/map3 | Zdravím vás od delegáta mimo Mapu. |
Při použití Map
se odpovídající segmenty cest odeberou z HttpRequest.Path
a připojí ke HttpRequest.PathBase
pro každý požadavek.
Map
podporuje vnoření, například:
app.Map("/level1", level1App => {
level1App.Map("/level2a", level2AApp => {
// "/level1/level2a" processing
});
level1App.Map("/level2b", level2BApp => {
// "/level1/level2b" processing
});
});
Map
také může odpovídat více segmentům najednou:
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 rozvětví kanál požadavku na základě výsledku daného predikátu. K mapování požadavků na novou větev kanálu je možné použít jakýkoli predikát typu Func<HttpContext, bool>
. V následujícím příkladu se predikát používá ke zjištění přítomnosti proměnné řetězce dotazu branch
:
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}");
});
}
Následující tabulka ukazuje požadavky a odpovědi z http://localhost:1234
s využitím předchozího kódu:
Požadavek | Reakce |
---|---|
localhost:1234 |
Hello from non-Map delegate. |
localhost:1234/?branch=main |
Branch used = main |
UseWhen také rozvětví kanál požadavku na základě výsledku daného predikátu. Na rozdíl od MapWhen
se tato větev znovu připojí k hlavnímu kanálu, pokud nezpůsobí zkratování nebo neobsahuje terminální middleware:
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.
});
}
V předchozím příkladu se pro všechny požadavky zapíše odpověď Hello from non-Map delegate.
. Pokud požadavek obsahuje proměnnou řetězce dotazu branch
, před opětovným připojením k hlavnímu kanálu se zaprotokoluje její hodnota.
Integrovaný middleware
ASP.NET Core se dodává s následujícími komponentami middlewaru. Sloupec Pořadí obsahuje poznámky k umístění middlewaru v kanálu zpracování požadavků a to, za jakých podmínek může middleware ukončit zpracování požadavků. Když middleware zkratuje kanál zpracování požadavků a zabrání dalšímu navazujícímu middlewaru zpracovat požadavek, označuje se jako terminální middleware. Další informace o zkratování najdete v části Vytvoření middlewarového kanálu s WebApplication.
Middleware | Popis | Objednávka |
---|---|---|
Autentizace | Poskytuje podporu ověřování. | Než bude potřeba HttpContext.User . Terminál pro zpětné volání OAuth. |
Autorizace | Poskytuje podporu při autorizaci. | Okamžitě po middlewaru Authentication. |
Cookie Politika | Sleduje souhlas uživatelů s ukládáním osobních údajů a vynucuje minimální standardy pro pole cookie, například secure a SameSite . |
Než middleware začne vydávat soubory cookie. Příklady: Authentication, Session, MVC (TempData). |
CORS | Provádí konfiguraci sdílení prostředků mezi zdroji (CORS). | Před komponentami, které používají CORS.
UseCors v současné době musí předcházet před UseResponseCaching , a to kvůli této chybě. |
DeveloperExceptionPage | Vygeneruje stránku s informacemi o chybách, které jsou určené jenom pro použití ve vývojovém prostředí. | Před komponentami, které generují chyby. Pokud je prostředí ve vývoji, šablony projektů automaticky zaregistrují tento middleware jako první middleware v pipeline. |
Diagnostika | Několik samostatných middlewarů, které poskytují stránku výjimek pro vývojáře, zpracování výjimek, stránky stavových kódů a výchozí webovou stránku pro nové aplikace. | Před komponentami, které generují chyby. Terminál pro výjimky nebo obsluhu výchozí webové stránky pro nové aplikace. |
Přesměrované hlavičky | Přesměruje přeposílané hlavičky na aktuální požadavek. | Před komponentami, které využívají aktualizovaná pole. Příklady: Schéma, hostitel, IP adresa klienta, metoda. |
Kontrola stavu | Kontroluje stav aplikace ASP.NET Core a jejích závislostí, jako je kontrola dostupnosti databáze. | Terminál, pokud požadavek odpovídá koncovému bodu kontroly stavu. |
Šíření protokolových hlaviček | Šíří hlavičky HTTP z příchozího požadavku do odchozích požadavků klienta HTTP. | |
Protokolování HTTP | Protokoluje požadavky HTTP a odpovědi. | Na začátku potrubí middlewaru. |
Přepsání metody HTTP | Umožňuje, aby příchozí požadavek POST změnil metodu. | Před komponentami, které využívají aktualizovanou metodu. |
Přesměrování HTTPS | Přesměruje všechny požadavky HTTP na HTTPS. | Před komponentami, které využívají danou adresu URL. |
Zabezpečení striktního přenosu HTTP (HSTS) | Middleware pro vylepšení zabezpečení, který přidává speciální hlavičku odpovědi. | Před odesláním odpovědí a po komponentách, které upravují požadavky. Příklady: Přeposílané hlavičky, přepsání adresy URL. |
MVC | Zpracovává požadavky s využitím MVC / Razor Pages. | Terminál, pokud požadavek odpovídá trase. |
OWIN | Interoperabilita s aplikacemi, servery a middlewarem založenými na OWIN. | Terminál, pokud middleware OWIN plně zpracuje daný požadavek. |
Ukládání výstupu do mezipaměti | Poskytuje podporu pro ukládání odpovědí do mezipaměti na základě konfigurace. | Před komponentami, které vyžadují cacheování. Je potřeba použít UseRouting před UseOutputCaching . Je potřeba použít UseCORS před UseOutputCaching . |
Ukládání odpovědí do mezipaměti | Poskytuje podporu pro ukládání odpovědí do mezipaměti. To vyžaduje, aby klientská účast fungovala. K úplnému řízení serveru použijte ukládání výstupu do mezipaměti. | Před komponentami, které vyžadují cacheování. Je potřeba použít UseCORS před UseResponseCaching . Aplikace uživatelského rozhraní, jako jsou například Razor Pages, obvykle nebývají užitečné, protože prohlížeče obvykle nastavují hlavičky požadavků, které brání ukládání do mezipaměti.
Ukládání výstupu do mezipaměti přináší výhody aplikací uživatelského rozhraní. |
Vyžádat dekompresi | Poskytuje podporu pro dekompresi požadavků. | Před komponentami, které čtou text požadavku. |
Komprese odpovědí | Poskytuje podporu pro kompresi odpovědí. | Před komponentami, které vyžadují kompresi. |
Žádost o lokalizaci | Poskytuje podporu lokalizace. | Před komponentami citlivými na lokalizaci. Při použití RouteDataRequestCultureProvider musí následovat po middlewaru Routing. |
Směrování koncového bodu | Definuje a omezuje trasy požadavků. | Terminál pro vyhovující trasy. |
LÁZNĚ | Zpracovává všechny požadavky od tohoto bodu v řetězci middlewaru vrácením výchozí stránky pro jednostránkovou aplikaci (SPA). | Na konci řetězce, aby mělo přednost ostatní middleware pro obsluhu statických souborů, akcí MVC atd. |
Sezení | Poskytuje podporu pro správu uživatelských relací. | Před komponentami, které vyžadují Session. |
Statické soubory | Poskytuje podporu pro obsluhu statických souborů a procházení adresářů. | Terminál, pokud požadavek odpovídá souboru. |
Přepsání adresy URL | Poskytuje podporu pro přepis adres URL a přesměrování požadavků. | Před komponentami, které využívají danou adresu URL. |
W3CLogging | Generuje protokoly přístupu k serveru v rozšířeném formátu souborů protokolu W3C. | Na začátku potrubí middlewaru. |
Webové sokety | Povoluje protokol WebSocket. | Před komponentami, které jsou nezbytné pro přijetí požadavků WebSocket. |
Další materiály
- Sekce Možnosti registrace a doba života obsahuje kompletní ukázku middlewaru se službami Scoped, Transient a Singleton.
- Psaní vlastního middlewaru ASP.NET Core
- Testování middlewaru ASP.NET Core
- Konfigurace gRPC-Web v ASP.NET Core
- Migrace modulů HTTP do middlewaru ASP.NET Core
- Spuštění aplikace v ASP.NET Core
- Funkce požadavků v ASP.NET Core
- Aktivace middlewaru na základě objektu pro vytváření v ASP.NET Core
- Aktivace middlewaru s využitím kontejneru třetí strany v ASP.NET Core
Autor: Rick Anderson a Steve Smith
Middleware je software sestavený do kanálu aplikace pro zpracování požadavků a odpovědí. Každá komponenta:
- Určuje, jestli se má požadavek předat další součásti v potrubí.
- Může provádět práci před a po další komponentě v řetězci.
K sestavení kanálu požadavků se používají delegáti požadavků. Delegáti požadavků zpracovávají každý požadavek HTTP.
Delegáti požadavků jsou konfigurováni pomocí rozšiřujících metod Run, Map a Use. Jednotlivý delegát požadavku může být zadán na řádku jako anonymní metoda (tzv. in-line middleware) nebo může být definován v opakovaně použitelné třídě. Tyto opakovaně použitelné třídy a vložené anonymní metody jsou middleware, označované také jako komponenty middlewaru. Každá komponenta middlewaru v kanálu požadavků zodpovídá za vyvolání další komponenty v kanálu nebo zkratování kanálu. Když middleware způsobí zkrat, označuje se jako terminální middleware, protože brání další middleware ve zpracování požadavku.
Migrace modulů HTTP do middlewaru ASP.NET Core vysvětluje rozdíl mezi kanály požadavků v ASP.NET Core a ASP.NET 4.x a poskytuje další ukázky middlewaru.
Analýza kódu middlewaru
ASP.NET Core obsahuje celou řadu analyzátorů Compile Platform, které kontrolují kód aplikace z hlediska kvality. Další informace najdete v tématu Analýza kódu v aplikacích ASP.NET Core.
Vytvoření kanálu middlewaru s využitím WebApplication
Kanál požadavků v ASP.NET Core se skládá z posloupnosti delegátů požadavků, kteří se volají postupně. Tento koncept demonstruje následující schéma. Vlákno spouštění postupuje podle černých šipek.
Každý delegát může provádět operace před a za dalším delegátem. Delegáti zpracování výjimek by se měli volat v počátečních fázích řetězce, aby mohli zachytit výjimky, ke kterým dochází v pozdějších fázích řetězce.
Nejjednodušší možná aplikace ASP.NET Core nastavuje jednoho delegáta požadavků, který zpracovává všechny požadavky. Tento případ nezahrnuje vlastní kanál požadavků. Místo toho se jako reakce na každý požadavek HTTP volá jedna anonymní funkce.
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
app.Run(async context =>
{
await context.Response.WriteAsync("Hello world!");
});
app.Run();
Propojte více delegátů požadavků pomocí Use. Parametr next
představuje dalšího delegáta v potrubí. Kanál můžete zkratovat tím, že nezavoláte parametr next
. Obvykle můžete provádět akce před delegátem next
i po něm, jak ukazuje následující příklad:
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();
Pokud delegát nepředá požadavek dalšímu delegátovi, označuje se to jako přerušení kanálu požadavků. Zkratování je často žádoucí, protože zabraňuje zbytečné práci. Například middleware statického souboru může fungovat jako terminálový middleware zpracováním požadavku na statický soubor a přeskočením zbytku zpracování. Middleware přidaný do kanálu před middleware, který ukončí další zpracování, stále zpracovává kód po příslušných příkazech next.Invoke
. Ohledně pokusu o zápis do již odeslané odpovědi si však projděte následující upozornění.
Varování
Po odeslání odpovědi klientovi nevolejte next.Invoke
. Změny v HttpResponse po spuštění odpovědi vyvolají výjimku. Například nastavení hlaviček a stavového kódu vyvolá výjimku. Zápis do textu odpovědi po volání next
:
- Může způsobit porušení protokolu. Příklad: Delší zápis, než je stanovená délka
Content-Length
. - Může poškodit formát textu. Příklad: Zápis zápatí HTML do souboru CSS.
HasStarted je užitečná nápověda indikující, jestli byly odeslány hlavičky nebo zapisováno do textu.
Delegáti Run neobdrží parametr next
. První delegát Run
je vždy terminální a ukončí zpracovatelský řetězec. Použití Run
je obvyklá konvence. Některé komponenty middlewaru můžou zpřístupnit metody Run[Middleware]
, které běží na konci kanálu:
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();
Pokud chcete zobrazit komentáře ke kódu přeložené do jiných jazyků, než je angličtina, dejte nám vědět v této diskuzi na GitHubu.
V předchozím příkladu delegát Run
zapíše "Hello from 2nd delegate."
do odpovědi a pak ukončí kanál. Pokud je za delegáta Use
přidán jiný delegát Run
nebo Run
, nevolá se.
Preferujte přetížení metody app.Use, které vyžaduje předání kontextu dalšímu kroku
Rozšiřující metoda app.Use bez přidělování:
- Vyžaduje předání kontextu do
next
. - Šetří dvě alokace paměti na jednotlivé požadavky, které jsou vyžadovány při použití jiné přetížené funkce.
Další informace najdete u tohoto problému na GitHubu.
Pořadí middlewaru
Následující diagram znázorňuje kompletní kanál zpracování požadavků pro aplikace ASP.NET Core MVC a Razor Pages. Můžete si prohlédnout, jak je v typické aplikaci uspořádané stávající middlewary seřazené a kde se přidávají vlastní middlewary. Máte plnou kontrolu nad tím, jak změnit pořadí stávajících middlewarů nebo vložit nové vlastní middlewary podle potřeby vašich scénářů.
Middleware Endpoint v předchozím diagramu spustí kanál filtru pro odpovídající typ aplikace – MVC nebo Razor Pages.
Middleware Routing v předchozím diagramu je zobrazený za statickými soubory. Toto je pořadí, které šablony projektů implementují explicitním voláním app.UseRouting. Pokud nezavoláte app.UseRouting
, ve výchozím nastavení se middleware Routing spustí na začátku kanálu. Další informace najdete v tématu Směrování.
Pořadí, ve kterém jsou komponenty middlewaru přidány do souboru Program.cs
, definuje pořadí, ve kterém se komponenty middlewaru vyvolávají pro požadavky, a obrácené pořadí pro odpovědi. Toto pořadí má zásadní důležitost pro zabezpečení, výkon a funkce.
Následující zvýrazněný kód v Program.cs
přidává komponenty middlewaru související se zabezpečením v typickém doporučeném pořadí:
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();
V předchozím kódu:
- Middleware, který se nepřidá při vytváření nové webové aplikace s účty jednotlivých uživatelů, je zakomentovaný.
- Ne každý middleware se objevuje přesně v tomto pořadí, ale mnoho z nich ano. Příklad:
-
UseCors
,UseAuthentication
aUseAuthorization
musí být v uvedeném pořadí. -
UseCors
musí aktuálně být předUseResponseCaching
. Tento požadavek je vysvětlený v problému s dotnet/aspnetcore #23218 na GitHubu. -
UseRequestLocalization
musí být uvedený před jakýmkoli jiným middlewarem, který kontroluje kulturu požadavků (napříkladapp.UseMvcWithDefaultRoute()
).
-
V některých scénářích má middleware jiné řazení. Například pořadí ukládání do mezipaměti a komprese je specifické pro daný scénář a existuje několik platných pořadí. Příklad:
app.UseResponseCaching();
app.UseResponseCompression();
V předchozím kódu by bylo možné snížit využití procesoru uložením komprimované odpovědi do mezipaměti, ale mohlo by se stát, že budete ukládat do mezipaměti více reprezentací prostředku pomocí různých kompresních algoritmů, jako jsou například Gzip nebo Brotli.
Následující pořadí kombinuje statické soubory, aby se umožnilo ukládání komprimovaných statických souborů do mezipaměti:
app.UseResponseCaching();
app.UseResponseCompression();
app.UseStaticFiles();
Následující kód Program.cs
přidá komponenty middlewaru pro běžné scénáře aplikací:
- Zpracování výjimek nebo chyb
- Když se aplikace spustí ve vývojovém prostředí:
- Middleware Developer Exception Page (UseDeveloperExceptionPage) hlásí běhové chyby aplikací.
- Middleware Database Error Page (UseDatabaseErrorPage) hlásí běhové chyby databází.
- Když se aplikace spustí v produkčním prostředí:
- Middleware Exception Handler (UseExceptionHandler) zachycuje výjimky vyvolané v následujících middlewarech.
- Middleware HSTS (HTTP Strict Transport Security Protocol) (UseHsts) přidává hlavičku
Strict-Transport-Security
.
- Když se aplikace spustí ve vývojovém prostředí:
- Middleware HTTPS Redirection (UseHttpsRedirection) přesměruje požadavky HTTP na HTTPS.
- Middleware pro statické soubory (UseStaticFiles) vrací statické soubory a přeruší další zpracování požadavků.
- Middleware Cookie Policy (UseCookiePolicy) zajišťuje soulad aplikace s Obecným nařízením EU o ochraně osobních údajů (GDPR).
- Routing Middleware (UseRouting) slouží ke směrování požadavků.
- Middleware Authentication (UseAuthentication) se pokusí ověřit uživatele předtím, než se mu povolí přístup k zabezpečeným prostředkům.
- Autorizační Middleware (UseAuthorization) opravňuje uživatele ke vstupu do zabezpečených prostředků.
- Session Middleware (UseSession) nastavuje a udržuje stav relace. Pokud aplikace používá stav relace, volejte middleware Session za middlewarem Cookie Policy a před middlewarem MVC.
- Middleware Endpoint Routing (UseEndpoints s MapRazorPages) slouží pro přidání koncových bodů Razor Pages do kanálu požadavků.
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();
V předchozím ukázkovém kódu je každá rozšiřující metoda middlewaru zpřístupněná v WebApplicationBuilder prostřednictvím oboru názvů Microsoft.AspNetCore.Builder.
UseExceptionHandler je první middleware komponenta přidaná do potrubí. Proto middleware Exception Handler zachycuje všechny výjimky, ke kterým dochází v pozdějších voláních.
Middleware Static File se volá v rané fázi zpracování kanálu, aby mohl zpracovávat požadavky a provést zkratování, aniž by se musely projít zbývající komponenty. Middleware Static File neposkytuje žádné kontroly autorizace. Všechny soubory obsluhované middlewarem Static File, včetně souborů pod wwwroot, jsou veřejně dostupné. Informace o přístupu k zabezpečení statických souborů najdete v tématu Statické soubory v ASP.NET Core.
Pokud požadavek nezpracuje middleware Static File, předá se do middlewaru Authentication (UseAuthentication), který provádí ověřování. Ověřování nezpůsobí přeskočení neověřených požadavků. I když Middleware Authentication ověřuje požadavky, autorizace (a zamítnutí) nastane až poté, co MVC vybere konkrétní Razor stránku nebo kontroler MVC a akci.
Následující příklad ukazuje pořadí middlewaru, ve kterém požadavky pro statické soubory zpracovává middleware Static File před middlewarem Response Compression. Statické soubory nejsou při tomto uspořádání middlewaru komprimovány. Odpovědi Razor Pages je možné komprimovat.
// Static files aren't compressed by Static File Middleware.
app.UseStaticFiles();
app.UseRouting();
app.UseResponseCompression();
app.MapRazorPages();
Informace o jednostránkových aplikacích najdete v průvodcích pro šablony projektů React a Angular.
Pořadí UseCors a UseStaticFiles
Pořadí volání UseCors
a UseStaticFiles
závisí na aplikaci. Další informace najdete v pořadí UseCors a UseStaticFiles
Pořadí middlewaru Forwarded Headers
Middleware Forwarded Headers by měl běžet před ostatním middlewarem. Toto řazení zajišťuje, že middleware, který spoléhá na informace z dopředných hlaviček, může využívat jejich hodnoty pro zpracování. Pokud chcete middleware Forwarded Headers spustit po diagnostice a middlewaru pro zpracování chyb, přečtěte si téma Middleware Ordered Headers.
Rozvětvení middleware kanálu
Rozšíření Map se používají jako konvence pro větvení kanálu.
Map
rozvětví požadavkový kanál na základě shody dané cesty požadavku. Pokud cesta žádosti začíná zadanou cestou, větev se spustí.
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");
});
}
Následující tabulka ukazuje požadavky a odpovědi z http://localhost:1234
s využitím předchozího kódu.
Požadavek | Reakce |
---|---|
localhost:1234 | Zdravím vás od delegáta mimo Mapu. |
localhost:1234/map1 | Test mapy 1 |
localhost:1234/map2 | Test mapy 2 |
localhost:1234/map3 | Zdravím vás od delegáta mimo Mapu. |
Při použití Map
se odpovídající segmenty cest odeberou z HttpRequest.Path
a připojí ke HttpRequest.PathBase
pro každý požadavek.
Map
podporuje vnoření, například:
app.Map("/level1", level1App => {
level1App.Map("/level2a", level2AApp => {
// "/level1/level2a" processing
});
level1App.Map("/level2b", level2BApp => {
// "/level1/level2b" processing
});
});
Map
také může odpovídat více segmentům najednou:
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 rozvětví kanál požadavku na základě výsledku daného predikátu. K mapování požadavků na novou větev kanálu je možné použít jakýkoli predikát typu Func<HttpContext, bool>
. V následujícím příkladu se predikát používá ke zjištění přítomnosti proměnné řetězce dotazu branch
:
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}");
});
}
Následující tabulka ukazuje požadavky a odpovědi z http://localhost:1234
s využitím předchozího kódu:
Požadavek | Reakce |
---|---|
localhost:1234 |
Hello from non-Map delegate. |
localhost:1234/?branch=main |
Branch used = main |
UseWhen také rozvětví kanál požadavku na základě výsledku daného predikátu. Na rozdíl od MapWhen
se tato větev znovu připojí k hlavnímu kanálu, pokud nezpůsobí zkratování nebo neobsahuje terminální middleware:
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.
});
}
V předchozím příkladu se pro všechny požadavky zapíše odpověď Hello from non-Map delegate.
. Pokud požadavek obsahuje proměnnou řetězce dotazu branch
, před opětovným připojením k hlavnímu kanálu se zaprotokoluje její hodnota.
Integrovaný middleware
ASP.NET Core se dodává s následujícími komponentami middlewaru. Sloupec Pořadí obsahuje poznámky k umístění middlewaru v kanálu zpracování požadavků a to, za jakých podmínek může middleware ukončit zpracování požadavků. Když middleware zkratuje kanál zpracování požadavků a zabrání dalšímu navazujícímu middlewaru zpracovat požadavek, označuje se jako terminální middleware. Další informace o zkratování najdete v části Vytvoření middlewarového kanálu s WebApplication.
Middleware | Popis | Objednávka |
---|---|---|
Autentizace | Poskytuje podporu ověřování. | Než bude potřeba HttpContext.User . Terminál pro zpětné volání OAuth. |
Autorizace | Poskytuje podporu při autorizaci. | Okamžitě po middlewaru Authentication. |
Cookie Politika | Sleduje souhlas uživatelů s ukládáním osobních údajů a vynucuje minimální standardy pro pole cookie, například secure a SameSite . |
Než middleware začne vydávat soubory cookie. Příklady: Authentication, Session, MVC (TempData). |
CORS | Provádí konfiguraci sdílení prostředků mezi zdroji (CORS). | Před komponentami, které používají CORS.
UseCors v současné době musí předcházet před UseResponseCaching , a to kvůli této chybě. |
DeveloperExceptionPage | Vygeneruje stránku s informacemi o chybách, které jsou určené jenom pro použití ve vývojovém prostředí. | Před komponentami, které generují chyby. Pokud je prostředí ve vývoji, šablony projektů automaticky zaregistrují tento middleware jako první middleware v pipeline. |
Diagnostika | Několik samostatných middlewarů, které poskytují stránku výjimek pro vývojáře, zpracování výjimek, stránky stavových kódů a výchozí webovou stránku pro nové aplikace. | Před komponentami, které generují chyby. Terminál pro výjimky nebo obsluhu výchozí webové stránky pro nové aplikace. |
Přesměrované hlavičky | Přesměruje přeposílané hlavičky na aktuální požadavek. | Před komponentami, které využívají aktualizovaná pole. Příklady: Schéma, hostitel, IP adresa klienta, metoda. |
Kontrola stavu | Kontroluje stav aplikace ASP.NET Core a jejích závislostí, jako je kontrola dostupnosti databáze. | Terminál, pokud požadavek odpovídá koncovému bodu kontroly stavu. |
Šíření protokolových hlaviček | Šíří hlavičky HTTP z příchozího požadavku do odchozích požadavků klienta HTTP. | |
Protokolování HTTP | Protokoluje požadavky HTTP a odpovědi. | Na začátku potrubí middlewaru. |
Přepsání metody HTTP | Umožňuje, aby příchozí požadavek POST změnil metodu. | Před komponentami, které využívají aktualizovanou metodu. |
Přesměrování HTTPS | Přesměruje všechny požadavky HTTP na HTTPS. | Před komponentami, které využívají danou adresu URL. |
Zabezpečení striktního přenosu HTTP (HSTS) | Middleware pro vylepšení zabezpečení, který přidává speciální hlavičku odpovědi. | Před odesláním odpovědí a po komponentách, které upravují požadavky. Příklady: Přeposílané hlavičky, přepsání adresy URL. |
MVC | Zpracovává požadavky s využitím MVC / Razor Pages. | Terminál, pokud požadavek odpovídá trase. |
OWIN | Interoperabilita s aplikacemi, servery a middlewarem založenými na OWIN. | Terminál, pokud middleware OWIN plně zpracuje daný požadavek. |
Vyžádat dekompresi | Poskytuje podporu pro dekompresi požadavků. | Před komponentami, které čtou text požadavku. |
Ukládání odpovědí do mezipaměti | Poskytuje podporu pro ukládání odpovědí do mezipaměti. | Před komponentami, které vyžadují cacheování. Je potřeba použít UseCORS před UseResponseCaching . |
Komprese odpovědí | Poskytuje podporu pro kompresi odpovědí. | Před komponentami, které vyžadují kompresi. |
Žádost o lokalizaci | Poskytuje podporu lokalizace. | Před komponentami citlivými na lokalizaci. Při použití RouteDataRequestCultureProvider musí následovat po middlewaru Routing. |
Směrování koncového bodu | Definuje a omezuje trasy požadavků. | Terminál pro vyhovující trasy. |
LÁZNĚ | Zpracovává všechny požadavky od tohoto bodu v řetězci middlewaru vrácením výchozí stránky pro jednostránkovou aplikaci (SPA). | Na konci řetězce, aby mělo přednost ostatní middleware pro obsluhu statických souborů, akcí MVC atd. |
Sezení | Poskytuje podporu pro správu uživatelských relací. | Před komponentami, které vyžadují Session. |
Statické soubory | Poskytuje podporu pro obsluhu statických souborů a procházení adresářů. | Terminál, pokud požadavek odpovídá souboru. |
Přepsání adresy URL | Poskytuje podporu pro přepis adres URL a přesměrování požadavků. | Před komponentami, které využívají danou adresu URL. |
W3CLogging | Generuje protokoly přístupu k serveru v rozšířeném formátu souborů protokolu W3C. | Na začátku potrubí middlewaru. |
Webové sokety | Povoluje protokol WebSocket. | Před komponentami, které jsou nezbytné pro přijetí požadavků WebSocket. |
Další materiály
- Sekce Možnosti registrace a doba života obsahuje kompletní ukázku middlewaru se službami Scoped, Transient a Singleton.
- Psaní vlastního middlewaru ASP.NET Core
- Testování middlewaru ASP.NET Core
- Konfigurace gRPC-Web v ASP.NET Core
- Migrace modulů HTTP do middlewaru ASP.NET Core
- Spuštění aplikace v ASP.NET Core
- Funkce požadavků v ASP.NET Core
- Aktivace middlewaru na základě objektu pro vytváření v ASP.NET Core
- Aktivace middlewaru s využitím kontejneru třetí strany v ASP.NET Core
Autor: Rick Anderson a Steve Smith
Middleware je software sestavený do kanálu aplikace pro zpracování požadavků a odpovědí. Každá komponenta:
- Určuje, jestli se má požadavek předat další součásti v potrubí.
- Může provádět práci před a po další komponentě v řetězci.
K sestavení kanálu požadavků se používají delegáti požadavků. Delegáti požadavků zpracovávají každý požadavek HTTP.
Delegáti požadavků jsou konfigurováni pomocí rozšiřujících metod Run, Map a Use. Jednotlivý delegát požadavku může být zadán na řádku jako anonymní metoda (tzv. in-line middleware) nebo může být definován v opakovaně použitelné třídě. Tyto opakovaně použitelné třídy a vložené anonymní metody jsou middleware, označované také jako komponenty middlewaru. Každá komponenta middlewaru v kanálu požadavků zodpovídá za vyvolání další komponenty v kanálu nebo zkratování kanálu. Když middleware způsobí zkrat, označuje se jako terminální middleware, protože brání další middleware ve zpracování požadavku.
Migrace modulů HTTP do middlewaru ASP.NET Core vysvětluje rozdíl mezi kanály požadavků v ASP.NET Core a ASP.NET 4.x a poskytuje další ukázky middlewaru.
Vytvoření kanálu middlewaru s využitím IApplicationBuilderu
Kanál požadavků v ASP.NET Core se skládá z posloupnosti delegátů požadavků, kteří se volají postupně. Tento koncept demonstruje následující schéma. Vlákno spouštění postupuje podle černých šipek.
Každý delegát může provádět operace před a za dalším delegátem. Delegáti zpracování výjimek by se měli volat v počátečních fázích řetězce, aby mohli zachytit výjimky, ke kterým dochází v pozdějších fázích řetězce.
Nejjednodušší možná aplikace ASP.NET Core nastavuje jednoho delegáta požadavků, který zpracovává všechny požadavky. Tento případ nezahrnuje vlastní kanál požadavků. Místo toho se jako reakce na každý požadavek HTTP volá jedna anonymní funkce.
public class Startup
{
public void Configure(IApplicationBuilder app)
{
app.Run(async context =>
{
await context.Response.WriteAsync("Hello, World!");
});
}
}
Propojte více delegátů požadavků pomocí Use. Parametr next
představuje dalšího delegáta v potrubí. Potrubí můžete zkratovat tím, že nezavoláte parametr next. Obvykle můžete provádět akce před dalším delegátem i po něm, jak ukazuje následující příklad:
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.");
});
}
}
Pokud delegát nepředá požadavek dalšímu delegátovi, označuje se to jako přerušení kanálu požadavků. Zkratování je často žádoucí, protože zabraňuje zbytečné práci. Například middleware statického souboru může fungovat jako terminálový middleware zpracováním požadavku na statický soubor a přeskočením zbytku zpracování. Middleware přidaný do kanálu před middleware, který ukončí další zpracování, stále zpracovává kód po příslušných příkazech next.Invoke
. Ohledně pokusu o zápis do již odeslané odpovědi si však projděte následující upozornění.
Varování
Po odeslání odpovědi klientovi nevolejte next.Invoke
. Změny v HttpResponse po spuštění odpovědi vyvolají výjimku. Například nastavení hlaviček a stavového kódu vyvolá výjimku. Zápis do textu odpovědi po volání next
:
- Může způsobit porušení protokolu. Příklad: Delší zápis, než je stanovená délka
Content-Length
. - Může poškodit formát textu. Příklad: Zápis zápatí HTML do souboru CSS.
HasStarted je užitečná nápověda indikující, jestli byly odeslány hlavičky nebo zapisováno do textu.
Delegáti Run neobdrží parametr next
. První delegát Run
je vždy terminální a ukončí zpracovatelský řetězec. Použití Run
je obvyklá konvence. Některé komponenty middlewaru můžou zpřístupnit metody Run[Middleware]
, které běží na konci kanálu:
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.");
});
}
}
Pokud chcete zobrazit komentáře ke kódu přeložené do jiných jazyků, než je angličtina, dejte nám vědět v této diskuzi na GitHubu.
V předchozím příkladu delegát Run
zapíše "Hello from 2nd delegate."
do odpovědi a pak ukončí kanál. Pokud je za delegáta Use
přidán jiný delegát Run
nebo Run
, nevolá se.
Pořadí middlewaru
Následující diagram znázorňuje kompletní kanál zpracování požadavků pro aplikace ASP.NET Core MVC a Razor Pages. Můžete si prohlédnout, jak je v typické aplikaci uspořádané stávající middlewary seřazené a kde se přidávají vlastní middlewary. Máte plnou kontrolu nad tím, jak změnit pořadí stávajících middlewarů nebo vložit nové vlastní middlewary podle potřeby vašich scénářů.
Middleware Endpoint v předchozím diagramu spustí kanál filtru pro odpovídající typ aplikace – MVC nebo Razor Pages.
Pořadí, ve kterém jsou komponenty middlewaru přidány do metody Startup.Configure
, definuje pořadí, ve kterém se komponenty middlewaru vyvolávají pro požadavky, a obrácené pořadí pro odpovědi. Toto pořadí má zásadní důležitost pro zabezpečení, výkon a funkce.
Následující metoda Startup.Configure
přidává komponenty middlewaru související se zabezpečením v typickém doporučeném pořadí:
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?}");
});
}
V předchozím kódu:
- Middleware, který se nepřidá při vytváření nové webové aplikace s účty jednotlivých uživatelů, je zakomentovaný.
- Ne každý middleware se objevuje přesně v tomto pořadí, ale mnoho z nich ano. Příklad:
-
UseCors
,UseAuthentication
aUseAuthorization
musí být v uvedeném pořadí. -
UseCors
v současné době musí předcházet předUseResponseCaching
, a to kvůli této chybě. -
UseRequestLocalization
musí být uvedený před jakýmkoli jiným middlewarem, který kontroluje kulturu požadavků (napříkladapp.UseMvcWithDefaultRoute()
).
-
V některých scénářích má middleware jiné řazení. Například pořadí ukládání do mezipaměti a komprese je specifické pro daný scénář a existuje několik platných pořadí. Příklad:
app.UseResponseCaching();
app.UseResponseCompression();
V předchozím kódu by bylo možné snížit využití procesoru uložením komprimované odpovědi do mezipaměti, ale mohlo by se stát, že budete ukládat do mezipaměti více reprezentací prostředku pomocí různých kompresních algoritmů, jako jsou například Gzip nebo Brotli.
Následující pořadí kombinuje statické soubory, aby se umožnilo ukládání komprimovaných statických souborů do mezipaměti:
app.UseResponseCaching();
app.UseResponseCompression();
app.UseStaticFiles();
Následující metoda Startup.Configure
přidá komponenty middlewaru pro běžné scénáře aplikací:
- Zpracování výjimek nebo chyb
- Když se aplikace spustí ve vývojovém prostředí:
- Middleware Developer Exception Page (UseDeveloperExceptionPage) hlásí běhové chyby aplikací.
- Middleware Database Error Page hlásí běhové chyby databází.
- Když se aplikace spustí v produkčním prostředí:
- Middleware Exception Handler (UseExceptionHandler) zachycuje výjimky vyvolané v následujících middlewarech.
- Middleware HSTS (HTTP Strict Transport Security Protocol) (UseHsts) přidává hlavičku
Strict-Transport-Security
.
- Když se aplikace spustí ve vývojovém prostředí:
- Middleware HTTPS Redirection (UseHttpsRedirection) přesměruje požadavky HTTP na HTTPS.
- Middleware pro statické soubory (UseStaticFiles) vrací statické soubory a přeruší další zpracování požadavků.
- Middleware Cookie Policy (UseCookiePolicy) zajišťuje soulad aplikace s Obecným nařízením EU o ochraně osobních údajů (GDPR).
- Routing Middleware (UseRouting) slouží ke směrování požadavků.
- Middleware Authentication (UseAuthentication) se pokusí ověřit uživatele předtím, než se mu povolí přístup k zabezpečeným prostředkům.
- Autorizační Middleware (UseAuthorization) opravňuje uživatele ke vstupu do zabezpečených prostředků.
- Session Middleware (UseSession) nastavuje a udržuje stav relace. Pokud aplikace používá stav relace, volejte middleware Session za middlewarem Cookie Policy a před middlewarem MVC.
- Middleware Endpoint Routing (UseEndpoints s MapRazorPages) slouží pro přidání koncových bodů Razor Pages do kanálu požadavků.
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();
});
}
V předchozím ukázkovém kódu je každá rozšiřující metoda middlewaru zpřístupněná v IApplicationBuilder prostřednictvím oboru názvů Microsoft.AspNetCore.Builder.
UseExceptionHandler je první middleware komponenta přidaná do potrubí. Proto middleware Exception Handler zachycuje všechny výjimky, ke kterým dochází v pozdějších voláních.
Middleware Static File se volá v rané fázi zpracování kanálu, aby mohl zpracovávat požadavky a provést zkratování, aniž by se musely projít zbývající komponenty. Middleware Static File neposkytuje žádné kontroly autorizace. Všechny soubory obsluhované middlewarem Static File, včetně souborů pod wwwroot, jsou veřejně dostupné. Informace o přístupu k zabezpečení statických souborů najdete v tématu Statické soubory v ASP.NET Core.
Pokud požadavek nezpracuje middleware Static File, předá se do middlewaru Authentication (UseAuthentication), který provádí ověřování. Ověřování nezpůsobí přeskočení neověřených požadavků. I když Middleware Authentication ověřuje požadavky, autorizace (a zamítnutí) nastane až poté, co MVC vybere konkrétní Razor stránku nebo kontroler MVC a akci.
Následující příklad ukazuje pořadí middlewaru, ve kterém požadavky pro statické soubory zpracovává middleware Static File před middlewarem Response Compression. Statické soubory nejsou při tomto uspořádání middlewaru komprimovány. Odpovědi Razor Pages je možné komprimovat.
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();
});
}
Pro jednostránkové aplikace (SPA) je middleware SPA UseSpaStaticFiles obvykle na konci middlewarového kanálu. Middleware SPA je poslední:
- Aby se všem ostatním middlewarům umožnilo reagovat na odpovídající požadavky jako první.
- Aby jednostránkovým aplikacím se směrováním na straně klienta bylo umožněno spouštět se na všech trasách, které nejsou rozpoznány serverovou aplikací.
Další podrobnosti o SPA najdete v průvodcích pro šablony projektů React a Angular.
Pořadí middlewaru Forwarded Headers
Middleware Forwarded Headers by měl běžet před ostatním middlewarem. Toto řazení zajišťuje, že middleware, který spoléhá na informace z dopředných hlaviček, může využívat jejich hodnoty pro zpracování. Pokud chcete middleware Forwarded Headers spustit po diagnostice a middlewaru pro zpracování chyb, přečtěte si téma Middleware Ordered Headers.
Rozvětvení middleware kanálu
Rozšíření Map se používají jako konvence pro větvení kanálu.
Map
rozvětví požadavkový kanál na základě shody dané cesty požadavku. Pokud cesta žádosti začíná zadanou cestou, větev se spustí.
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.");
});
}
}
Následující tabulka ukazuje požadavky a odpovědi z http://localhost:1234
s využitím předchozího kódu.
Požadavek | Reakce |
---|---|
localhost:1234 | Zdravím vás od delegáta mimo Mapu. |
localhost:1234/map1 | Test mapy 1 |
localhost:1234/map2 | Test mapy 2 |
localhost:1234/map3 | Zdravím vás od delegáta mimo Mapu. |
Při použití Map
se odpovídající segmenty cest odeberou z HttpRequest.Path
a připojí ke HttpRequest.PathBase
pro každý požadavek.
Map
podporuje vnoření, například:
app.Map("/level1", level1App => {
level1App.Map("/level2a", level2AApp => {
// "/level1/level2a" processing
});
level1App.Map("/level2b", level2BApp => {
// "/level1/level2b" processing
});
});
Map
také může odpovídat více segmentům najednou:
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 rozvětví kanál požadavku na základě výsledku daného predikátu. K mapování požadavků na novou větev kanálu je možné použít jakýkoli predikát typu Func<HttpContext, bool>
. V následujícím příkladu se predikát používá ke zjištění přítomnosti proměnné řetězce dotazu branch
:
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.");
});
}
}
Následující tabulka ukazuje požadavky a odpovědi z http://localhost:1234
s využitím předchozího kódu:
Požadavek | Reakce |
---|---|
localhost:1234 | Zdravím vás od delegáta mimo Mapu. |
localhost:1234/?branch=main | Použitá větev = main |
UseWhen také rozvětví kanál požadavku na základě výsledku daného predikátu. Na rozdíl od MapWhen
se tato větev znovu připojí k hlavnímu kanálu, pokud nezpůsobí zkratování nebo neobsahuje terminální middleware:
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.");
});
}
}
V předchozím příkladu se pro všechny požadavky zapíše odpověď Hello from main pipeline. Pokud požadavek obsahuje proměnnou řetězce dotazu branch
, před opětovným připojením k hlavnímu kanálu se zaprotokoluje její hodnota.
Integrovaný middleware
ASP.NET Core se dodává s následujícími komponentami middlewaru. Sloupec Pořadí obsahuje poznámky k umístění middlewaru v kanálu zpracování požadavků a to, za jakých podmínek může middleware ukončit zpracování požadavků. Když middleware zkratuje kanál zpracování požadavků a zabrání dalšímu navazujícímu middlewaru zpracovat požadavek, označuje se jako terminální middleware. Další informace o zkratování najdete v části Vytvoření kanálu middlewaru s využitím IApplicationBuilderu.
Middleware | Popis | Objednávka |
---|---|---|
Ochrana proti padělání | Poskytuje podporu pro ochranu proti falšování požadavků. | Po ověření a autorizaci, předtím než se přejde ke koncovým bodům. |
Autentizace | Poskytuje podporu ověřování. | Než bude potřeba HttpContext.User . Terminál pro zpětné volání OAuth. |
Autorizace | Poskytuje podporu při autorizaci. | Okamžitě po middlewaru Authentication. |
Cookie Politika | Sleduje souhlas uživatelů s ukládáním osobních údajů a vynucuje minimální standardy pro pole cookie, například secure a SameSite . |
Než middleware začne vydávat soubory cookie. Příklady: Authentication, Session, MVC (TempData). |
CORS | Provádí konfiguraci sdílení prostředků mezi zdroji (CORS). | Před komponentami, které používají CORS.
UseCors v současné době musí předcházet před UseResponseCaching , a to kvůli této chybě. |
Diagnostika | Několik samostatných middlewarů, které poskytují stránku výjimek pro vývojáře, zpracování výjimek, stránky stavových kódů a výchozí webovou stránku pro nové aplikace. | Před komponentami, které generují chyby. Terminál pro výjimky nebo obsluhu výchozí webové stránky pro nové aplikace. |
Přesměrované hlavičky | Přesměruje přeposílané hlavičky na aktuální požadavek. | Před komponentami, které využívají aktualizovaná pole. Příklady: Schéma, hostitel, IP adresa klienta, metoda. |
Kontrola stavu | Kontroluje stav aplikace ASP.NET Core a jejích závislostí, jako je kontrola dostupnosti databáze. | Terminál, pokud požadavek odpovídá koncovému bodu kontroly stavu. |
Šíření protokolových hlaviček | Šíří hlavičky HTTP z příchozího požadavku do odchozích požadavků klienta HTTP. | |
Přepsání metody HTTP | Umožňuje, aby příchozí požadavek POST změnil metodu. | Před komponentami, které využívají aktualizovanou metodu. |
Přesměrování HTTPS | Přesměruje všechny požadavky HTTP na HTTPS. | Před komponentami, které využívají danou adresu URL. |
Zabezpečení striktního přenosu HTTP (HSTS) | Middleware pro vylepšení zabezpečení, který přidává speciální hlavičku odpovědi. | Před odesláním odpovědí a po komponentách, které upravují požadavky. Příklady: Přeposílané hlavičky, přepsání adresy URL. |
MVC | Zpracovává požadavky s využitím MVC / Razor Pages. | Terminál, pokud požadavek odpovídá trase. |
OWIN | Interoperabilita s aplikacemi, servery a middlewarem založenými na OWIN. | Terminál, pokud middleware OWIN plně zpracuje daný požadavek. |
Ukládání odpovědí do mezipaměti | Poskytuje podporu pro ukládání odpovědí do mezipaměti. | Před komponentami, které vyžadují cacheování. Je potřeba použít UseCORS před UseResponseCaching . |
Komprese odpovědí | Poskytuje podporu pro kompresi odpovědí. | Před komponentami, které vyžadují kompresi. |
Žádost o lokalizaci | Poskytuje podporu lokalizace. | Před komponentami citlivými na lokalizaci. Při použití RouteDataRequestCultureProvider musí následovat po middlewaru Routing. |
Směrování koncového bodu | Definuje a omezuje trasy požadavků. | Terminál pro vyhovující trasy. |
LÁZNĚ | Zpracovává všechny požadavky od tohoto bodu v řetězci middlewaru vrácením výchozí stránky pro jednostránkovou aplikaci (SPA). | Na konci řetězce, aby mělo přednost ostatní middleware pro obsluhu statických souborů, akcí MVC atd. |
Sezení | Poskytuje podporu pro správu uživatelských relací. | Před komponentami, které vyžadují Session. |
Statické soubory | Poskytuje podporu pro obsluhu statických souborů a procházení adresářů. | Terminál, pokud požadavek odpovídá souboru. |
Přepsání adresy URL | Poskytuje podporu pro přepis adres URL a přesměrování požadavků. | Před komponentami, které využívají danou adresu URL. |
Webové sokety | Povoluje protokol WebSocket. | Před komponentami, které jsou nezbytné pro přijetí požadavků WebSocket. |
Další materiály
- Sekce Možnosti registrace a doba života obsahuje kompletní ukázku middlewaru se službami Scoped, Transient a Singleton.
- Psaní vlastního middlewaru ASP.NET Core
- Testování middlewaru ASP.NET Core
- Migrace modulů HTTP do middlewaru ASP.NET Core
- Spuštění aplikace v ASP.NET Core
- Funkce požadavků v ASP.NET Core
- Aktivace middlewaru na základě objektu pro vytváření v ASP.NET Core
- Aktivace middlewaru s využitím kontejneru třetí strany v ASP.NET Core