ASP.NET Core Jiné

Od Rick Anderson a Steve Smith

Middleware je software, který se sestaví do kanálu aplikace za účelem zpracování požadavků a odpovědí. Jednotlivé komponenty:

  • Zvolí, jestli se má žádost předat další komponentě v kanálu.
  • Může provádět práci před a za další komponentou v kanálu.

Delegáti žádostí se používají k sestavení kanálu požadavků. Delegát žádosti zpracuje jednotlivé požadavky HTTP.

Delegáti žádostí jsou nakonfigurováni pomocí Run Map Use metod rozšíření, a. Jednotlivé delegáty žádostí je možné zadat jako anonymní metodu (označovanou v rámci middlewarového middlewaru) nebo ji lze definovat 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á součást middlewaru v kanálu požadavků zodpovídá za vyvolání další komponenty v kanálu nebo při krátkém okruhu kanálu. Když jsou krátkodobé okruhy middleware, nazývá se middleware terminálu , protože zabrání dalšímu middlewaru ve zpracování žádosti.

migrace obslužných rutin a modulů HTTP do ASP.NET Core middlewaruvysvě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 pomocí WebApplication

kanál žádostí o ASP.NET Core se skládá z posloupnosti delegátů požadavků, který se nazývá jedna po druhé. Následující diagram znázorňuje koncept. Vlákno provádění následuje za černými šipkami.

Požadavek zpracování, který ukazuje, že se dorazí na požadavek, zpracovává se prostřednictvím tří middlewarů a odpověď opouští aplikaci Každý middleware spustí svou logiku a předá požadavek dalšímu middlewaru v příkazu Next (). Poté, co třetí middleware zpracuje požadavek, požadavek předá předchozí dva middleware v obráceném pořadí pro další zpracování po jejich dalších () příkazech před ukončením aplikace jako reakci na klienta.

Každý delegát může provádět operace před a po dalším delegátu. Delegáty zpracování výjimek by se měly volat v rámci kanálu na začátku, takže můžou zachytit výjimky, ke kterým dochází v pozdějších fázích kanálu.

nejjednodušší možná ASP.NET Core aplikace nastaví jediného delegáta žádosti, který zpracovává všechny požadavky. Tento případ nezahrnuje skutečný kanál žádostí. Místo toho je volána jedna anonymní funkce v reakci na každý požadavek HTTP.

var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();

app.Run(async context =>
{
    await context.Response.WriteAsync("Hello world!");
});

app.Run();

Řetězení více požadavků delegátů společně s Use . nextParametr představuje dalšího delegáta v kanálu. Kanál můžete pro krátké okruhy vymezit tím , že nevoláte next parametr. Obvykle můžete provádět akce před i po next delegátu, jak ukazuje následující příklad:

var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();

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.");
});

app.Run();

Když delegát neprojde požadavek na dalšího delegáta, nazývá se to krátkodobý kanál žádosti. Krátkodobé okruhy jsou často žádoucí, protože brání zbytečné práci. Například middleware statických souborů může fungovat jako middleware terminálu tím, že zpracovává požadavek na statický soubor a krátký okruh zbývajících částí kanálu. Middleware přidané do kanálu předtím, než middleware, který ukončí další zpracování, stále zpracovává kód po svých next.Invoke příkazech. Přečtěte si ale následující upozornění týkající se pokusu o zápis do odpovědi, která již byla odeslána.

Upozornění

Nevolejte next.Invoke po odeslání odpovědi klientovi. Změny HttpResponse poté, co odpověď začala, vyvolávají výjimku. Například nastavení záhlaví a stavový kód vyvolávají výjimku. Zápis do těla odpovědi po volání next :

  • Může způsobit narušení protokolu. Například zápis více než uvedené Content-Length .
  • Může poškodit formát textu. Například zápis zápatí HTML do souboru CSS.

HasStarted je užitečnou nápovědou, která označuje, zda byla odeslána hlavička nebo zda byl text napsán do.

Run Delegáti neobdrží next parametr. První Run delegát je vždycky terminál a ukončí kanál. Run je konvence. Některé komponenty middlewaru můžou vystavovat Run[Middleware] metody, které se spouštějí na konci kanálu:

var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();

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.");
});

app.Run();

Pokud chcete zobrazit komentáře ke kódu přeložené do jiných jazyků než angličtiny, dejte nám vědět v tomto problému diskuze na GitHubu.

V předchozím příkladu Run delegát zapisuje "Hello from 2nd delegate." do odpovědi a pak kanál ukončí. Pokud Use Run je po delegátu přidán jiný nebo delegát Run , není volán.

Preferovat aplikaci Použijte přetížení, které vyžaduje předání kontextu dalšímu.

Aplikace, která přiděluje . Použít metodu rozšíření:

  • Vyžaduje předání kontextu do next .
  • Ukládá dvě interní přidělení podle požadavků, které jsou požadovány při použití jiné přetížení.

další informace najdete v tomto GitHub problému.

Pořadí middlewaru

následující diagram znázorňuje kompletní kanál zpracování požadavků pro ASP.NET Core aplikace MVC a Razor stránky. Můžete vidět, jak, v typické aplikaci jsou seřazené existující middleware a kdy se přidávají vlastní middleware. Máte plnou kontrolu nad tím, jak změnit pořadí stávajících middlewarů, nebo vložit nové vlastní middleware podle potřeby pro vaše scénáře.

ASP.NET Core kanál middlewaru

Middleware koncového bodu v předchozím diagramu spouští kanál filtru pro odpovídající typ aplikace — MVC nebo Razor stránky.

Middleware Směrování v předchozím diagramu se zobrazí v následujících statických souborech. Toto je pořadí, ve kterém šablony projektu implementují explicitně voláním aplikace. UseRouting. Pokud nevoláte app.UseRouting , middleware Směrování ve výchozím nastavení spustí na začátku kanálu. Další informace najdete v tématu Směrování.

kanál filtru ASP.NET Core

Pořadí, v jakém jsou přidány komponenty middlewaru do souboru program. cs definuje pořadí, ve kterém jsou komponenty middleware vyvolány na žádostech, a obrácené pořadí pro odpověď. Pořadí je důležité pro zabezpečení, výkon a funkčnost.

Následující zvýrazněný kód v programu program. cs přidá součásti 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řidaly při vytváření nové webové aplikace s jednotlivými účty uživatele , jsou zakomentovány.
  • Ne každý middleware se zobrazí v tomto přesném pořadí, ale mnoho do něj. Například:
    • UseCors, UseAuthentication , a se UseAuthorization musí objevit v uvedeném pořadí.
    • UseCors v současné době musí být uvedena před UseResponseCaching . tento požadavek je vysvětlen v GitHub problém dotnet/aspnetcore #23218.
    • UseRequestLocalization musí se nacházet před jakýmkoli middlewarem, který by mohl kontrolovat jazykovou verzi žádosti (například app.UseMvcWithDefaultRoute() ).

V některých scénářích má middleware jiné řazení. Například ukládání do mezipaměti a v pořadí komprese je specifické pro konkrétní scénář a existuje více platných pořadí. Například:

app.UseResponseCaching();
app.UseResponseCompression();

V předchozím kódu je možné snížit využití procesoru ukládáním komprimované odpovědi do mezipaměti, ale můžete také ukončit ukládání více reprezentace prostředku do mezipaměti pomocí různých algoritmů komprese, jako je gzip nebo Brotli.

Následující řazení kombinuje statické soubory a povoluje ukládání komprimovaných statických souborů do mezipaměti:

app.UseResponseCaching();
app.UseResponseCompression();
app.UseStaticFiles();

Následující program. cs kód přidává komponenty middlewaru pro běžné scénáře aplikací:

  1. Zpracování výjimek a chyb
    • Když aplikace běží ve vývojovém prostředí:
      • Aplikace middleware stránky s výjimkou vývojářů ( UseDeveloperExceptionPage ) hlásí chyby běhového modulu.
      • Zpráva middleware pro chybovou stránku databáze ( UseDatabaseErrorPage ) oznamuje chyby běhového modulu databáze.
    • Když aplikace běží v produkčním prostředí:
      • Middleware obslužné rutiny výjimek ( UseExceptionHandler ) zachytává výjimky vyvolané v následujících middlewarech.
      • Middleware HSTS (HTTP Strict Transport Security Protocol) ( UseHsts ) přidá Strict-Transport-Security hlavičku.
  2. Middleware () přesměrování protokolu HTTPS ( UseHttpsRedirection ) přesměruje požadavky HTTP na https.
  3. Soubor middleware () statických souborů ( UseStaticFiles ) vrací statické soubory a další zpracování žádostí o krátkodobé okruhy.
  4. Cookie Middleware zásad ( UseCookiePolicy ) aplikace v souladu s pravidly pro EU obecné nařízení o ochraně osobních údajů (GDPR).
  5. Směrování middleware ( UseRouting ) pro směrování požadavků.
  6. Middleware ověřování ( UseAuthentication ) se pokusí ověřit uživatele předtím, než budou mít přístup k zabezpečeným prostředkům.
  7. Middleware autorizace ( UseAuthorization ) opravňuje uživatele k přístupu k zabezpečeným prostředkům.
  8. Middleware relace ( UseSession ) vytváří a udržuje stav relace. Pokud aplikace používá stav relace, volejte middleware relace po Cookie middlewaru zásad a před middlewarem MVC.
  9. Middleware směrování koncového bodu ( UseEndpoints s MapRazorPages ) pro přidání Razor koncových bodů stránek 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 příkladu kódu je každá metoda rozšíření middleware vystavena WebApplicationBuilder prostřednictvím Microsoft.AspNetCore.Builder oboru názvů.

UseExceptionHandler je první součást middleware přidaná do kanálu. Proto middleware obslužné rutiny výjimek zachycuje všechny výjimky, ke kterým dojde v pozdějších voláních.

Middleware statických souborů se zavolá v průběhu kanálu, aby mohl zpracovávat požadavky a krátké okruhy bez toho, aby procházely zbývajícími součástmi. Middleware statických souborů neposkytuje žádné autorizační kontroly. Všechny soubory, které poskytuje middleware pro statický soubor, včetně těch v rámci wwwroot, jsou veřejně dostupné. Přístup k zabezpečení statických souborů naleznete v tématu Statické soubory v ASP.NET Core .

Pokud požadavek nezpracovává middleware pro statický soubor, je předán do middleware ověřování ( UseAuthentication ), který provádí ověřování. Ověřování neověřuje neověřené požadavky v krátkém okruhu. I když middleware ověřování ověřuje požadavky, autorizaci (a odmítnutí) proběhne pouze poté, co MVC vybere konkrétní Razor stránku nebo kontroler MVC a akci.

Následující příklad ukazuje pořadí middlewaru, kde požadavky na statické soubory jsou zpracovávány pomocí middlewaru statického souboru před použitím middlewaru pro komprimaci odezvy. Statické soubory nejsou s tímto pořadím middlewaru komprimovány. RazorOdpovědi na stránky lze komprimovat.

// Static files aren't compressed by Static File Middleware.
app.UseStaticFiles();

app.UseRouting();

app.UseResponseCompression();

app.MapRazorPages();

informace o aplikacích s jednou stránkou naleznete v příručkách k šablonám projektů React a Angular .

Pořadí middlewaru u předávaných hlaviček

Middleware předaných hlaviček by se měla spustit před jiným middlewarem. Toto řazení zajišťuje, aby middleware spoléhající se na předané informace hlaviček mohl spotřebovat hodnoty hlaviček pro zpracování. Pro spuštění předávaných middlewarových hlaviček po diagnostice a middlewaru zpracování chyb si přečtěte téma pořadí middlewaru u předaných hlaviček.

Větvení kanálu middlewaru

Map rozšíření se používají jako konvence pro větvení kanálu. Map rozvětvení kanálu požadavků na základě shody dané cesty požadavku. Pokud cesta k požadavku začíná danou cestou, je větev spuštěná.

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. <p>");
});

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");
    });
}

V následující tabulce jsou uvedeny žádosti a odpovědi z http://localhost:1234 použití předchozího kódu.

Žádost Odpověď
localhost: 1234 Hello z delegáta bez mapy.
localhost: 1234/Map1 Mapování testu 1
localhost: 1234/MAP2 – Mapovat test 2
localhost: 1234/map3 – Hello z delegáta bez mapy.

Při Map použití se odpovídající segmenty cesty odeberou z HttpRequest.Path a připojí se k HttpRequest.PathBase pro každý požadavek.

Map podporuje vnořování, například:

app.Map("/level1", level1App => {
    level1App.Map("/level2a", level2AApp => {
        // "/level1/level2a" processing
    });
    level1App.Map("/level2b", level2BApp => {
        // "/level1/level2b" processing
    });
});

Map může také 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. <p>");
});

app.Run();

static void HandleMultiSeg(IApplicationBuilder app)
{
    app.Run(async context =>
    {
        await context.Response.WriteAsync("Map Test 1");
    });
}

MapWhen rozvětvení kanálu požadavků na základě výsledku daného predikátu. Func<HttpContext, bool>K mapování požadavků na novou větev kanálu lze použít jakýkoli predikát typu. V následujícím příkladu se k detekci přítomnosti proměnné řetězce dotazu používá predikát 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. <p>");
        });
    }
}

V následující tabulce jsou uvedeny žádosti a odpovědi z http://localhost:1234 použití předchozího kódu:

Žádost Odpověď
localhost: 1234 Hello z delegáta bez mapy.
localhost: 1234/? větev = Main Použitá větev = Main

UseWhen také větví kanál požadavků na základě výsledku daného predikátu. Na rozdíl od MapWhen , tato větev se znovu připojí k hlavnímu kanálu, pokud nemá krátký okruh nebo obsahuje middleware terminálu:

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. <p>");
});

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 odpověď "Hello z hlavního kanálu". je napsán pro všechny požadavky. Pokud požadavek obsahuje proměnnou řetězce dotazu branch , je jeho hodnota protokolována před opětovným připojením k hlavnímu kanálu.

Vestavěný middleware

ASP.NET Core se dodává s následujícími součástmi middlewaru. Sloupec Order poskytuje poznámky k umístění middlewaru v kanálu zpracování požadavků a za jakých podmínek může middleware ukončit zpracování požadavků. Když middleware middleware vytvoří kanál zpracování požadavků a zabrání dalšímu podřízenému middlewaru ve zpracování žádosti, nazývá se middleware terminálu. Další informace o krátkodobém okruhu najdete v části vytvoření kanálu middlewaru pomocí IApplicationBuilder .

Middleware Description Objednávka
Authentication Poskytuje podporu ověřování. Předtím HttpContext.User , než je potřeba. Terminál pro zpětná volání OAuth.
Autorizace Poskytuje podporu autorizace. Hned po ověřovacím middlewaru.
Cookie Politických Sleduje souhlas uživatelů při ukládání osobních údajů a vynutila minimální standardy pro cookie pole, například secure a SameSite . Před middlewarem, který vydává problémy cookie s. Příklady: ověřování, relace, MVC (TempData).
CORS Konfiguruje sdílení prostředků mezi zdroji. Před komponenty, které používají CORS. UseCors v současné době UseResponseCaching se musí před touto chyboupřecházet.
DeveloperExceptionPage Vygeneruje stránku s informacemi o chybě, která je určena pouze pro použití ve vývojovém prostředí. Před komponenty, které generují chyby. Šablony projektu automaticky registrují tento middleware jako první middleware v kanálu při vývoji prostředí.
Diagnostika Několik samostatných middlewarů, které poskytují stránku s výjimkou vývojářů, zpracování výjimek, stránky stavového kódu a výchozí webovou stránku pro nové aplikace. Před komponenty, které generují chyby. Terminál pro výjimky nebo pro výchozí webovou stránku pro nové aplikace
Předávaná záhlaví Přepošle hlavičky proxy na aktuální požadavek. Před komponenty, které používají aktualizované pole. Příklady: schéma, hostitel, IP adresa klienta, metoda.
Kontroly stavu kontroluje stav aplikace ASP.NET Core a jejích závislostí, jako je například kontrola dostupnosti databáze. Terminál, je-li požadavek shodný s koncovým bodem kontroly stavu.
Šíření hlaviček Šíří hlavičky protokolu HTTP z příchozího požadavku do odchozích požadavků klienta HTTP.
Protokolování HTTP Protokoluje požadavky a odpovědi HTTP. Na začátku kanálu middlewaru.
Přepsání metody HTTP Umožňuje příchozí žádosti POST přepsat metodu. Před komponenty, které používají aktualizovanou metodu.
Přesměrování HTTPS Přesměrovat všechny požadavky HTTP na HTTPS. Před komponenty, které používají adresu URL.
HTTP Strict Transport Security (HSTS) Vylepšení zabezpečení – middleware, který přidává speciální hlavičku odpovědi. Před odesláním odpovědí a po součástech, které upravují požadavky. Příklady: předávané hlavičky, přepis adresy URL.
MVC Zpracovává požadavky pomocí MVC nebo Razor stránek. Terminál, pokud požadavek odpovídá trase.
OWIN Interoperabilita s aplikacemi, servery a middlewarem založeným na OWIN Terminál, pokud middleware OWIN plně zpracovává požadavek.
Ukládání do mezipaměti odpovědi Poskytuje podporu pro ukládání odpovědí do mezipaměti. Před součástmi, které vyžadují ukládání do mezipaměti. UseCORS musí předcházet UseResponseCaching .
Komprese odezvy Poskytuje podporu pro komprimaci odpovědí. Před součástmi, které vyžadují kompresi.
Lokalizace žádosti Poskytuje podporu lokalizace. Před lokalizací citlivých komponent. Po použití se musí objevit po Middlewari směrování RouteDataRequestCultureProvider .
Směrování koncových bodů Definuje a omezuje trasy požadavků. Terminál pro vyhovující trasy.
OVĚŘOVÁNÍ Zpracovává všechny požadavky od tohoto bodu v řetězci middleware vrácením výchozí stránky pro aplikaci s jednou stránkou (SPA). V řetězci pozdě, aby měl přednost další middleware pro obsluhu statických souborů, akcí MVC atd.
Relace Poskytuje podporu pro správu uživatelských relací. Před komponenty, které vyžadují relaci.
Statické soubory Poskytuje podporu pro poskytování statických souborů a procházení adresářů. Terminál, pokud požadavek odpovídá souboru
Přepsání adresy URL Poskytuje podporu pro přepisování adres URL a přesměrování požadavků. Před komponenty, které používají adresu URL.
W3CLogging Vygeneruje protokoly přístupu serveru v rozšířeném formátu souboru protokolu W3C. Na začátku kanálu middlewaru.
WebSockets Povolí protokol WebSockets. Před komponenty, které jsou vyžadovány pro příjem požadavků protokolu WebSocket.

Další zdroje informací

Od Rick Anderson a Steve Smith

Middleware je software, který se sestaví do kanálu aplikace za účelem zpracování požadavků a odpovědí. Jednotlivé komponenty:

  • Zvolí, jestli se má žádost předat další komponentě v kanálu.
  • Může provádět práci před a za další komponentou v kanálu.

Delegáti žádostí se používají k sestavení kanálu požadavků. Delegát žádosti zpracuje jednotlivé požadavky HTTP.

Delegáti žádostí jsou nakonfigurováni pomocí Run Map Use metod rozšíření, a. Jednotlivé delegáty žádostí je možné zadat jako anonymní metodu (označovanou v rámci middlewarového middlewaru) nebo ji lze definovat 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á součást middlewaru v kanálu požadavků zodpovídá za vyvolání další komponenty v kanálu nebo při krátkém okruhu kanálu. Když jsou krátkodobé okruhy middleware, nazývá se middleware terminálu , protože zabrání dalšímu middlewaru ve zpracování žádosti.

migrace obslužných rutin a modulů HTTP do ASP.NET Core middlewaruvysvě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 pomocí IApplicationBuilder

kanál žádostí o ASP.NET Core se skládá z posloupnosti delegátů požadavků, který se nazývá jedna po druhé. Následující diagram znázorňuje koncept. Vlákno provádění následuje za černými šipkami.

Požadavek zpracování, který ukazuje, že se dorazí na požadavek, zpracovává se prostřednictvím tří middlewarů a odpověď opouští aplikaci Každý middleware spustí svou logiku a předá požadavek dalšímu middlewaru v příkazu Next (). Poté, co třetí middleware zpracuje požadavek, požadavek předá předchozí dva middleware v obráceném pořadí pro další zpracování po jejich dalších () příkazech před ukončením aplikace jako reakci na klienta.

Každý delegát může provádět operace před a po dalším delegátu. Delegáty zpracování výjimek by se měly volat v rámci kanálu na začátku, takže můžou zachytit výjimky, ke kterým dochází v pozdějších fázích kanálu.

nejjednodušší možná ASP.NET Core aplikace nastaví jediného delegáta žádosti, který zpracovává všechny požadavky. Tento případ nezahrnuje skutečný kanál žádostí. Místo toho je volána jedna anonymní funkce v reakci na každý požadavek HTTP.

public class Startup
{
    public void Configure(IApplicationBuilder app)
    {
        app.Run(async context =>
        {
            await context.Response.WriteAsync("Hello, World!");
        });
    }
}

Řetězení více požadavků delegátů společně s Use . nextParametr představuje dalšího delegáta v kanálu. Kanál můžete pro krátké okruhy vymezit tím , že nevoláte Další parametr. Obvykle můžete provádět akce před i po dalším delegátu, 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.");
        });
    }
}

Když delegát neprojde požadavek na dalšího delegáta, nazývá se to krátkodobý kanál žádosti. Krátkodobé okruhy jsou často žádoucí, protože brání zbytečné práci. Například middleware statických souborů může fungovat jako middleware terminálu tím, že zpracovává požadavek na statický soubor a krátký okruh zbývajících částí kanálu. Middleware přidané do kanálu předtím, než middleware, který ukončí další zpracování, stále zpracovává kód po svých next.Invoke příkazech. Přečtěte si ale následující upozornění týkající se pokusu o zápis do odpovědi, která již byla odeslána.

Upozornění

Nevolejte next.Invoke po odeslání odpovědi klientovi. Změny HttpResponse poté, co odpověď začala, vyvolávají výjimku. Například nastavení záhlaví a stavový kód vyvolávají výjimku. Zápis do těla odpovědi po volání next :

  • Může způsobit narušení protokolu. Například zápis více než uvedené Content-Length .
  • Může poškodit formát textu. Například zápis zápatí HTML do souboru CSS.

HasStarted je užitečnou nápovědou, která označuje, zda byla odeslána hlavička nebo zda byl text napsán do.

Run Delegáti neobdrží next parametr. První Run delegát je vždycky terminál a ukončí kanál. Run je konvence. Některé komponenty middlewaru můžou vystavovat Run[Middleware] metody, které se spouštějí 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ž angličtiny, dejte nám vědět v tomto problému diskuze na GitHubu.

V předchozím příkladu Run delegát zapisuje "Hello from 2nd delegate." do odpovědi a pak kanál ukončí. Pokud Use Run je po delegátu přidán jiný nebo delegát Run , není volán.

Pořadí middlewaru

následující diagram znázorňuje kompletní kanál zpracování požadavků pro ASP.NET Core aplikace MVC a Razor stránky. Můžete vidět, jak, v typické aplikaci jsou seřazené existující middleware a kdy se přidávají vlastní middleware. Máte plnou kontrolu nad tím, jak změnit pořadí stávajících middlewarů, nebo vložit nové vlastní middleware podle potřeby pro vaše scénáře.

ASP.NET Core kanál middlewaru

Middleware koncového bodu v předchozím diagramu spouští kanál filtru pro odpovídající typ aplikace — MVC nebo Razor stránky.

kanál filtru ASP.NET Core

Pořadí, v jakém jsou komponenty middleware přidány v Startup.Configure metodě, definuje pořadí, ve kterém jsou komponenty middleware vyvolány na žádostech a obráceném pořadí pro odpověď. Pořadí je důležité pro zabezpečení, výkon a funkčnost.

Následující metoda Startup.Configure přidá 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 zobrazí v tomto přesném pořadí, ale mnoho jich ano. Například:
    • UseCors, UseAuthentication a se musí zobrazovat v UseAuthorization zobrazeném pořadí.
    • UseCorsv současné době se musí UseResponseCaching zobrazit před touto chybou.
    • UseRequestLocalization musí být před libovolným middlewarem, který by mohl zkontrolovat jazykovou verzi požadavku (například app.UseMvcWithDefaultRoute() ).

V některých scénářích má middleware jiné řazení. Například ukládání do mezipaměti a řazení komprese je specifické pro konkrétní scénář a existuje několik platných objednávek. Například:

app.UseResponseCaching();
app.UseResponseCompression();

Pomocí předchozího kódu lze procesor uložit do mezipaměti pomocí komprimované odpovědi, ale můžete nakonec uložit do mezipaměti několik reprezentací prostředku pomocí různých kompresních algoritmů, jako je Gzip nebo Brotli.

Následující řazení kombinuje statické soubory, aby bylo možné ukládat komprimované statické soubory do mezipaměti:

app.UseResponseCaching();
app.UseResponseCompression();
app.UseStaticFiles();

Následující metoda Startup.Configure přidá middlewarové komponenty pro běžné scénáře aplikací:

  1. Zpracování výjimek nebo chyb
    • Když se aplikace spustí ve vývojovém prostředí:
      • Middleware stránky výjimky pro vývojáře ( UseDeveloperExceptionPage ) hlásí chyby modulu runtime aplikace.
      • Middleware databázové chybové stránky hlásí chyby modulu runtime databáze.
    • Když se aplikace spustí v produkčním prostředí:
      • Middleware obslužné rutiny výjimky ( UseExceptionHandler ) zachycuje výjimky vyvolané v následujících middlewarech.
      • Middleware HTTP Strict Transport Security Protocol (HSTS) ( UseHsts ) přidá Strict-Transport-Security hlavičku .
  2. Middleware pro přesměrování HTTPS ( UseHttpsRedirection ) přesměruje požadavky HTTP na HTTPS.
  3. Middleware statického souboru ( ) vrací statické soubory a UseStaticFiles krátké okruhy další zpracování požadavků.
  4. Cookie Middleware zásad ( ) odpovídá aplikaci předpisům UseCookiePolicy EU Obecné nařízení o ochraně osobních údajů (GDPR).
  5. Middleware směrování ( UseRouting ) pro směrování požadavků.
  6. Ověřovací middleware ( ) se pokusí uživatele ověřit, než mu bude povolen UseAuthentication přístup k zabezpečeným prostředkům.
  7. Autorizační middleware ( UseAuthorization ) autorizuje uživatele pro přístup k zabezpečeným prostředkům.
  8. Middleware relace ( UseSession ) vytváří a udržuje stav relace. Pokud aplikace používá stav relace, volejte middleware relace po middlewaru zásad a Cookie před middlewarem MVC.
  9. Middleware pro směrování koncových bodů ( s ) pro přidání koncových bodů UseEndpoints Pages MapRazorPages do Razor kanálu požadavku.
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 příkladu kódu je každá metoda rozšíření middlewaru zpřístupněna prostřednictvím IApplicationBuilder oboru Microsoft.AspNetCore.Builder názvů .

UseExceptionHandler je první komponenta middlewaru přidaná do kanálu. Middleware obslužné rutiny výjimky proto zachycuje všechny výjimky, ke kterým dojde v pozdějších voláních.

Middleware static file se volá v rané fázi kanálu, aby mohl zpracovávat požadavky a krátký okruh, aniž by prošel zbývajícími komponentami. Middleware statického souboru nemá žádné autorizační kontroly. Všechny soubory, které poskytuje middleware Static File, včetně souborů v rámci wwwroot, jsou veřejně dostupné. Přístup k zabezpečení statických souborů najdete v tématu Statické soubory v ASP.NET Core .

Pokud požadavek nezvládá middleware statického souboru, předá se ověřovacímu middlewaru ( ), který UseAuthentication provádí ověřování. Ověřování nezkrátí neověřené požadavky. I když ověřovací middleware ověřuje požadavky, autorizace (a zamítnutí) nastane až poté, co MVC vybere konkrétní kontroler stránky nebo MVC a Razor akci.

Následující příklad ukazuje pořadí middlewaru, ve kterém middleware před kompresí odpovědí zpracovává požadavky na statické soubory middlewarem statického souboru. Statické soubory nejsou v tomto pořadí middlewaru komprimované. 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();
    });
}

U jedno stránkových aplikací (SPA) je middleware SPA obvykle poslední v UseSpaStaticFiles middlewaru. Middleware SPA je poslední:

  • Aby všechny ostatní middleware mohly jako první reagovat na odpovídající požadavky.
  • Aby bylo možné spustit SSP se směrováním na straně klienta pro všechny trasy, které serverová aplikace nerozpozná.

Další podrobnosti o SSP najdete v příručkách pro šablony React a Angular projektů.

Pořadí middlewaru předáných hlaviček

Middleware předaných hlaviček by se měla spustit před jiným middlewarem. Toto řazení zajišťuje, aby middleware spoléhající se na předané informace hlaviček mohl spotřebovat hodnoty hlaviček pro zpracování. Pro spuštění předávaných middlewarových hlaviček po diagnostice a middlewaru zpracování chyb si přečtěte téma pořadí middlewaru u předaných hlaviček.

Větvení middlewarového kanálu

Map Rozšíření se používají jako konvence pro větvení kanálu. Map větví kanálu požadavku na základě shod dané cesty požadavku. Pokud cesta požadavku začíná danou 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. <p>");
        });
    }
}

V následující tabulce jsou uvedeny požadavky a odpovědi http://localhost:1234 z předchozího kódu.

Žádost Odpověď
localhost:1234 Hello z delegáta bez mapy
localhost:1234/map1 Test mapy 1
localhost:1234/map2 Test mapy 2
localhost:1234/map3 Hello z delegáta bez mapy

Při použití se odpovídající segmenty cesty pro každý požadavek odebraly a Map HttpRequest.Path HttpRequest.PathBase připojují k .

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 může také 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 větví kanálu 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 Func<HttpContext, bool> predikát typu. V následujícím příkladu se k detekci přítomnosti proměnné řetězce dotazu používá predikát 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. <p>");
        });
    }
}

V následující tabulce jsou uvedeny požadavky a odpovědi http://localhost:1234 z předchozího kódu:

Žádost Odpověď
localhost:1234 Hello z delegáta bez mapy
localhost:1234/?branch=main Použitá větev = main

UseWhen také větví kanálu požadavku na základě výsledku daného predikátu. Na rozdíl od systému se tato větev znovu připojí k hlavnímu kanálu, pokud nemá krátký okruh nebo neobsahuje MapWhen terminálový 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 zobrazí odpověď "Hello from main pipeline" (Dobrý den z hlavního kanálu). se zapisuje pro všechny požadavky. Pokud požadavek obsahuje proměnnou řetězce dotazu , její hodnota se zaprotokoluje před tím, než se hlavní branch kanál znovu připojí.

Integrovaný middleware

ASP.NET Core se dodává s následujícími komponentami middlewaru. Sloupec Order (Objednávka) obsahuje poznámky k umístění middlewaru v kanálu zpracování požadavků a za jakých podmínek může middleware zpracování požadavků ukončit. Když middleware zkrátí kanál zpracování požadavků a zabrání dalšímu zpracování požadavku podřízenému middlewaru, nazývá se to terminální middleware. Další informace o zkrácení najdete v části Vytvoření middlewarového kanálu pomocí IApplicationBuilder.

Middleware Description Objednávka
Authentication Poskytuje podporu ověřování. Než HttpContext.User bude potřeba. Terminál pro zpětná volání OAuth.
Autorizace Poskytuje podporu autorizace. Ihned po ověřovacím middlewaru.
Cookie Zásad Sleduje souhlas uživatelů s ukládáním osobních údajů a vynucuje minimální standardy pro cookie pole, jako je a secure SameSite . Před middlewarem, u které cookie k problémům došl. Příklady: Ověřování, relace, MVC (TempData).
CORS Nakonfiguruje sdílení prostředků mezi zdroji. Před komponentami, které používají CORS. UseCorsv současné době je nutné UseResponseCaching kvůli této chybě přejít před .
Diagnostika Několik samostatných middlewarů, které poskytují stránku výjimek pro vývojáře, zpracování výjimek, stránky stavového kódu a výchozí webovou stránku pro nové aplikace. Před komponentami, které generují chyby. Terminál pro výjimky nebo obsluhující výchozí webovou stránku pro nové aplikace
Předáná záhlaví Předá hlavičky proxied aktuálnímu požadavku. 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 její závislosti, například kontroluje dostupnost databáze. Terminál, pokud požadavek odpovídá koncovému bodu kontroly stavu
Šíření hlaviček Rozšíří hlavičky HTTP z příchozího požadavku na odchozí požadavky klienta HTTP.
Přepsání metody HTTP Umožňuje příchozímu požadavku POST přepsat metodu . Před komponentami, které využívají aktualizovanou metodu.
Přesměrování HTTPS Přesměrovat všechny požadavky HTTP na HTTPS. Před komponentami, které adresu URL využívají.
Http Strict Transport Security (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é upravuje požadavky. Příklady: Předánaná záhlaví, Přepis adres URL.
MVC Zpracovává požadavky pomocí MVC/ Razor stránek. Terminál, pokud požadavek odpovídá trase
OWIN Spolupráce s aplikacemi, servery a middlewarem založenými na OWIN Terminál, pokud middleware OWIN plně zpracuje požadavek.
Odpověď Ukládání do mezipaměti Poskytuje podporu pro ukládání odpovědí do mezipaměti. Před komponentami, které vyžadují ukládání do mezipaměti. UseCORS musí předchádovat UseResponseCaching před .
Komprese odpovědí Poskytuje podporu pro komprimaci odpovědí. Před komponentami, které vyžadují kompresi.
Lokalizace požadavku Poskytuje podporu lokalizace. Před lokalizací citlivých komponent. Při použití se musí zobrazit po middlewaru RouteDataRequestCultureProvider směrování.
Směrování koncového bodu Definuje a omezuje trasy požadavků. Terminál pro odpovídající trasy.
SPA Zpracovává všechny požadavky od tohoto bodu v řetězci middlewaru vrácením výchozí stránky jedno stránkovací aplikace (SPA). V pozdější části řetězu má přednost jiný middleware pro obsluhu statických souborů, akcí MVC atd.
Relace Poskytuje podporu pro správu uživatelských relací. Před součástmi, které vyžadují relaci.
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 žádosti o přesměrování. Před komponentami, které adresu URL využívají.
WebSockets Povolí protokol WebSocket. Před komponentami, které jsou potřeba k přijetí požadavků WebSocket.

Další zdroje informací