Směrování v ASP.NET Core
Ryan Nowak, Kirk Larkin a Rick Anderson
Poznámka:
Toto není nejnovější verze tohoto článku. Aktuální verzi najdete v tomto článku ve verzi .NET 9.
Upozorňující
Tato verze ASP.NET Core se už nepodporuje. Další informace najdete v zásadách podpory .NET a .NET Core. Aktuální verzi najdete v tomto článku ve 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í.
Aktuální verzi najdete v tomto článku ve verzi .NET 9.
Směrování zodpovídá za porovnávání příchozích požadavků HTTP a odesílání těchto požadavků do spustitelných koncových bodů aplikace. Koncové body jsou jednotky spustitelného kódu zpracování požadavků. Koncové body se definují v aplikaci a konfigurují se při spuštění aplikace. Proces porovnávání koncových bodů může extrahovat hodnoty z adresy URL požadavku a poskytnout tyto hodnoty pro zpracování požadavků. Pomocí informací o koncovém bodu z aplikace je směrování také schopné generovat adresy URL, které se mapují na koncové body.
Aplikace můžou nakonfigurovat směrování pomocí:
- Kontrolery
- Razor Pages
- SignalR
- gRPC Services
- Middleware s povoleným koncovým bodem, jako jsou kontroly stavu.
- Delegáti a lambda zaregistrované ve směrování
Tento článek se zabývá podrobnostmi nízké úrovně směrování ASP.NET Core. Informace o konfiguraci směrování:
- Informace o kontroleru najdete v tématu Směrování na akce kontroleru v ASP.NET Core.
- Konvence Razor stránek najdete v tématu Razor Stránky trasy a konvence aplikací v ASP.NET Core.
- Pokyny Blazor ke směrování, které se přidávají nebo nahrazují pokyny v tomto článku, najdete v tématu ASP.NET Blazor Základní směrování a navigace.
Základy směrování
Následující kód ukazuje základní příklad směrování:
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
app.MapGet("/", () => "Hello World!");
app.Run();
Předchozí příklad obsahuje jeden koncový bod pomocí MapGet metody:
- Při odeslání požadavku HTTP
GET
na kořenovou adresu URL/
:- Delegát požadavku se spustí.
Hello World!
je zapsán do odpovědi HTTP.
- Pokud metoda požadavku není
GET
nebo kořenová adresa URL není/
, žádná trasa neodpovídá a vrátí se http 404.
Směrování používá dvojici middlewaru, zaregistrovaného uživatelem UseRouting a UseEndpoints:
UseRouting
přidá trasu odpovídající kanálu middlewaru. Tento middleware se podívá na sadu koncových bodů definovaných v aplikaci a vybere nejlepší shodu na základě požadavku.UseEndpoints
přidá spuštění koncového bodu do kanálu middlewaru. Spustí delegáta přidruženého k vybranému koncovému bodu.
Aplikace obvykle nemusí volat UseRouting
ani UseEndpoints
. WebApplicationBuilder konfiguruje middlewarový kanál, který zabalí middleware přidaný do Program.cs
UseRouting
a UseEndpoints
. Aplikace ale můžou změnit pořadí, ve kterém UseRouting
se budou spouštět, UseEndpoints
a to explicitním voláním těchto metod. Například následující kód provede explicitní volání UseRouting
:
app.Use(async (context, next) =>
{
// ...
await next(context);
});
app.UseRouting();
app.MapGet("/", () => "Hello World!");
V předchozím kódu:
- Volání pro
app.Use
registraci vlastního middlewaru, který se spouští na začátku kanálu. - Volání konfiguruje
UseRouting
middleware odpovídající směrování tak, aby se spustil po vlastním middlewaru. - Koncový bod zaregistrovaný na
MapGet
konci kanálu se spustí.
Pokud by předchozí příklad nezahrnoval volání UseRouting
, vlastní middleware by se spustil za middlewarem odpovídajícím trasě.
Poznámka: Trasy přidané přímo ke WebApplication spuštění na konci kanálu.
Koncové body
Metoda MapGet
se používá k definování koncového bodu. Koncový bod je něco, co může být:
- Vybráno tak, že se shoduje s adresou URL a metodou HTTP.
- Spustí se spuštěním delegáta.
Koncové body, které se dají spárovat a spouštět aplikací, jsou nakonfigurované v UseEndpoints
. Například MapGet, MapPosta podobné metody připojit žádosti delegáty do systému směrování. Další metody lze použít k připojení funkcí architektury ASP.NET Core ke směrovacímu systému:
- MapRazorPages for Razor Pages
- MapControllers pro kontrolery
- MapHub THub<> forSignalR
- MapGrpcService TService<> pro gRPC
Následující příklad ukazuje směrování s sofistikovanější šablonou trasy:
app.MapGet("/hello/{name:alpha}", (string name) => $"Hello {name}!");
Řetězec /hello/{name:alpha}
je šablona trasy. Ke konfiguraci shody koncového bodu se používá šablona trasy. V tomto případě šablona odpovídá:
- Adresa URL, jako je
/hello/Docs
- Všechny cesty URL, které začínají
/hello/
posloupností abecedních znaků.:alpha
použije omezení trasy, které odpovídá pouze abecedním znakům. Omezení tras jsou vysvětlena dále v tomto článku.
Druhý segment cesty URL: {name:alpha}
- Je vázán na
name
parametr. - Je zachycen a uložen v HttpRequest.RouteValues.
Následující příklad ukazuje směrování s kontrolami stavu a autorizací:
app.UseAuthentication();
app.UseAuthorization();
app.MapHealthChecks("/healthz").RequireAuthorization();
app.MapGet("/", () => "Hello World!");
Předchozí příklad ukazuje, jak:
- S směrováním je možné použít autorizační middleware.
- Koncové body je možné použít ke konfiguraci chování autorizace.
Volání MapHealthChecks přidá koncový bod kontroly stavu. Při zřetězování RequireAuthorization k tomuto volání se ke koncovému bodu připojí zásady autorizace.
Volání UseAuthentication a UseAuthorization přidání middlewaru pro ověřování a autorizaci Tyto middleware jsou umístěny mezi UseRouting a UseEndpoints
tak, aby mohly:
- Podívejte se, který koncový bod vybral
UseRouting
. - Před odesláním do koncového bodu použijte zásadu UseEndpoints autorizace.
Metadata koncového bodu
V předchozím příkladu existují dva koncové body, ale k autorizační zásadě jsou připojené jenom koncové body kontroly stavu. Pokud požadavek odpovídá koncovému bodu kontroly stavu, /healthz
provede se kontrola autorizace. To ukazuje, že koncové body můžou mít připojená další data. Tato další data se nazývají metadata koncového bodu:
- Metadata je možné zpracovat pomocí middlewaru pracujícího se směrováním.
- Metadata můžou být libovolného typu .NET.
Koncepty směrování
Systém směrování vychází z kanálu middlewaru přidáním výkonného konceptu koncového bodu . Koncové body představují jednotky funkcí aplikace, které se vzájemně liší z hlediska směrování, autorizace a libovolného počtu systémů ASP.NET Core.
Definice koncového bodu ASP.NET Core
Koncový bod ASP.NET Core je:
- Spustitelný soubor: Má .RequestDelegate
- Rozšiřitelný: Má kolekci metadat .
- Možnost výběru: Volitelně obsahuje informace o směrování.
- Výčet: Kolekci koncových bodů je možné uvést načtením EndpointDataSource z DI.
Následující kód ukazuje, jak načíst a zkontrolovat koncový bod odpovídající aktuálnímu požadavku:
app.Use(async (context, next) =>
{
var currentEndpoint = context.GetEndpoint();
if (currentEndpoint is null)
{
await next(context);
return;
}
Console.WriteLine($"Endpoint: {currentEndpoint.DisplayName}");
if (currentEndpoint is RouteEndpoint routeEndpoint)
{
Console.WriteLine($" - Route Pattern: {routeEndpoint.RoutePattern}");
}
foreach (var endpointMetadata in currentEndpoint.Metadata)
{
Console.WriteLine($" - Metadata: {endpointMetadata}");
}
await next(context);
});
app.MapGet("/", () => "Inspect Endpoint.");
Koncový bod, pokud je vybraný, lze načíst z objektu HttpContext
. Jeho vlastnosti je možné zkontrolovat. Objekty koncového bodu jsou neměnné a po vytvoření není možné je změnit. Nejběžnějším typem RouteEndpointkoncového bodu je . RouteEndpoint
obsahuje informace, které mu umožní vybrat směrovací systém.
V předchozím kódu aplikace. Slouží ke konfiguraci vloženého middlewaru.
Následující kód ukazuje, že v závislosti na tom, kde app.Use
se v kanálu volá, nemusí existovat koncový bod:
// Location 1: before routing runs, endpoint is always null here.
app.Use(async (context, next) =>
{
Console.WriteLine($"1. Endpoint: {context.GetEndpoint()?.DisplayName ?? "(null)"}");
await next(context);
});
app.UseRouting();
// Location 2: after routing runs, endpoint will be non-null if routing found a match.
app.Use(async (context, next) =>
{
Console.WriteLine($"2. Endpoint: {context.GetEndpoint()?.DisplayName ?? "(null)"}");
await next(context);
});
// Location 3: runs when this endpoint matches
app.MapGet("/", (HttpContext context) =>
{
Console.WriteLine($"3. Endpoint: {context.GetEndpoint()?.DisplayName ?? "(null)"}");
return "Hello World!";
}).WithDisplayName("Hello");
app.UseEndpoints(_ => { });
// Location 4: runs after UseEndpoints - will only run if there was no match.
app.Use(async (context, next) =>
{
Console.WriteLine($"4. Endpoint: {context.GetEndpoint()?.DisplayName ?? "(null)"}");
await next(context);
});
Předchozí ukázka přidá Console.WriteLine
příkazy, které zobrazují, jestli byl vybrán koncový bod nebo ne. Pro přehlednost ukázka přiřadí zadaný koncový bod zobrazovaný název /
.
Předchozí ukázka také zahrnuje volání UseRouting
a UseEndpoints
řízení přesně toho, kdy se tyto middlewary spouští v rámci kanálu.
Spuštění tohoto kódu s adresou URL /
zobrazení:
1. Endpoint: (null)
2. Endpoint: Hello
3. Endpoint: Hello
Spuštění tohoto kódu s jakoukoli jinou adresou URL zobrazí:
1. Endpoint: (null)
2. Endpoint: (null)
4. Endpoint: (null)
Tento výstup ukazuje, že:
- Koncový bod je před zavolání vždy null
UseRouting
. - Pokud se najde shoda, koncový bod je mezi
UseRouting
a UseEndpoints. - Middleware
UseEndpoints
je terminál , když se najde shoda. Middleware terminálu je definován dále v tomto článku. - Middleware po spuštění pouze v
UseEndpoints
případě, že nebyla nalezena žádná shoda.
Middleware UseRouting
používá metodu SetEndpoint pro připojení koncového bodu k aktuálnímu kontextu. Middleware je možné nahradit UseRouting
vlastní logikou a přesto získat výhody používání koncových bodů. Koncové body jsou primitivní nízké úrovně, jako je middleware, a nejsou svázané s implementací směrování. Většina aplikací nemusí nahradit UseRouting
vlastní logikou.
Middleware UseEndpoints
je navržený tak, aby se používal společně s middlewarem UseRouting
. Základní logika pro spuštění koncového bodu není složitá. Slouží GetEndpoint k načtení koncového bodu a následnému vyvolání jeho RequestDelegate vlastnosti.
Následující kód ukazuje, jak může middleware ovlivnit nebo reagovat na směrování:
app.UseHttpMethodOverride();
app.UseRouting();
app.Use(async (context, next) =>
{
if (context.GetEndpoint()?.Metadata.GetMetadata<RequiresAuditAttribute>() is not null)
{
Console.WriteLine($"ACCESS TO SENSITIVE DATA AT: {DateTime.UtcNow}");
}
await next(context);
});
app.MapGet("/", () => "Audit isn't required.");
app.MapGet("/sensitive", () => "Audit required for sensitive data.")
.WithMetadata(new RequiresAuditAttribute());
public class RequiresAuditAttribute : Attribute { }
Předchozí příklad ukazuje dva důležité koncepty:
- Middleware se může spustit před
UseRouting
úpravou dat, se kterými směrování pracuje.- Obvykle middleware, který se zobrazí před úpravou směrování některé vlastnosti požadavku, například UseRewriter, UseHttpMethodOverridenebo UsePathBase.
- Middleware se může spustit mezi
UseRouting
směrováním a UseEndpoints zpracovat výsledky směrování před spuštěním koncového bodu.- Middleware, který běží mezi
UseRouting
aUseEndpoints
:- Obvykle kontroluje metadata, aby porozuměla koncovým bodům.
- Často provádí rozhodnutí o zabezpečení, jak to dělá
UseAuthorization
aUseCors
.
- Kombinace middlewaru a metadat umožňuje konfigurovat zásady pro jednotlivé koncové body.
- Middleware, který běží mezi
Předchozí kód ukazuje příklad vlastního middlewaru, který podporuje zásady pro jednotlivé koncové body. Middleware zapíše protokol auditu přístupu k citlivým datům do konzoly. Middleware je možné nakonfigurovat tak, aby auditoval koncový bod s RequiresAuditAttribute
metadaty. Tato ukázka ukazuje způsob vyjádření výslovného souhlasu, kdy se auditují jenom koncové body označené jako citlivé. Tuto logiku je možné definovat obráceně, auditovat všechno, co není označené jako bezpečné, například. Systém metadat koncového bodu je flexibilní. Tato logika by mohla být navržena jakýmkoli způsobem, který vyhovuje případu použití.
Předchozí vzorový kód je určený k předvedení základních konceptů koncových bodů. Ukázka není určená pro produkční použití. Ucelenější verze middlewaru protokolu auditu:
- Přihlaste se k souboru nebo databázi.
- Uveďte podrobnosti, jako je uživatel, IP adresa, název citlivého koncového bodu a další.
Metadata zásad auditu jsou definována RequiresAuditAttribute
jako Attribute
jednodušší použití s architekturami založenými na třídách, jako jsou kontrolery a SignalR. Při použití trasy ke kódu:
- Metadata jsou připojena pomocí rozhraní API tvůrce.
- Architektury založené na třídách zahrnují všechny atributy odpovídající metody a třídy při vytváření koncových bodů.
Osvědčenými postupy pro typy metadat je definovat buď jako rozhraní, nebo atributy. Rozhraní a atributy umožňují opakované použití kódu. Systém metadat je flexibilní a neukládá žádná omezení.
Porovnání middlewaru terminálu se směrováním
Následující příklad ukazuje terminálový middleware i směrování:
// Approach 1: Terminal Middleware.
app.Use(async (context, next) =>
{
if (context.Request.Path == "/")
{
await context.Response.WriteAsync("Terminal Middleware.");
return;
}
await next(context);
});
app.UseRouting();
// Approach 2: Routing.
app.MapGet("/Routing", () => "Routing.");
Styl middlewaru zobrazeného s terminálovým middlewarem Approach 1:
. Říká se tomu middleware terminálu, protože dělá odpovídající operaci:
- Odpovídající operace v předchozí ukázce je
Path == "/"
pro middleware aPath == "/Routing"
pro směrování. - Když je shoda úspěšná, spustí některé funkce a vrátí se místo vyvolání middlewaru
next
.
Říká se tomu middleware terminálu, protože ukončí hledání, spustí některé funkce a vrátí se.
Následující seznam porovnává middleware terminálu se směrováním:
- Oba přístupy umožňují ukončení kanálu zpracování:
- Middleware ukončí kanál tím, že se místo vyvolání
next
. - Koncové body jsou vždy terminálové.
- Middleware ukončí kanál tím, že se místo vyvolání
- Middleware terminálu umožňuje umístění middlewaru na libovolné místo v kanálu:
- Koncové body se provádějí na pozici UseEndpoints.
- Middleware terminálu umožňuje libovolnému kódu určit, kdy middleware odpovídá:
- Vlastní kód pro porovnávání tras může být podrobný a obtížně zapisuje správně.
- Směrování poskytuje jednoduchá řešení pro typické aplikace. Většina aplikací nevyžaduje vlastní kód pro porovnávání tras.
- Rozhraní koncových bodů s middlewarem, jako
UseAuthorization
je například aUseCors
.- Použití middlewaru terminálu s
UseAuthorization
autorizačním systémem neboUseCors
vyžaduje ruční propojení se systémem autorizace.
- Použití middlewaru terminálu s
Koncový bod definuje obojí:
- Delegát na zpracování požadavků.
- Kolekce libovolných metadat. Metadata se používají k implementaci průřezových aspektů na základě zásad a konfigurace připojených k jednotlivým koncovým bodům.
Terminálový middleware může být efektivní nástroj, ale může vyžadovat:
- Značné množství kódování a testování.
- Ruční integrace s jinými systémy za účelem dosažení požadované úrovně flexibility.
Před zápisem middlewaru terminálu zvažte integraci se směrováním.
Existující middleware terminálu, který se integruje s mapou , nebo MapWhen se obvykle dá převést na koncový bod podporující směrování. MapHealthChecks ukazuje vzor pro router-ware:
- Napište metodu rozšíření na IEndpointRouteBuilder.
- Vytvoření vnořeného kanálu middlewaru pomocí CreateApplicationBuilder.
- Připojte middleware k novému kanálu. V tomto případě . UseHealthChecks
- Buildmiddlewarový kanál do .RequestDelegate
- Zavolejte a poskytněte
Map
nový kanál middlewaru. - Vrátí objekt tvůrce poskytnutý
Map
metodou rozšíření.
Následující kód ukazuje použití MapHealthChecks:
app.UseAuthentication();
app.UseAuthorization();
app.MapHealthChecks("/healthz").RequireAuthorization();
Předchozí ukázka ukazuje, proč je vrácení objektu tvůrce důležité. Vrácení objektu tvůrce umožňuje vývojáři aplikací konfigurovat zásady, jako je autorizace pro koncový bod. V tomto příkladu nemá middleware kontroly stavu žádnou přímou integraci se systémem autorizace.
Systém metadat byl vytvořen v reakci na problémy zjištěné autory rozšiřitelnosti pomocí middlewaru terminálu. Pro každý middleware je problematické implementovat vlastní integraci s autorizačním systémem.
Porovnávání adres URL
- Je proces, kterým směrování odpovídá příchozímu požadavku na koncový bod.
- Je založená na datech v cestě URL a hlavičkách.
- Můžete ho rozšířit, abyste zvážili všechna data v požadavku.
Když se spustí middleware směrování, nastaví Endpoint
hodnotu požadavku na funkci HttpContext požadavku z aktuálního požadavku:
- Volání httpContext.GetEndpoint získá koncový bod.
HttpRequest.RouteValues
získá kolekci hodnot tras.
Middleware, který se spustí po spuštění middlewaru směrování, může zkontrolovat koncový bod a provést akci. Například autorizační middleware může probrat kolekci metadat koncového bodu pro zásady autorizace. Po spuštění veškerého middlewaru v kanálu zpracování požadavků se vyvolá delegát vybraného koncového bodu.
Systém směrování ve směrování koncového bodu zodpovídá za veškerá rozhodnutí o odesílání. Vzhledem k tomu, že middleware používá zásady na základě vybraného koncového bodu, je důležité, aby:
- Jakékoli rozhodnutí, které může ovlivnit odesílání nebo použití zásad zabezpečení, se provádí v rámci systému směrování.
Upozorňující
V případě zpětné kompatibility se při spuštění delegáta koncového RouteContext.RouteData bodu kontroleru nebo Razor stránky nastaví vlastnosti na odpovídající hodnoty na základě dosud provedeného zpracování požadavku.
Typ RouteContext
bude v budoucí verzi označen jako zastaralý:
- Migrovat
RouteData.Values
naHttpRequest.RouteValues
. - Migrace
RouteData.DataTokens
pro načtení IDataTokensMetadata z metadat koncového bodu
Porovnávání adres URL funguje v konfigurovatelné sadě fází. V každé fázi je výstup sadou shod. Sadu shod lze dále zúžit v další fázi. Implementace směrování nezaručuje pořadí zpracování pro odpovídající koncové body. Všechny možné shody se zpracovávají najednou. Fáze porovnávání adres URL probíhají v následujícím pořadí. ASP.NET Core:
- Zpracovává cestu URL vůči sadě koncových bodů a jejich šablon tras a shromažďuje všechny shody.
- Vezme předchozí seznam a odebere shody, které selžou s použitými omezeními trasy.
- Vezme předchozí seznam a odebere shody, které sadu instancí selžou MatcherPolicy .
- EndpointSelector Použije k poslednímu rozhodnutí z předchozího seznamu.
Seznam koncových bodů má prioritu podle následujících:
- RouteEndpoint.Order
- Priorita šablony trasy
Všechny odpovídající koncové body se zpracovávají v každé fázi, dokud se nedosáhne EndpointSelector . Jedná se EndpointSelector
o konečnou fázi. Jako nejlepší shodu zvolí koncový bod s nejvyšší prioritou. Pokud existují jiné shody se stejnou prioritou jako nejlepší shoda, vyvolá se výjimka nejednoznačné shody.
Priorita trasy se vypočítá na základě konkrétnější šablony trasy, která má vyšší prioritu. Představte si například šablony /hello
a /{message}
:
- Obě odpovídají cestě
/hello
URL . /hello
je konkrétnější a proto vyšší priorita.
Obecně platí, že priorita trasy má dobrou úlohu při výběru nejvhodnější shody pro druhy schémat adres URL používaných v praxi. Používejte Order pouze v případě potřeby, abyste se vyhnuli nejednoznačnosti.
Vzhledem k druhům rozšiřitelnosti poskytované směrováním není možné, aby směrovací systém předem počítaly nejednoznačné trasy. Představte si příklad, jako jsou šablony /{message:alpha}
tras a /{message:int}
:
- Omezení
alpha
odpovídá pouze abecedním znakům. - Omezení
int
odpovídá pouze číslu. - Tyto šablony mají stejnou prioritu tras, ale obě adresy URL se neshodují.
- Pokud systém směrování nahlásil při spuštění nejednoznačnosti, zablokoval by tento platný případ použití.
Upozorňující
Pořadí operací uvnitř UseEndpoints nemá vliv na chování směrování, s jednou výjimkou. MapControllerRoute a MapAreaRoute automaticky přiřadí hodnotu objednávky ke svým koncovým bodům na základě pořadí, ve které jsou vyvolány. To simuluje dlouhodobé chování kontrolerů bez systému směrování, který poskytuje stejné záruky jako starší implementace směrování.
Směrování koncových bodů v ASP.NET Core:
- Nemá koncept tras.
- Neposkytuje záruky objednávání. Všechny koncové body se zpracovávají najednou.
Priorita šablony trasy a pořadí výběru koncového bodu
Priorita šablony trasy je systém, který každé šabloně trasy přiřadí hodnotu na základě toho, jak je konkrétní. Priorita šablony trasy:
- Vyhne se nutnosti upravovat pořadí koncových bodů v běžných případech.
- Snaží se shodovat s očekáváními obecného chování směrování.
Představte si například šablony /Products/List
a /Products/{id}
. Bylo by rozumné předpokládat, že /Products/List
je lepší shoda než /Products/{id}
pro cestu /Products/List
URL . To funguje, protože literálový segment /List
je považován za lepší prioritu než segment /{id}
parametru .
Podrobnosti o tom, jak funguje priorita, jsou svázány s tím, jak se definují šablony tras:
- Šablony s více segmenty jsou považovány za konkrétnější.
- Segment s literálovým textem se považuje za konkrétnější než segment parametru.
- Segment parametru s omezením se považuje za konkrétnější než jeden bez.
- Složitý segment se považuje za specifický jako segment parametru s omezením.
- Parametry pro zachytávání jsou nejmíň specifické. Důležité informace o trasách pro zachytávání všech tras najdete v části Šablony tras catch-all.
Koncepty generování adres URL
Generování adres URL:
- Je proces, pomocí kterého směrování může vytvořit cestu URL na základě sady hodnot tras.
- Umožňuje logické oddělení mezi koncovými body a adresami URL, které k nim přistupují.
Směrování koncových bodů zahrnuje LinkGenerator rozhraní API. LinkGenerator
je jednoúčelová služba, která je k dispozici z DI. Rozhraní LinkGenerator
API se dá použít mimo kontext spuštěného požadavku. Mvc.IUrlHelper a scénáře, které se spoléhají , IUrlHelperjako jsou pomocné rutiny značek, pomocné rutiny HTML a výsledky akcí, používají LinkGenerator
rozhraní API interně k poskytování možností generování odkazů.
Generátor odkazů je podporován konceptem adresního a adresního schématu. Schéma adres je způsob, jak určit koncové body, které by se měly zvážit pro generování propojení. Například scénáře názvu trasy a směrovacích hodnot, které mnoho uživatelů znáte z kontrolerů a Razor Stránky se implementují jako schéma adres.
Generátor odkazů může odkazovat na kontrolery a Razor stránky pomocí následujících rozšiřujících metod:
Přetížení těchto metod přijímají argumenty, které zahrnují HttpContext
. Tyto metody jsou funkčně ekvivalentní url.Action a Url.Page, ale nabízejí další flexibilitu a možnosti.
Metody GetPath*
jsou nejvíce podobné Url.Action
a Url.Page
v tom, že vygenerují identifikátor URI obsahující absolutní cestu. Metody GetUri*
vždy generují absolutní identifikátor URI obsahující schéma a hostitele. Metody, které přijímají HttpContext
vygenerování identifikátoru URI v kontextu prováděcího požadavku. Hodnoty okolní trasy, základní cesta URL, schéma a hostitel ze spuštěného požadavku se použijí, pokud je nepřepíšete.
LinkGenerator je volána s adresou. Generování identifikátoru URI probíhá ve dvou krocích:
- Adresa je svázaná se seznamem koncových bodů, které odpovídají adrese.
- Vyhodnocuje se RoutePattern každý koncový bod, dokud se nenajde vzor trasy, který odpovídá zadaným hodnotám. Výsledný výstup se zkombinuje s ostatními částmi identifikátoru URI zadanými do generátoru propojení a vrátí se.
Metody poskytované standardními možnostmi LinkGenerator generování propojení pro libovolný typ adresy. Nejpohodlnější způsob použití generátoru propojení je prostřednictvím rozšiřujících metod, které provádějí operace pro konkrétní typ adresy:
Extension – metoda | Popis |
---|---|
GetPathByAddress | Vygeneruje identifikátor URI s absolutní cestou na základě zadaných hodnot. |
GetUriByAddress | Vygeneruje absolutní identifikátor URI na základě zadaných hodnot. |
Upozorňující
Věnujte pozornost následujícím důsledkům volání LinkGenerator metod:
V konfiguraci aplikace používejte
GetUri*
metody rozšíření s opatrností, která neověřuje hlavičkuHost
příchozích požadavků. Pokud hlavičkaHost
příchozích požadavků není ověřená, může být nedůvěryhodný vstup požadavku odeslán zpět klientovi v identifikátorech URI v zobrazení nebo stránce. Doporučujeme, aby všechny produkční aplikace nakonfigurovaly svůj server tak, aby ověřovaly hlavičkuHost
proti známým platným hodnotám.Používejte LinkGenerator s opatrností v middlewaru v kombinaci s
Map
neboMapWhen
.Map*
změní základní cestu prováděcího požadavku, která má vliv na výstup generování propojení. LinkGenerator Všechna rozhraní API umožňují zadat základní cestu. Zadejte prázdnouMap*
základní cestu, která vrátí zpět vliv na generování propojení.
Příklad middlewaru
V následujícím příkladu middleware používá LinkGenerator rozhraní API k vytvoření odkazu na metodu akce, která obsahuje seznam produktů pro ukládání. Použití generátoru odkazů vložením do třídy a volání GenerateLink
je k dispozici pro libovolnou třídu v aplikaci:
public class ProductsMiddleware
{
private readonly LinkGenerator _linkGenerator;
public ProductsMiddleware(RequestDelegate next, LinkGenerator linkGenerator) =>
_linkGenerator = linkGenerator;
public async Task InvokeAsync(HttpContext httpContext)
{
httpContext.Response.ContentType = MediaTypeNames.Text.Plain;
var productsPath = _linkGenerator.GetPathByAction("Products", "Store");
await httpContext.Response.WriteAsync(
$"Go to {productsPath} to see our products.");
}
}
Šablony tras
Tokeny v rámci {}
definují parametry trasy, které jsou vázané, pokud se trasa shoduje. V segmentu trasy je možné definovat více než jeden parametr trasy, ale parametry trasy musí být oddělené hodnotou literálu. Příklad:
{controller=Home}{action=Index}
není platná trasa, protože neexistuje žádná hodnota literálu mezi {controller}
a {action}
. Parametry trasy musí mít název a mohou mít zadané další atributy.
Literál jiný než směrovací parametry (například {id}
) a oddělovač /
cesty musí odpovídat textu v adrese URL. Porovnávání textu nerozlišuje malá a velká písmena a vychází z dekódované reprezentace cesty adresy URL. Chcete-li se shodovat s oddělovačem {
parametru trasy literálu nebo }
, uchytáte oddělovač opakováním znaku. Například {{
nebo }}
.
Hvězdička *
nebo dvojitá hvězdička **
:
- Lze použít jako předponu parametru trasy pro vazbu na rest identifikátor URI.
- Nazývají se parametry catch-all. Příklad:
blog/{**slug}
- Odpovídá libovolnému identifikátoru
blog/
URI, který začíná a má za ním libovolnou hodnotu. - Následující hodnota
blog/
je přiřazena ke slug směrovací hodnotě.
- Odpovídá libovolnému identifikátoru
Upozorňující
Parametr catch-all může nesprávně odpovídat trasám kvůli chybě při směrování. Aplikace ovlivněné touto chybou mají následující charakteristiky:
- Například trasa pro zachytávání– vše
{**slug}"
- Trasa catch-all neodpovídá požadavkům, které by se měly shodovat.
- Odebráním jiných tras začne fungovat zachytávání všech tras.
Podívejte se na chyby GitHubu 18677 a 16579 , například případy, které tuto chybu narazily.
Oprava výslovného souhlasu s touto chybou je obsažená v sadě .NET Core 3.1.301 SDK a novějších verzích. Následující kód nastaví interní přepínač, který tuto chybu opraví:
public static void Main(string[] args)
{
AppContext.SetSwitch("Microsoft.AspNetCore.Routing.UseCorrectCatchAllBehavior",
true);
CreateHostBuilder(args).Build().Run();
}
// Remaining code removed for brevity.
Parametry catch-all mohou také odpovídat prázdnému řetězci.
Parametr catch-all umisťuje příslušné znaky při použití trasy k vygenerování adresy URL, včetně znaků oddělovače /
cest. Například trasa foo/{*path}
s hodnotami { path = "my/path" }
trasy generuje foo/my%2Fpath
. Všimněte si řídicího lomítka. Pokud chcete znaky oddělovače cest odezvy použít předponu parametru **
trasy. Trasa foo/{**path}
s { path = "my/path" }
vygenerovanými .foo/my/path
Vzory adres URL, které se pokoušejí zachytit název souboru s volitelnou příponou souboru, mají další důležité informace. Představte si například šablonu files/{filename}.{ext?}
. Když hodnoty obou filename
hodnot existují ext
, naplní se obě hodnoty. Pokud v adrese URL existuje jenom hodnota filename
, trasa se shoduje, protože koncové hodnoty .
jsou volitelné. Následující adresy URL odpovídají této trase:
/files/myFile.txt
/files/myFile
Parametry trasy můžou mít výchozí hodnoty určené zadáním výchozí hodnoty za názvem parametru odděleným symbolem rovná se (=
). Například {controller=Home}
definuje Home
jako výchozí hodnotu pro controller
. Výchozí hodnota se použije, pokud v adrese URL parametru není žádná hodnota. Parametry trasy jsou volitelné připojením otazníku (?
) na konec názvu parametru. Například id?
. Rozdíl mezi volitelnými hodnotami a výchozími parametry trasy je:
- Parametr trasy s výchozí hodnotou vždy vytvoří hodnotu.
- Volitelný parametr má hodnotu pouze v případě, že je hodnota poskytována adresou URL požadavku.
Parametry trasy můžou mít omezení, která musí odpovídat hodnotě trasy vázané z adresy URL. Přidání :
a omezení názvu za názvem parametru trasy určuje vložené omezení parametru trasy. Pokud omezení vyžaduje argumenty, jsou za názvem omezení uzavřeny v závorkách (...)
. Více vložených omezení lze zadat připojením jiného :
názvu a názvu omezení.
Název omezení a argumenty se předávají službě IInlineConstraintResolver , aby se vytvořila instance IRouteConstraint , která se má použít při zpracování adresy URL. Například šablona blog/{article:minlength(10)}
trasy určuje minlength
omezení s argumentem 10
. Další informace o omezeních tras a seznamu omezení poskytovaných architekturou najdete v části Omezení trasy.
Parametry trasy mohou mít také transformátory parametrů. Transformátory parametrů transformují hodnotu parametru při generování odkazů a odpovídajících akcí a stránek na adresy URL. Stejně jako omezení lze transformátory parametrů přidat do parametru trasy přidáním :
názvu a transformátoru za název parametru trasy. Například šablona blog/{article:slugify}
trasy určuje slugify
transformátor. Další informace o transformátorech parametrů naleznete v části Transformátory parametrů .
Následující tabulka ukazuje ukázkové šablony tras a jejich chování:
Šablona trasy | Příklad odpovídajícího identifikátoru URI | Identifikátor URI požadavku... |
---|---|---|
hello |
/hello |
Odpovídá pouze jedné cestě /hello . |
{Page=Home} |
/ |
Odpovídá a nastaví Page na Home . |
{Page=Home} |
/Contact |
Odpovídá a nastaví Page na Contact . |
{controller}/{action}/{id?} |
/Products/List |
Mapuje se na Products kontroler a List akci. |
{controller}/{action}/{id?} |
/Products/Details/123 |
Mapuje se Products na kontroler a Details akci s nastavenouid na hodnotu 123. |
{controller=Home}/{action=Index}/{id?} |
/ |
Mapuje se na kontroler a Index metoduHome . Vlastnost id je ignorována. |
{controller=Home}/{action=Index}/{id?} |
/Products |
Mapuje se na kontroler a Index metoduProducts . Vlastnost id je ignorována. |
Použití šablony je obecně nejjednodušším přístupem ke směrování. Omezení a výchozí hodnoty lze zadat také mimo šablonu trasy.
Komplexní segmenty
Komplexní segmenty se zpracovávají pomocí odpovídajících oddělovačů literálů zprava doleva způsobem, který není greedy . Jedná se například [Route("/a{b}c{d}")]
o složitý segment.
Složité segmenty fungují určitým způsobem, který je potřeba pochopit, aby je bylo možné úspěšně použít. Příklad v této části ukazuje, proč složité segmenty skutečně fungují dobře, když se text oddělovače nezobrazí uvnitř hodnot parametrů. Použití regulárního výrazu a ruční extrahování hodnot je potřeba pro složitější případy.
Upozorňující
Při zpracování System.Text.RegularExpressions nedůvěryhodného vstupu předejte vypršení časového limitu. Uživatel se zlými úmysly může poskytnout vstup, který RegularExpressions
způsobí útok na dostupnost služby. ASP.NET rozhraní API architektury Core, která používají RegularExpressions
vypršení časového limitu.
Toto je souhrn kroků, které směrování provádí pomocí šablony /a{b}c{d}
a cesty /abcd
URL . Slouží |
k vizualizaci fungování algoritmu:
- První literál, zprava doleva, je
c
. Hledá se tedy/abcd
zprava a najde/ab|c|d
. - Vše napravo (
d
) se teď shoduje s parametrem{d}
trasy . - Další literál, zprava doleva, je
a
. Takže/ab|c|d
je prohledáno od místa, kde jsme skončili, paka
je nalezen/|a|b|c|d
. - Hodnota vpravo (
b
) se teď shoduje s parametrem{b}
trasy . - Neexistuje žádný zbývající text a žádná zbývající šablona trasy, takže se jedná o shodu.
Tady je příklad záporného případu, který používá stejnou šablonu /a{b}c{d}
a cestu /aabcd
URL . Slouží |
k vizualizaci fungování algoritmu. Tento případ není shoda, která je vysvětlená stejným algoritmem:
- První literál, zprava doleva, je
c
. Hledá se tedy/aabcd
zprava a najde/aab|c|d
. - Vše napravo (
d
) se teď shoduje s parametrem{d}
trasy . - Další literál, zprava doleva, je
a
. Takže/aab|c|d
je prohledáno od místa, kde jsme skončili, paka
je nalezen/a|a|b|c|d
. - Hodnota vpravo (
b
) se teď shoduje s parametrem{b}
trasy . - V tomto okamžiku existuje zbývající text
a
, ale algoritmus vyčeráhl šablonu trasy, aby parsovala, takže se nejedná o shodu.
Vzhledem k tomu, že odpovídající algoritmus není greedy:
- Odpovídá nejmenšímu množství textu, který je možné v každém kroku.
- Případ, kdy se hodnota oddělovače zobrazí uvnitř hodnot parametrů, způsobí, že se neshoduje.
Regulární výrazy poskytují mnohem větší kontrolu nad jejich odpovídajícím chováním.
Porovnávání greedy, označované také jako maximální počet pokusů o nalezení nejdelší možné shody ve vstupním textu, který splňuje vzor regulárního výrazu. Ne greedy párování, označované také jako opožděné párování, hledá nejkratší možnou shodu ve vstupním textu, který splňuje vzor regulárního výrazu.
Směrování se speciálními znaky
Směrování se speciálními znaky může vést k neočekávaným výsledkům. Představte si například kontroler s následující metodou akce:
[HttpGet("{id?}/name")]
public async Task<ActionResult<string>> GetName(string id)
{
var todoItem = await _context.TodoItems.FindAsync(id);
if (todoItem == null || todoItem.Name == null)
{
return NotFound();
}
return todoItem.Name;
}
Pokud string id
obsahuje následující kódované hodnoty, mohou dojít k neočekávaným výsledkům:
ASCII | Encoded |
---|---|
/ |
%2F |
|
+ |
Parametry trasy nejsou vždy dekódovány adresou URL. Tento problém může být vyřešen v budoucnu. Další informace najdete v tomto problému na GitHubu.
Omezení trasy
Omezení směrování se provádějí, když došlo ke shodě s příchozí adresou URL a cesta url se tokenizuje do hodnot tras. Omezení tras obecně kontrolují hodnotu trasy přidruženou prostřednictvím šablony trasy a ověřte, jestli je hodnota přijatelná, nebo nepravdivá. Některá omezení trasy používají data mimo hodnotu trasy a zvažují, jestli je možné požadavek směrovat. Například HttpMethodRouteConstraint může přijmout nebo odmítnout požadavek na základě jeho příkazu HTTP. Omezení se používají v požadavcích směrování a generování propojení.
Upozorňující
Nepoužívejte omezení pro ověřování vstupu. Pokud se pro ověření vstupu používají omezení, výsledkem neplatného 404
vstupu je odpověď Nenalezena. Neplatný vstup by měl vytvořit chybný 400
požadavek s příslušnou chybovou zprávou. Omezení tras se používají k nejednoznačnosti podobných tras, nikoli k ověření vstupů pro konkrétní trasu.
Následující tabulka ukazuje ukázková omezení směrování a jejich očekávané chování:
omezení | Příklad | Příklady shod | Notes |
---|---|---|---|
int |
{id:int} |
123456789 , -123456789 |
Odpovídá libovolnému celočíselnému číslu. |
bool |
{active:bool} |
true , FALSE |
Shody true nebo false . Nerozlišují se malá a velká písmena |
datetime |
{dob:datetime} |
2016-12-31 , 2016-12-31 7:32pm |
Odpovídá platné DateTime hodnotě v invariantní jazykové verzi. Viz předchozí upozornění. |
decimal |
{price:decimal} |
49.99 , -1,000.01 |
Odpovídá platné decimal hodnotě v invariantní jazykové verzi. Viz předchozí upozornění. |
double |
{weight:double} |
1.234 , -1,001.01e8 |
Odpovídá platné double hodnotě v invariantní jazykové verzi. Viz předchozí upozornění. |
float |
{weight:float} |
1.234 , -1,001.01e8 |
Odpovídá platné float hodnotě v invariantní jazykové verzi. Viz předchozí upozornění. |
guid |
{id:guid} |
CD2C1638-1638-72D5-1638-DEADBEEF1638 |
Odpovídá platné Guid hodnotě. |
long |
{ticks:long} |
123456789 , -123456789 |
Odpovídá platné long hodnotě. |
minlength(value) |
{username:minlength(4)} |
Rick |
Řetězec musí mít alespoň 4 znaky. |
maxlength(value) |
{filename:maxlength(8)} |
MyFile |
Řetězec nesmí být delší než 8 znaků. |
length(length) |
{filename:length(12)} |
somefile.txt |
Řetězec musí mít přesně 12 znaků. |
length(min,max) |
{filename:length(8,16)} |
somefile.txt |
Řetězec musí mít maximálně 8 znaků a nesmí být delší než 16 znaků. |
min(value) |
{age:min(18)} |
19 |
Celočíselná hodnota musí být alespoň 18. |
max(value) |
{age:max(120)} |
91 |
Celočíselná hodnota nesmí být větší než 120. |
range(min,max) |
{age:range(18,120)} |
91 |
Celočíselná hodnota musí být alespoň 18, ale nesmí být větší než 120. |
alpha |
{name:alpha} |
Rick |
Řetězec musí obsahovat jeden nebo více abecedních znaků a -z a nerozlišuje velká a malá písmena. |
regex(expression) |
{ssn:regex(^\\d{{3}}-\\d{{2}}-\\d{{4}}$)} |
123-45-6789 |
Řetězec musí odpovídat regulárnímu výrazu. Podívejte se na tipy k definování regulárního výrazu. |
required |
{name:required} |
Rick |
Používá se k vynucení toho, aby během generování adresy URL byla přítomna hodnota, která není parametrem. |
Upozorňující
Při zpracování System.Text.RegularExpressions nedůvěryhodného vstupu předejte vypršení časového limitu. Uživatel se zlými úmysly může poskytnout vstup, který RegularExpressions
způsobí útok na dostupnost služby. ASP.NET rozhraní API architektury Core, která používají RegularExpressions
vypršení časového limitu.
Pro jeden parametr lze použít více omezení oddělených dvojtečkami. Například následující omezení omezuje parametr na celočíselnou hodnotu 1 nebo vyšší:
[Route("users/{id:int:min(1)}")]
public User GetUserById(int id) { }
Upozorňující
Omezení směrování, která ověřují adresu URL a jsou převedeny na typ CLR, vždy používají neutrální jazykovou verzi. Například převod na typ int
CLR nebo DateTime
. Tato omezení předpokládají, že adresa URL není lokalizovatelná. Omezení tras poskytovaná architekturou nemění hodnoty uložené v hodnotách tras. Všechny hodnoty směrování parsované z adresy URL se ukládají jako řetězce. Omezení se například pokusí převést hodnotu trasy na hodnotu float, ale převedená hodnota se použije pouze k ověření, float
že se dá převést na plovoucí hodnotu.
Regulární výrazy v omezeních
Upozorňující
Při zpracování System.Text.RegularExpressions nedůvěryhodného vstupu předejte vypršení časového limitu. Uživatel se zlými úmysly může poskytnout vstup, který RegularExpressions
způsobí útok na dostupnost služby. ASP.NET rozhraní API architektury Core, která používají RegularExpressions
vypršení časového limitu.
Regulární výrazy lze zadat jako vložená omezení pomocí regex(...)
omezení trasy. Metody v rodině MapControllerRoute také přijímají literál objektu omezení. Pokud se tento formulář použije, řetězcové hodnoty se interpretují jako regulární výrazy.
Následující kód používá omezení vložených regulárních výrazů:
app.MapGet("{message:regex(^\\d{{3}}-\\d{{2}}-\\d{{4}}$)}",
() => "Inline Regex Constraint Matched");
Následující kód používá literál objektu k určení omezení regulárního výrazu:
app.MapControllerRoute(
name: "people",
pattern: "people/{ssn}",
constraints: new { ssn = "^\\d{3}-\\d{2}-\\d{4}$", },
defaults: new { controller = "People", action = "List" });
Architektura ASP.NET Core přidává RegexOptions.IgnoreCase | RegexOptions.Compiled | RegexOptions.CultureInvariant
do konstruktoru regulárních výrazů. Podívejte RegexOptions se na popis těchto členů.
Regulární výrazy používají oddělovače a tokeny podobné těm používaným směrováním a jazykem C#. Tokeny regulárních výrazů musí být uchycené. Chcete-li použít regulární výraz ^\d{3}-\d{2}-\d{4}$
v vložené omezení, použijte jednu z následujících možností:
- Nahraďte
\
znaky zadané v řetězci jako\\
znaky ve zdrojovém souboru jazyka C#, aby bylo možné řídicí znak řetězce utéct\
. - Doslovné řetězcové literály.
Chcete-li uvozovat znaky {
oddělovače parametrů směrování , [
}
]
zdvojnásobit znaky ve výrazu, {{
například , }}
, , . ]]
[[
Následující tabulka ukazuje regulární výraz a jeho řídicí verzi:
Regulární výraz | Řídicí regulární výraz |
---|---|
^\d{3}-\d{2}-\d{4}$ |
^\\d{{3}}-\\d{{2}}-\\d{{4}}$ |
^[a-z]{2}$ |
^[[a-z]]{{2}}$ |
Regulární výrazy používané při směrování často začínají znakem ^
a odpovídají počáteční pozici řetězce. Výrazy často končí znakem $
a odpovídají konci řetězce. Znaky ^
a $
zajistěte, aby regulární výraz odpovídal celé hodnotě parametru trasy. ^
Bez znaků a $
znaků regulární výraz odpovídá jakémukoli podřetězci v řetězci, což je často nežádoucí. Následující tabulka obsahuje příklady a vysvětluje, proč se shodují nebo se neshodují:
Výraz | String | Párování | Komentář |
---|---|---|---|
[a-z]{2} |
dobrý den | Ano | Shoda podřetěžce |
[a-z]{2} |
123abc456 | Ano | Shoda podřetěžce |
[a-z]{2} |
mz | Ano | Odpovídá výrazu |
[a-z]{2} |
MZ | Ano | Nerozlišuje se malá a velká písmena. |
^[a-z]{2}$ |
dobrý den | No | Viz ^ a $ výše |
^[a-z]{2}$ |
123abc456 | No | Viz ^ a $ výše |
Další informace o syntaxi regulárních výrazů naleznete v tématu Regulární výrazy rozhraní .NET Framework.
Chcete-li omezit parametr na známou sadu možných hodnot, použijte regulární výraz. Například {action:regex(^(list|get|create)$)}
odpovídá pouze hodnotě action
trasy do list
, get
nebo create
. Pokud je řetězec předán do slovníku omezení, je řetězec ^(list|get|create)$
ekvivalentní. Omezení, která se předávají ve slovníku omezení, která neodpovídají některému ze známých omezení, se také považují za regulární výrazy. Omezení předaná v šabloně, která neodpovídají některému ze známých omezení, se považují za regulární výrazy.
Vlastní omezení trasy
Vlastní omezení trasy je možné vytvořit implementací IRouteConstraint rozhraní. Rozhraní IRouteConstraint
obsahuje Match, který vrátí true
, pokud je omezení splněno a false
jinak.
Vlastní omezení trasy jsou zřídka nutná. Před implementací vlastního omezení trasy zvažte alternativy, jako je například vazba modelu.
Složka ASP.NET Core Constraints poskytuje dobré příklady vytváření omezení. Například GuidRouteConstraint.
Pokud chcete použít vlastní IRouteConstraint
typ omezení trasy, musí být zaregistrovaný v kontejneru služby v aplikaci ConstraintMap . A ConstraintMap
je slovník, který mapuje klíče omezení směrování na IRouteConstraint
implementace, které tato omezení ověřují. Aplikaci ConstraintMap
je možné aktualizovat buď Program.cs
v rámci AddRouting hovoru, nebo konfigurací RouteOptions přímo pomocí builder.Services.Configure<RouteOptions>
. Příklad:
builder.Services.AddRouting(options =>
options.ConstraintMap.Add("noZeroes", typeof(NoZeroesRouteConstraint)));
Předchozí omezení se použije v následujícím kódu:
[ApiController]
[Route("api/[controller]")]
public class NoZeroesController : ControllerBase
{
[HttpGet("{id:noZeroes}")]
public IActionResult Get(string id) =>
Content(id);
}
Implementace NoZeroesRouteConstraint
brání 0
použití v parametru trasy:
public class NoZeroesRouteConstraint : IRouteConstraint
{
private static readonly Regex _regex = new(
@"^[1-9]*$",
RegexOptions.CultureInvariant | RegexOptions.IgnoreCase,
TimeSpan.FromMilliseconds(100));
public bool Match(
HttpContext? httpContext, IRouter? route, string routeKey,
RouteValueDictionary values, RouteDirection routeDirection)
{
if (!values.TryGetValue(routeKey, out var routeValue))
{
return false;
}
var routeValueString = Convert.ToString(routeValue, CultureInfo.InvariantCulture);
if (routeValueString is null)
{
return false;
}
return _regex.IsMatch(routeValueString);
}
}
Upozorňující
Při zpracování System.Text.RegularExpressions nedůvěryhodného vstupu předejte vypršení časového limitu. Uživatel se zlými úmysly může poskytnout vstup, který RegularExpressions
způsobí útok na dostupnost služby. ASP.NET rozhraní API architektury Core, která používají RegularExpressions
vypršení časového limitu.
Předchozí kód:
- Zabraňuje
0
v{id}
segmentu trasy. - Ukazuje se, že poskytuje základní příklad implementace vlastního omezení. Neměla by se používat v produkční aplikaci.
Následující kód je lepším přístupem k tomu, aby se zabránilo zpracování obsahujícího id
0
:
[HttpGet("{id}")]
public IActionResult Get(string id)
{
if (id.Contains('0'))
{
return StatusCode(StatusCodes.Status406NotAcceptable);
}
return Content(id);
}
Předchozí kód má oproti přístupu následující výhody NoZeroesRouteConstraint
:
- Nevyžaduje vlastní omezení.
- Vrátí popisnější chybu, pokud parametr trasy obsahuje
0
.
Transformátory parametrů
Transformátory parametrů:
- Spustí se při generování odkazu pomocí LinkGenerator.
- Implementovat Microsoft.AspNetCore.Routing.IOutboundParameterTransformer.
- Jsou nakonfigurovány pomocí ConstraintMap.
- Převezměte hodnotu trasy parametru a transformujte ji na novou řetězcovou hodnotu.
- Výsledkem je použití transformované hodnoty ve vygenerovaném odkazu.
Například vlastní slugify
transformátor parametru ve vzoru blog\{article:slugify}
trasy s Url.Action(new { article = "MyTestArticle" })
vygenerovanými blog\my-test-article
.
Zvažte následující IOutboundParameterTransformer
implementaci:
public class SlugifyParameterTransformer : IOutboundParameterTransformer
{
public string? TransformOutbound(object? value)
{
if (value is null)
{
return null;
}
return Regex.Replace(
value.ToString()!,
"([a-z])([A-Z])",
"$1-$2",
RegexOptions.CultureInvariant,
TimeSpan.FromMilliseconds(100))
.ToLowerInvariant();
}
}
Chcete-li použít transformátor parametrů ve vzoru trasy, nakonfigurujte ho pomocí :ConstraintMap Program.cs
builder.Services.AddRouting(options =>
options.ConstraintMap["slugify"] = typeof(SlugifyParameterTransformer));
Architektura ASP.NET Core používá transformátory parametrů k transformaci identifikátoru URI, kde se koncový bod překládá. Například transformátory parametrů transformují směrovací hodnoty použité ke shodě area
, controller
, action
a page
:
app.MapControllerRoute(
name: "default",
pattern: "{controller:slugify=Home}/{action:slugify=Index}/{id?}");
U předchozí šablony trasy se akce SubscriptionManagementController.GetAll
shoduje s identifikátorem URI /subscription-management/get-all
. Transformátor parametrů nemění směrovací hodnoty použité k vygenerování propojení. Například Url.Action("GetAll", "SubscriptionManagement")
výstupy /subscription-management/get-all
.
ASP.NET Core poskytuje konvence rozhraní API pro použití transformátorů parametrů se generovanými trasami:
- Konvence Microsoft.AspNetCore.Mvc.ApplicationModels.RouteTokenTransformerConvention MVC aplikuje zadaný transformátor parametrů na všechny trasy atributů v aplikaci. Parametr transformer transformuje tokeny směrování atributů při jejich nahrazení. Další informace naleznete v tématu Použití transformátoru parametrů k přizpůsobení nahrazení tokenu.
- Razor Stránky používají PageRouteTransformerConvention konvenci rozhraní API. Tato konvence aplikuje zadaný transformátor parametrů na všechny automaticky zjištěné Razor stránky. Transformátor parametru transformuje segmenty Razor složek a názvů souborů tras Pages. Další informace naleznete v tématu Použití transformátoru parametrů k přizpůsobení tras stránky.
Referenční informace ke generování adres URL
Tato část obsahuje odkaz na algoritmus implementovaný generováním adres URL. V praxi používají nejsložitější příklady generování adres URL kontrolery nebo Razor stránky. Další informace najdete v tématu Směrování v kontrolerů .
Proces generování adresy URL začíná voláním LinkGenerator.GetPathByAddress nebo podobnou metodou. Metoda je poskytována s adresou, sadou hodnot tras a volitelně informace o aktuálním požadavku z HttpContext
.
Prvním krokem je použití adresy k vyřešení sady kandidátských koncových bodů pomocí typu IEndpointAddressScheme<TAddress> adresy.
Jakmile sada kandidátů najde schéma adres, koncové body se objednávají a zpracovávají iterativním způsobem, dokud operace generování adresy URL nebude úspěšná. Generování adresy URL nekontroluje nejednoznačnosti, první vrácený výsledek je konečný výsledek.
Řešení potíží s generováním adres URL pomocí protokolování
Prvním krokem při generování adresy URL při řešení potíží je nastavení úrovně Microsoft.AspNetCore.Routing
protokolování na TRACE
. LinkGenerator
zaznamenává mnoho podrobností o jeho zpracování, které může být užitečné při řešení problémů.
Podrobnosti o generování adres URL najdete v referenčních informacích ke generování adres URL.
Adresy
Adresy jsou konceptem generování adres URL, které slouží k vytvoření vazby volání do generátoru odkazů na sadu kandidátských koncových bodů.
Adresy jsou rozšiřitelný koncept, který ve výchozím nastavení obsahuje dvě implementace:
- Jako adresu použijte název koncového bodu (
string
):- Poskytuje podobné funkce jako název trasy MVC.
- IEndpointNameMetadata Používá typ metadat.
- Vyřeší zadaný řetězec s metadaty všech registrovaných koncových bodů.
- Vyvolá výjimku při spuštění, pokud více koncových bodů používá stejný název.
- Doporučuje se pro obecné použití mimo kontrolery a Razor stránky.
- Použití hodnot směrování (RouteValuesAddress) jako adresy:
- Poskytuje podobné funkce jako kontrolery a Razor starší generace adres URL stránky.
- Velmi složité rozšířit a ladit.
- Poskytuje implementaci, kterou
IUrlHelper
používají pomocné rutiny značek, pomocné rutiny HTML, výsledky akcí atd.
Role schématu adres spočívá v přidružení mezi adresou a odpovídajícími koncovými body podle libovolných kritérií:
- Schéma názvu koncového bodu provádí základní vyhledávání slovníku.
- Schéma hodnot tras má komplexní nejlepší podmnožinu algoritmu sady.
Okolní hodnoty a explicitní hodnoty
Z aktuálního požadavku směrování přistupuje ke směrovacím hodnotám aktuálního požadavku HttpContext.Request.RouteValues
. Hodnoty přidružené k aktuálnímu požadavku se označují jako okolní hodnoty. Pro účely srozumitelnosti se dokumentace týká směrovacích hodnot předávaných metodám jako explicitních hodnot.
Následující příklad ukazuje okolní hodnoty a explicitní hodnoty. Poskytuje okolní hodnoty z aktuálního požadavku a explicitních hodnot:
public class WidgetController : ControllerBase
{
private readonly LinkGenerator _linkGenerator;
public WidgetController(LinkGenerator linkGenerator) =>
_linkGenerator = linkGenerator;
public IActionResult Index()
{
var indexPath = _linkGenerator.GetPathByAction(
HttpContext, values: new { id = 17 })!;
return Content(indexPath);
}
// ...
Předchozí kód:
- Návraty
/Widget/Index/17
- Získá LinkGenerator přes DI.
Následující kód poskytuje pouze explicitní hodnoty a žádné okolní hodnoty:
var subscribePath = _linkGenerator.GetPathByAction(
"Subscribe", "Home", new { id = 17 })!;
Předchozí metoda vrátí /Home/Subscribe/17
Následující kód ve návratu WidgetController
/Widget/Subscribe/17
:
var subscribePath = _linkGenerator.GetPathByAction(
HttpContext, "Subscribe", null, new { id = 17 });
Následující kód poskytuje kontroler z okolních hodnot v aktuálním požadavku a explicitní hodnoty:
public class GadgetController : ControllerBase
{
public IActionResult Index() =>
Content(Url.Action("Edit", new { id = 17 })!);
}
V předchozím kódu:
/Gadget/Edit/17
je vrácena.- UrlIUrlHelperzíská .
- Action vygeneruje adresu URL s absolutní cestou pro metodu akce. Adresa URL obsahuje zadaný
action
název aroute
hodnoty.
Následující kód poskytuje okolní hodnoty z aktuálního požadavku a explicitní hodnoty:
public class IndexModel : PageModel
{
public void OnGet()
{
var editUrl = Url.Page("./Edit", new { id = 17 });
// ...
}
}
Předchozí kód se nastaví url
, když /Edit/17
Edit Razor Page obsahuje následující direktivu stránky:
@page "{id:int}"
Pokud stránka Upravit neobsahuje "{id:int}"
šablonu trasy, url
je /Edit?id=17
.
Chování MVC IUrlHelper přidává kromě zde popsaných pravidel vrstvu složitosti:
IUrlHelper
vždy poskytuje směrovací hodnoty z aktuálního požadavku jako okolní hodnoty.- IUrlHelper.Action vždy zkopíruje aktuální
action
hodnoty acontroller
směrovací hodnoty jako explicitní hodnoty, pokud je nepřepíše vývojář. - IUrlHelper.Page vždy zkopíruje aktuální
page
hodnotu trasy jako explicitní hodnotu, pokud ji nepřepíšete. IUrlHelper.Page
vždy přepíše aktuálníhandler
hodnotunull
trasy jako explicitní hodnoty, pokud ji nepřepíšete.
Uživatelé jsou často překvapeni chováním okolních hodnot, protože MVC zdánlivě nedodržuje vlastní pravidla. Z historických důvodů a z důvodu kompatibility mají určité hodnoty tras, jako action
je , controller
, page
a handler
mají vlastní zvláštní chování.
Ekvivalentní funkce poskytované LinkGenerator.GetPathByAction
a LinkGenerator.GetPathByPage
duplikuje tyto anomálie z důvodu kompatibility IUrlHelper
.
Proces generování adres URL
Jakmile se najde sada kandidátských koncových bodů, algoritmus generování adres URL:
- Zpracovává koncové body iterativním způsobem.
- Vrátí první úspěšný výsledek.
Prvním krokem v tomto procesu je zneplatnění hodnoty trasy. Zneplatnění hodnoty trasy je proces, kterým směrování rozhodne, které hodnoty trasy z okolních hodnot se mají použít a které by se měly ignorovat. Každá okolní hodnota se považuje a buď v kombinaci s explicitními hodnotami, nebo je ignorována.
Nejlepším způsobem, jak přemýšlet o roli okolních hodnot, je, že se snaží uložit vývojáři aplikací psaní, v některých běžných případech. Scénáře, ve kterých jsou okolní hodnoty užitečné, se tradičně vztahují k MVC:
- Při propojení s jinou akcí ve stejném řadiči není nutné zadat název kontroleru.
- Při propojení s jiným řadičem ve stejné oblasti není nutné zadat název oblasti.
- Při propojení se stejnou metodou akce není nutné zadávat hodnoty tras.
- Při propojení s jinou částí aplikace nechcete přenášet hodnoty tras, které nemají v této části aplikace žádný význam.
Volání nebo LinkGenerator
IUrlHelper
vrácení jsou obvykle způsobená tím, že null
nerozumí neplatné hodnotě trasy. Při řešení potíží s neplatnou hodnotou trasy můžete explicitně zadat více hodnot tras, abyste zjistili, jestli se tím problém vyřeší.
Neplatná hodnota trasy funguje na předpokladu, že schéma adresy URL aplikace je hierarchické s hierarchií vytvořenou zleva doprava. Představte si šablonu {controller}/{action}/{id?}
směrování základního kontroleru, abyste získali intuitivní představu o tom, jak to funguje v praxi. Změna hodnoty zneplatní všechny směrovací hodnoty, které se zobrazují vpravo. To odráží předpoklad o hierarchii. Pokud má aplikace okolní hodnotu a id
operace určuje jinou hodnotu pro controller
:
id
nebude znovu použito, protože{controller}
je nalevo od{id?}
.
Několik příkladů demonstrujících tento princip:
- Pokud explicitní hodnoty obsahují hodnotu pro
id
, okolní hodnota jeid
ignorována. Okolní hodnoty acontroller
action
lze je použít. - Pokud explicitní hodnoty obsahují hodnotu pro
action
, je ignorována jakákoli okolní hodnota proaction
. Lze použít okolní hodnotycontroller
. Pokud se explicitní hodnota pro jinou než okolní hodnotaaction
action
pro ,id
hodnota se nepoužije. Pokud je explicitní hodnotaaction
stejná jako okolní hodnota proaction
,id
lze použít hodnotu. - Pokud explicitní hodnoty obsahují hodnotu pro
controller
, je ignorována jakákoli okolní hodnota procontroller
. Pokud se explicitní hodnota pro jinou než okolní hodnotacontroller
controller
pro ,action
hodnoty aid
hodnoty nebudou použity. Pokud je explicitní hodnotacontroller
stejná jako okolní hodnota procontroller
,action
lze použít hodnoty aid
hodnoty.
Tento proces je ještě složitější díky existenci tras atributů a vyhrazených konvenčních tras. Běžné trasy kontroleru, jako {controller}/{action}/{id?}
je například určení hierarchie pomocí parametrů trasy. Pro vyhrazené konvenční trasy a trasy atributů pro kontrolery a Razor stránky:
- Existuje hierarchie hodnot tras.
- Nezobrazují se v šabloně.
V těchto případech generování adresy URL definuje koncept požadovaných hodnot . Koncové body vytvořené kontrolery a Razor stránkami mají zadané požadované hodnoty, které umožňují zneplatnění hodnoty trasy.
Podrobný algoritmus zneplatnění hodnoty trasy:
- Požadované názvy hodnot se kombinují s parametry trasy a pak se zpracovávají zleva doprava.
- Pro každý parametr se porovná okolní hodnota a explicitní hodnota:
- Pokud je okolní hodnota a explicitní hodnota stejné, proces pokračuje.
- Pokud je okolní hodnota přítomná a explicitní hodnota není, použije se při generování adresy URL okolní hodnota.
- Pokud okolní hodnota není přítomná a explicitní hodnota je, zamítněte okolní hodnotu a všechny následné okolní hodnoty.
- Pokud se nachází okolí a explicitní hodnota a obě hodnoty jsou odlišné, zamítněte okolní hodnotu a všechny následné okolní hodnoty.
V tuto chvíli je operace generování adres URL připravená k vyhodnocení omezení trasy. Sada přijatých hodnot se zkombinuje s výchozími hodnotami parametrů, které jsou k dispozici pro omezení. Pokud všechna omezení projdou, operace bude pokračovat.
Dále je možné použít akceptované hodnoty k rozšíření šablony trasy. Šablona trasy se zpracuje:
- Zleva doprava.
- Každý parametr má jeho přijatou hodnotu nahrazenou.
- S následujícími zvláštními případy:
- Pokud přijaté hodnoty chybí hodnota a parametr má výchozí hodnotu, použije se výchozí hodnota.
- Pokud přijaté hodnoty chybí a parametr je nepovinný, zpracování pokračuje.
- Pokud některý parametr trasy napravo od chybějícího volitelného parametru má hodnotu, operace selže.
- Pokud je to možné, sbalí se souvislé parametry s výchozími hodnotami a volitelné parametry.
Hodnoty explicitně za předpokladu, že neodpovídají segmentu trasy, se přidají do řetězce dotazu. Následující tabulka ukazuje výsledek při použití šablony {controller}/{action}/{id?}
trasy .
Okolní hodnoty | Explicitní hodnoty | Výsledek |
---|---|---|
controller = "Home" | action = "O aplikaci" | /Home/About |
controller = "Home" | controller = "Order", action = "About" | /Order/About |
controller = "Home", color = "Red" | action = "O aplikaci" | /Home/About |
controller = "Home" | action = "O produktu", barva = "Červená" | /Home/About?color=Red |
Volitelné pořadí parametrů trasy
Volitelné parametry trasy musí pocházet po všech požadovaných parametrech trasy a literálech. V následujícím kódu id
name
musí parametry pocházet za parametrem color
:
using Microsoft.AspNetCore.Mvc;
namespace WebApplication1.Controllers;
[Route("api/[controller]")]
public class MyController : ControllerBase
{
// GET /api/my/red/2/joe
// GET /api/my/red/2
// GET /api/my
[HttpGet("{color}/{id:int?}/{name?}")]
public IActionResult GetByIdAndOptionalName(string color, int id = 1, string? name = null)
{
return Ok($"{color} {id} {name ?? ""}");
}
}
Problémy s neplatnou hodnotou trasy
Následující kód ukazuje příklad schématu generování adres URL, které není podporováno směrováním:
app.MapControllerRoute(
"default",
"{culture}/{controller=Home}/{action=Index}/{id?}");
app.MapControllerRoute(
"blog",
"{culture}/{**slug}",
new { controller = "Blog", action = "ReadPost" });
V předchozím kódu culture
se parametr trasy používá pro lokalizaci. Touha má parametr culture
vždy přijmout jako okolní hodnotu. Parametr culture
však není přijat jako okolní hodnota kvůli způsobu, jakým požadované hodnoty fungují:
"default"
V šabloněculture
trasy je parametr trasy vlevo odcontroller
, takže změnycontroller
nebudouculture
neplatné ."blog"
V šabloněculture
trasy se parametr trasy považuje za napravo odcontroller
parametru trasy, který se zobrazí v požadovaných hodnotách.
Parsování cest URL pomocí LinkParser
Třída LinkParser přidává podporu analýzy cesty URL do sady hodnot tras. Metoda ParsePathByEndpointName přebírá název koncového bodu a cestu URL a vrátí sadu hodnot tras extrahovaných z cesty URL.
V následujícím příkladu kontroler akce GetProduct
používá šablonu api/Products/{id}
trasy a má Name :GetProduct
[ApiController]
[Route("api/[controller]")]
public class ProductsController : ControllerBase
{
[HttpGet("{id}", Name = nameof(GetProduct))]
public IActionResult GetProduct(string id)
{
// ...
Ve stejné třídě AddRelatedProduct
kontroleru akce očekává cestu URL, pathToRelatedProduct
kterou lze poskytnout jako parametr řetězce dotazu:
[HttpPost("{id}/Related")]
public IActionResult AddRelatedProduct(
string id, string pathToRelatedProduct, [FromServices] LinkParser linkParser)
{
var routeValues = linkParser.ParsePathByEndpointName(
nameof(GetProduct), pathToRelatedProduct);
var relatedProductId = routeValues?["id"];
// ...
V předchozím příkladu AddRelatedProduct
akce extrahuje id
hodnotu trasy z cesty URL. Například s cestou /api/Products/1
URL , relatedProductId
hodnota je nastavena na 1
. Tento přístup umožňuje klientům rozhraní API používat cesty url při odkazování na prostředky, aniž by museli vědět, jak je taková adresa URL strukturovaná.
Konfigurace metadat koncového bodu
Následující odkazy obsahují informace o konfiguraci metadat koncového bodu:
- Povolení Cors se směrováním koncových bodů
- Ukázka IAuthorizationPolicyProvider pomocí vlastního
[MinimumAgeAuthorize]
atributu - Testování ověřování pomocí atributu [Authorize]
- RequireAuthorization
- Výběr schématu s atributem [Authorize]
- Použití zásad pomocí atributu [Authorize]
- Autorizace na základě rolí v ASP.NET Core
Porovnávání hostitelů v trasách pomocí RequireHost
RequireHost použije omezení na trasu, která vyžaduje zadaného hostitele. Parametrem RequireHost
[Host] může být:
- Hostitel:
www.domain.com
, odpovídáwww.domain.com
libovolnému portu. - Hostitel se zástupným znakem:
*.domain.com
, shodywww.domain.com
,subdomain.domain.com
nebowww.subdomain.domain.com
na libovolném portu. - Port:
*:5000
Odpovídá portu 5000 s libovolným hostitelem. - Hostitel a port:
www.domain.com:5000
nebo*.domain.com:5000
odpovídá hostiteli a portu.
Lze zadat více parametrů pomocí RequireHost
nebo [Host]
. Omezení odpovídá hostitelům platným pro některý z parametrů. Například [Host("domain.com", "*.domain.com")]
shody domain.com
, www.domain.com
a subdomain.domain.com
.
Následující kód používá RequireHost
k vyžadování zadaného hostitele na trase:
app.MapGet("/", () => "Contoso").RequireHost("contoso.com");
app.MapGet("/", () => "AdventureWorks").RequireHost("adventure-works.com");
app.MapHealthChecks("/healthz").RequireHost("*:8080");
Následující kód používá [Host]
atribut na kontroleru k vyžadování některého ze zadaných hostitelů:
[Host("contoso.com", "adventure-works.com")]
public class HostsController : Controller
{
public IActionResult Index() =>
View();
[Host("example.com")]
public IActionResult Example() =>
View();
}
[Host]
Když se atribut použije na metodu kontroleru i akce:
- Použije se atribut akce.
- Atribut kontroleru je ignorován.
Upozorňující
Rozhraní API, které závisí na hlavičce hostitele, například HttpRequest.Host a RequireHost, podléhají potenciálnímu falšování identity klienty.
Pokud chcete zabránit falšování identity hostitele a portu, použijte jeden z následujících přístupů:
- Použijte HttpContext.Connection (ConnectionInfo.LocalPort) místo, kde jsou porty kontrolovány.
- Používejte filtrování hostitelů.
Skupiny tras
Metoda MapGroup rozšíření pomáhá uspořádat skupiny koncových bodů s běžnou předponou. Snižuje opakující se kód a umožňuje přizpůsobit celé skupiny koncových bodů jediným voláním metod, jako RequireAuthorization jsou a WithMetadata které přidávají metadata koncového bodu.
Například následující kód vytvoří dvě podobné skupiny koncových bodů:
app.MapGroup("/public/todos")
.MapTodosApi()
.WithTags("Public");
app.MapGroup("/private/todos")
.MapTodosApi()
.WithTags("Private")
.AddEndpointFilterFactory(QueryPrivateTodos)
.RequireAuthorization();
EndpointFilterDelegate QueryPrivateTodos(EndpointFilterFactoryContext factoryContext, EndpointFilterDelegate next)
{
var dbContextIndex = -1;
foreach (var argument in factoryContext.MethodInfo.GetParameters())
{
if (argument.ParameterType == typeof(TodoDb))
{
dbContextIndex = argument.Position;
break;
}
}
// Skip filter if the method doesn't have a TodoDb parameter.
if (dbContextIndex < 0)
{
return next;
}
return async invocationContext =>
{
var dbContext = invocationContext.GetArgument<TodoDb>(dbContextIndex);
dbContext.IsPrivate = true;
try
{
return await next(invocationContext);
}
finally
{
// This should only be relevant if you're pooling or otherwise reusing the DbContext instance.
dbContext.IsPrivate = false;
}
};
}
public static RouteGroupBuilder MapTodosApi(this RouteGroupBuilder group)
{
group.MapGet("/", GetAllTodos);
group.MapGet("/{id}", GetTodo);
group.MapPost("/", CreateTodo);
group.MapPut("/{id}", UpdateTodo);
group.MapDelete("/{id}", DeleteTodo);
return group;
}
V tomto scénáři můžete použít relativní adresu hlavičky Location
ve výsledku 201 Created
:
public static async Task<Created<Todo>> CreateTodo(Todo todo, TodoDb database)
{
await database.AddAsync(todo);
await database.SaveChangesAsync();
return TypedResults.Created($"{todo.Id}", todo);
}
První skupina koncových bodů se bude shodovat pouze s požadavky s předponou /public/todos
a jsou přístupná bez ověřování. Druhá skupina koncových bodů bude odpovídat pouze požadavkům s předponou /private/todos
a vyžaduje ověření.
Objekt QueryPrivateTodos
pro filtrování koncových bodů je místní funkce, která upravuje parametry obslužné rutiny TodoDb
trasy tak, aby umožňovala přístup k privátním datům úkolů a jejich ukládání.
Skupiny tras také podporují vnořené skupiny a složité vzory předpon s parametry trasy a omezeními. V následujícím příkladu a obslužná rutina trasy namapovaná na user
skupinu může zachytit {org}
parametry a {group}
parametry trasy definované v předponách vnější skupiny.
Předpona může být také prázdná. To může být užitečné pro přidání metadat koncového bodu nebo filtrů do skupiny koncových bodů beze změny vzoru trasy.
var all = app.MapGroup("").WithOpenApi();
var org = all.MapGroup("{org}");
var user = org.MapGroup("{user}");
user.MapGet("", (string org, string user) => $"{org}/{user}");
Přidání filtrů nebo metadat do skupiny se chová stejně jako jejich individuální přidání do každého koncového bodu před přidáním dalších filtrů nebo metadat, které mohly být přidány do vnitřní skupiny nebo konkrétního koncového bodu.
var outer = app.MapGroup("/outer");
var inner = outer.MapGroup("/inner");
inner.AddEndpointFilter((context, next) =>
{
app.Logger.LogInformation("/inner group filter");
return next(context);
});
outer.AddEndpointFilter((context, next) =>
{
app.Logger.LogInformation("/outer group filter");
return next(context);
});
inner.MapGet("/", () => "Hi!").AddEndpointFilter((context, next) =>
{
app.Logger.LogInformation("MapGet filter");
return next(context);
});
V předchozím příkladu vnější filtr zapíše příchozí požadavek před vnitřním filtrem, i když byl přidán druhý. Vzhledem k tomu, že filtry byly použity u různých skupin, pořadí, které byly přidány vzhledem k sobě, nezáleží. Přidají se filtry objednávek bez ohledu na to, jestli se použije na stejnou skupinu nebo konkrétní koncový bod.
Žádost o /outer/inner/
protokolování bude následující:
/outer group filter
/inner group filter
MapGet filter
Doprovodné materiály k výkonu pro směrování
Pokud má aplikace problémy s výkonem, směrování se často považuje za problém. Důvodem je podezření, že architektury, jako jsou kontrolery a Razor stránky, hlásí dobu strávenou uvnitř rozhraní v protokolovacích zprávách. Pokud je mezi časem hlášeným kontrolery a celkovým časem požadavku významný rozdíl:
- Vývojáři eliminují kód aplikace jako zdroj problému.
- Běžně se předpokládá, že příčinou je směrování.
Směrování je testované výkonem pomocí tisíců koncových bodů. Je nepravděpodobné, že by typická aplikace narazila na problém s výkonem jenom tím, že je příliš velká. Nejčastější hlavní příčinou pomalého směrování je obvykle špatně se chovající vlastní middleware.
Následující ukázka kódu ukazuje základní techniku zúžení zdroje zpoždění:
var logger = app.Services.GetRequiredService<ILogger<Program>>();
app.Use(async (context, next) =>
{
var stopwatch = Stopwatch.StartNew();
await next(context);
stopwatch.Stop();
logger.LogInformation("Time 1: {ElapsedMilliseconds}ms", stopwatch.ElapsedMilliseconds);
});
app.UseRouting();
app.Use(async (context, next) =>
{
var stopwatch = Stopwatch.StartNew();
await next(context);
stopwatch.Stop();
logger.LogInformation("Time 2: {ElapsedMilliseconds}ms", stopwatch.ElapsedMilliseconds);
});
app.UseAuthorization();
app.Use(async (context, next) =>
{
var stopwatch = Stopwatch.StartNew();
await next(context);
stopwatch.Stop();
logger.LogInformation("Time 3: {ElapsedMilliseconds}ms", stopwatch.ElapsedMilliseconds);
});
app.MapGet("/", () => "Timing Test.");
Směrování podle času:
- Prokládání každého middlewaru pomocí kopie middlewaru časování zobrazeného v předchozím kódu.
- Přidejte jedinečný identifikátor pro korelaci dat časování s kódem.
Jedná se o základní způsob, jak zúžit zpoždění, pokud je významné, například více než 10ms
. Odečítá Time 2
se od Time 1
sestav čas strávený v middlewaru UseRouting
.
Následující kód používá kompaktnější přístup k předchozímu kódu časování:
public sealed class AutoStopwatch : IDisposable
{
private readonly ILogger _logger;
private readonly string _message;
private readonly Stopwatch _stopwatch;
private bool _disposed;
public AutoStopwatch(ILogger logger, string message) =>
(_logger, _message, _stopwatch) = (logger, message, Stopwatch.StartNew());
public void Dispose()
{
if (_disposed)
{
return;
}
_logger.LogInformation("{Message}: {ElapsedMilliseconds}ms",
_message, _stopwatch.ElapsedMilliseconds);
_disposed = true;
}
}
var logger = app.Services.GetRequiredService<ILogger<Program>>();
var timerCount = 0;
app.Use(async (context, next) =>
{
using (new AutoStopwatch(logger, $"Time {++timerCount}"))
{
await next(context);
}
});
app.UseRouting();
app.Use(async (context, next) =>
{
using (new AutoStopwatch(logger, $"Time {++timerCount}"))
{
await next(context);
}
});
app.UseAuthorization();
app.Use(async (context, next) =>
{
using (new AutoStopwatch(logger, $"Time {++timerCount}"))
{
await next(context);
}
});
app.MapGet("/", () => "Timing Test.");
Potenciálně nákladné funkce směrování
Následující seznam obsahuje přehled o funkcích směrování, které jsou relativně drahé v porovnání se základními šablonami tras:
- Regulární výrazy: Je možné psát regulární výrazy, které jsou složité nebo mají dlouhou dobu trvání s malým množstvím vstupu.
- Komplexní segmenty (
{x}-{y}-{z}
):- Jsou výrazně dražší než analýza běžného segmentu cesty URL.
- Výsledkem je přidělení mnoha dalších podřetěžců.
- Synchronní přístup k datům: Mnoho složitých aplikací má v rámci směrování přístup k databázi. Použijte body rozšiřitelnosti, například MatcherPolicy a EndpointSelectorContext, které jsou asynchronní.
Pokyny pro velké směrovací tabulky
Ve výchozím nastavení ASP.NET Core používá algoritmus směrování, který obchoduje s pamětí za čas procesoru. To má pěkný účinek, že čas porovnávání tras závisí pouze na délce cesty, která se má shodovat, a ne na počtu tras. Tento přístup ale může být v některých případech problematický, když má aplikace velký počet tras (v tisících) a v trasách existuje velké množství předpon proměnných. Například pokud trasy mají parametry v počátečních segmentech trasy, například {parameter}/some/literal
.
Je nepravděpodobné, že by aplikace narazila na situaci, kdy se jedná o problém, pokud:
- V aplikaci existuje velký počet tras, které tento model používají.
- V aplikaci je velký počet tras.
Jak zjistit, jestli aplikace narazí na problém s velkou směrovací tabulkou
- Existují dva příznaky, které je třeba hledat:
- Aplikace se pomalu spustí při prvním požadavku.
- Mějte na paměti, že je to povinné, ale nestačí. Existuje mnoho dalších problémů, které se nesměrují, než může způsobit pomalé spuštění aplikace. Zkontrolujte níže uvedený stav, abyste přesně zjistili, jestli aplikace v této situaci neběží.
- Aplikace během spouštění spotřebovává velké množství paměti a výpis paměti zobrazuje velký počet
Microsoft.AspNetCore.Routing.Matching.DfaNode
instancí.
- Aplikace se pomalu spustí při prvním požadavku.
Jak tento problém vyřešit
Existuje několik technik a optimalizací, které je možné použít u tras, které tento scénář z velké části zlepšují:
- Pokud je to možné, použijte omezení trasy na parametry, například
{parameter:int}
{parameter:guid}
,{parameter:regex(\\d+)}
, atd.- To umožňuje algoritmus směrování interně optimalizovat struktury používané pro porovnávání a výrazně snížit využitou paměť.
- Ve většině případů to stačí, abyste se vrátili k přijatelnému chování.
- Změňte trasy tak, aby se parametry přesunuly do pozdějších segmentů v šabloně.
- Tím se sníží počet možných cest tak, aby odpovídal koncovému bodu dané cestě.
- Použijte dynamickou trasu a dynamicky proveďte mapování na kontroler nebo stránku.
- Toho lze dosáhnout pomocí
MapDynamicControllerRoute
aMapDynamicPageRoute
.
- Toho lze dosáhnout pomocí
Middleware s krátkým okruhem po směrování
Když směrování odpovídá koncovému bodu, obvykle umožňuje rest spuštění kanálu middlewaru před vyvoláním logiky koncového bodu. Služby můžou snížit využití prostředků filtrováním známých požadavků v rané fázi kanálu. Metodu ShortCircuit rozšíření použijte k okamžitému vyvolání logiky koncového bodu směrování a následnému ukončení požadavku. Například daná trasa nemusí procházet ověřováním nebo middlewarem CORS. Následující příklad žádostí o zkraty, které odpovídají /short-circuit
trase:
app.MapGet("/short-circuit", () => "Short circuiting!").ShortCircuit();
Metoda ShortCircuit(IEndpointConventionBuilder, Nullable<Int32>) může volitelně převzít stavový kód.
MapShortCircuit Pomocí metody můžete nastavit zkratování pro více tras najednou předáním pole parametrů s předponami adresy URL. Například prohlížeče a roboti často testují servery pro dobře známé cesty jako robots.txt
a favicon.ico
. Pokud aplikace tyto soubory nemá, může jeden řádek kódu nakonfigurovat obě trasy:
app.MapShortCircuit(404, "robots.txt", "favicon.ico");
MapShortCircuit
vrátí, IEndpointConventionBuilder aby do ní bylo možné přidat další omezení směrování, jako je filtrování hostitelů.
MapShortCircuit
Metody nemají vliv na ShortCircuit
middleware umístěný před UseRouting
. Při pokusu o použití těchto metod s koncovými body, které mají [Authorize]
také metadata, [RequireCors]
způsobí selhání požadavků s chybou InvalidOperationException
. Tato metadata se použijí pomocí [Authorize]
[EnableCors]
atributů nebo RequireCors metod nebo RequireAuthorization metod.
Chcete-li zobrazit účinek zkratového middlewaru, nastavte kategorii protokolování "Microsoft" na "Informace" v appsettings.Development.json
:
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Information",
"Microsoft.Hosting.Lifetime": "Information"
}
}
}
Spusťte následující kód:
var app = WebApplication.Create();
app.UseHttpLogging();
app.MapGet("/", () => "No short-circuiting!");
app.MapGet("/short-circuit", () => "Short circuiting!").ShortCircuit();
app.MapShortCircuit(404, "robots.txt", "favicon.ico");
app.Run();
Následující příklad pochází z protokolů konzoly vytvořených spuštěním koncového /
bodu. Zahrnuje výstup z middlewaru protokolování:
info: Microsoft.AspNetCore.Routing.EndpointMiddleware[0]
Executing endpoint 'HTTP: GET /'
info: Microsoft.AspNetCore.Routing.EndpointMiddleware[1]
Executed endpoint 'HTTP: GET /'
info: Microsoft.AspNetCore.HttpLogging.HttpLoggingMiddleware[2]
Response:
StatusCode: 200
Content-Type: text/plain; charset=utf-8
Date: Wed, 03 May 2023 21:05:59 GMT
Server: Kestrel
Alt-Svc: h3=":5182"; ma=86400
Transfer-Encoding: chunked
Následující příklad pochází ze spuštění koncového /short-circuit
bodu. Nemá nic z middlewaru protokolování, protože middleware byl zkrácený:
info: Microsoft.AspNetCore.Routing.EndpointRoutingMiddleware[4]
The endpoint 'HTTP: GET /short-circuit' is being executed without running additional middleware.
info: Microsoft.AspNetCore.Routing.EndpointRoutingMiddleware[5]
The endpoint 'HTTP: GET /short-circuit' has been executed without running additional middleware.
Pokyny pro autory knihoven
Tato část obsahuje pokyny pro autory knihoven, kteří vycházejí ze směrování. Cílem těchto podrobností je zajistit, aby vývojáři aplikací měli dobré zkušenosti s používáním knihoven a architektur, které rozšiřují směrování.
Definování koncových bodů
Pokud chcete vytvořit architekturu, která používá směrování pro porovnávání adres URL, začněte definováním uživatelského prostředí, které je postavené na UseEndpoints.
DO staví na vrcholu IEndpointRouteBuilder. To umožňuje uživatelům vytvářet architekturu s jinými funkcemi ASP.NET Core bez nejasností. Každá šablona ASP.NET Core zahrnuje směrování. Předpokládejme, že směrování je pro uživatele k dispozici a známé.
// Your framework
app.MapMyFramework(...);
app.MapHealthChecks("/healthz");
DO vrátit zapečetěný beton typ z volání MapMyFramework(...)
, které implementuje IEndpointConventionBuilder. Většina metod architektury Map...
tento vzor dodržuje. Rozhraní IEndpointConventionBuilder
:
- Umožňuje složená metadata.
- Cílí na různé rozšiřující metody.
Deklarování vlastního typu umožňuje do tvůrce přidat vlastní funkce specifické pro architekturu. Je v pořádku zabalit tvůrce deklarovaného architekturou a předat do něj volání.
// Your framework
app.MapMyFramework(...)
.RequireAuthorization()
.WithMyFrameworkFeature(awesome: true);
app.MapHealthChecks("/healthz");
ZVAŽTE psaní vlastního EndpointDataSource. EndpointDataSource
je primitivní úroveň nízké úrovně pro deklarování a aktualizaci kolekce koncových bodů. EndpointDataSource
je výkonné rozhraní API používané kontrolery a Razor stránkami. Další informace najdete v tématu Dynamické směrování koncových bodů.
Testy směrování mají základní příklad neaktualizuje zdroje dat.
ZVAŽTE implementaci GetGroupedEndpoints. Tím získáte úplnou kontrolu nad spouštěním konvencí skupin a konečnými metadaty ve seskupených koncových bodech. To například umožňuje vlastní EndpointDataSource
implementaci spouštět filtry koncových bodů přidané do skupin.
VE výchozím nastavení se nepokoušejte EndpointDataSource
o registraci. Vyžadovat, aby uživatelé zaregistrovali vaši architekturu v UseEndpoints. Filozofie směrování spočívá v tom, že ve výchozím nastavení se nic nezahrnuje a je to UseEndpoints
místo pro registraci koncových bodů.
Vytvoření middlewaru integrovaného se směrováním
ZVAŽTE definování typů metadat jako rozhraní.
Umožňuje použít typy metadat jako atribut tříd a metod.
public interface ICoolMetadata
{
bool IsCool { get; }
}
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
public class CoolMetadataAttribute : Attribute, ICoolMetadata
{
public bool IsCool => true;
}
Architektury, jako jsou kontrolery a Razor stránky, podporují použití atributů metadat na typy a metody. Pokud deklarujete typy metadat:
- Zpřístupní je jako atributy.
- Většina uživatelů má zkušenosti s používáním atributů.
Deklarace typu metadat jako rozhraní přidává další vrstvu flexibility:
- Rozhraní jsou kompozibilní.
- Vývojáři můžou deklarovat své vlastní typy, které kombinují více zásad.
Umožňuje přepsat metadata, jak je znázorněno v následujícím příkladu:
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
public class SuppressCoolMetadataAttribute : Attribute, ICoolMetadata
{
public bool IsCool => false;
}
[CoolMetadata]
public class MyController : Controller
{
public void MyCool() { }
[SuppressCoolMetadata]
public void Uncool() { }
}
Nejlepší způsob, jak postupovat podle těchto pokynů, je vyhnout se definování metadat značek:
- Nehledáte jenom přítomnost typu metadat.
- Definujte vlastnost metadat a zkontrolujte vlastnost.
Kolekce metadat je seřazená a podporuje přepsání podle priority. V případě kontrolerů jsou metadata pro metodu akce nejvýraznější.
Do make middleware užitečný s a bez směrování:
app.UseAuthorization(new AuthorizationPolicy() { ... });
// Your framework
app.MapMyFramework(...).RequireAuthorization();
Jako příklad tohoto návodu UseAuthorization
zvažte middleware. Middleware pro autorizaci umožňuje předávat záložní zásady. Záložní zásada, pokud je zadaná, platí pro obě:
- Koncové body bez zadané zásady
- Požadavky, které neodpovídají koncovému bodu.
Díky tomu je middleware autorizace užitečný mimo kontext směrování. Autorizační middleware lze použít pro tradiční programování middlewaru.
Ladění diagnostiky
Podrobný výstup diagnostiky směrování nastavíte Logging:LogLevel:Microsoft
na Debug
hodnotu . Ve vývojovém prostředí nastavte úroveň protokolu v appsettings.Development.json
:
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Debug",
"Microsoft.Hosting.Lifetime": "Information"
}
}
}
Další materiály
Směrování zodpovídá za porovnávání příchozích požadavků HTTP a odesílání těchto požadavků do spustitelných koncových bodů aplikace. Koncové body jsou jednotky spustitelného kódu zpracování požadavků. Koncové body se definují v aplikaci a konfigurují se při spuštění aplikace. Proces porovnávání koncových bodů může extrahovat hodnoty z adresy URL požadavku a poskytnout tyto hodnoty pro zpracování požadavků. Pomocí informací o koncovém bodu z aplikace je směrování také schopné generovat adresy URL, které se mapují na koncové body.
Aplikace můžou nakonfigurovat směrování pomocí:
- Kontrolery
- Razor Pages
- SignalR
- gRPC Services
- Middleware s povoleným koncovým bodem, jako jsou kontroly stavu.
- Delegáti a lambda zaregistrované ve směrování
Tento článek se zabývá podrobnostmi nízké úrovně směrování ASP.NET Core. Informace o konfiguraci směrování:
- Informace o kontroleru najdete v tématu Směrování na akce kontroleru v ASP.NET Core.
- Konvence Razor stránek najdete v tématu Razor Stránky trasy a konvence aplikací v ASP.NET Core.
Základy směrování
Následující kód ukazuje základní příklad směrování:
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
app.MapGet("/", () => "Hello World!");
app.Run();
Předchozí příklad obsahuje jeden koncový bod pomocí MapGet metody:
- Při odeslání požadavku HTTP
GET
na kořenovou adresu URL/
:- Delegát požadavku se spustí.
Hello World!
je zapsán do odpovědi HTTP.
- Pokud metoda požadavku není
GET
nebo kořenová adresa URL není/
, žádná trasa neodpovídá a vrátí se http 404.
Směrování používá dvojici middlewaru, zaregistrovaného uživatelem UseRouting a UseEndpoints:
UseRouting
přidá trasu odpovídající kanálu middlewaru. Tento middleware se podívá na sadu koncových bodů definovaných v aplikaci a vybere nejlepší shodu na základě požadavku.UseEndpoints
přidá spuštění koncového bodu do kanálu middlewaru. Spustí delegáta přidruženého k vybranému koncovému bodu.
Aplikace obvykle nemusí volat UseRouting
ani UseEndpoints
. WebApplicationBuilder konfiguruje middlewarový kanál, který zabalí middleware přidaný do Program.cs
UseRouting
a UseEndpoints
. Aplikace ale můžou změnit pořadí, ve kterém UseRouting
se budou spouštět, UseEndpoints
a to explicitním voláním těchto metod. Například následující kód provede explicitní volání UseRouting
:
app.Use(async (context, next) =>
{
// ...
await next(context);
});
app.UseRouting();
app.MapGet("/", () => "Hello World!");
V předchozím kódu:
- Volání pro
app.Use
registraci vlastního middlewaru, který se spouští na začátku kanálu. - Volání konfiguruje
UseRouting
middleware odpovídající směrování tak, aby se spustil po vlastním middlewaru. - Koncový bod zaregistrovaný na
MapGet
konci kanálu se spustí.
Pokud by předchozí příklad nezahrnoval volání UseRouting
, vlastní middleware by se spustil za middlewarem odpovídajícím trasě.
Koncové body
Metoda MapGet
se používá k definování koncového bodu. Koncový bod je něco, co může být:
- Vybráno tak, že se shoduje s adresou URL a metodou HTTP.
- Spustí se spuštěním delegáta.
Koncové body, které se dají spárovat a spouštět aplikací, jsou nakonfigurované v UseEndpoints
. Například MapGet, MapPosta podobné metody připojit žádosti delegáty do systému směrování. Další metody lze použít k připojení funkcí architektury ASP.NET Core ke směrovacímu systému:
- MapRazorPages for Razor Pages
- MapControllers pro kontrolery
- MapHub THub<> forSignalR
- MapGrpcService TService<> pro gRPC
Následující příklad ukazuje směrování s sofistikovanější šablonou trasy:
app.MapGet("/hello/{name:alpha}", (string name) => $"Hello {name}!");
Řetězec /hello/{name:alpha}
je šablona trasy. Ke konfiguraci shody koncového bodu se používá šablona trasy. V tomto případě šablona odpovídá:
- Adresa URL, jako je
/hello/Docs
- Všechny cesty URL, které začínají
/hello/
posloupností abecedních znaků.:alpha
použije omezení trasy, které odpovídá pouze abecedním znakům. Omezení tras jsou vysvětlena dále v tomto článku.
Druhý segment cesty URL: {name:alpha}
- Je vázán na
name
parametr. - Je zachycen a uložen v HttpRequest.RouteValues.
Následující příklad ukazuje směrování s kontrolami stavu a autorizací:
app.UseAuthentication();
app.UseAuthorization();
app.MapHealthChecks("/healthz").RequireAuthorization();
app.MapGet("/", () => "Hello World!");
Předchozí příklad ukazuje, jak:
- S směrováním je možné použít autorizační middleware.
- Koncové body je možné použít ke konfiguraci chování autorizace.
Volání MapHealthChecks přidá koncový bod kontroly stavu. Při zřetězování RequireAuthorization k tomuto volání se ke koncovému bodu připojí zásady autorizace.
Volání UseAuthentication a UseAuthorization přidání middlewaru pro ověřování a autorizaci Tyto middleware jsou umístěny mezi UseRouting a UseEndpoints
tak, aby mohly:
- Podívejte se, který koncový bod vybral
UseRouting
. - Před odesláním do koncového bodu použijte zásadu UseEndpoints autorizace.
Metadata koncového bodu
V předchozím příkladu existují dva koncové body, ale k autorizační zásadě jsou připojené jenom koncové body kontroly stavu. Pokud požadavek odpovídá koncovému bodu kontroly stavu, /healthz
provede se kontrola autorizace. To ukazuje, že koncové body můžou mít připojená další data. Tato další data se nazývají metadata koncového bodu:
- Metadata je možné zpracovat pomocí middlewaru pracujícího se směrováním.
- Metadata můžou být libovolného typu .NET.
Koncepty směrování
Systém směrování vychází z kanálu middlewaru přidáním výkonného konceptu koncového bodu . Koncové body představují jednotky funkcí aplikace, které se vzájemně liší z hlediska směrování, autorizace a libovolného počtu systémů ASP.NET Core.
Definice koncového bodu ASP.NET Core
Koncový bod ASP.NET Core je:
- Spustitelný soubor: Má .RequestDelegate
- Rozšiřitelný: Má kolekci metadat .
- Možnost výběru: Volitelně obsahuje informace o směrování.
- Výčet: Kolekci koncových bodů je možné uvést načtením EndpointDataSource z DI.
Následující kód ukazuje, jak načíst a zkontrolovat koncový bod odpovídající aktuálnímu požadavku:
app.Use(async (context, next) =>
{
var currentEndpoint = context.GetEndpoint();
if (currentEndpoint is null)
{
await next(context);
return;
}
Console.WriteLine($"Endpoint: {currentEndpoint.DisplayName}");
if (currentEndpoint is RouteEndpoint routeEndpoint)
{
Console.WriteLine($" - Route Pattern: {routeEndpoint.RoutePattern}");
}
foreach (var endpointMetadata in currentEndpoint.Metadata)
{
Console.WriteLine($" - Metadata: {endpointMetadata}");
}
await next(context);
});
app.MapGet("/", () => "Inspect Endpoint.");
Koncový bod, pokud je vybraný, lze načíst z objektu HttpContext
. Jeho vlastnosti je možné zkontrolovat. Objekty koncového bodu jsou neměnné a po vytvoření není možné je změnit. Nejběžnějším typem RouteEndpointkoncového bodu je . RouteEndpoint
obsahuje informace, které mu umožní vybrat směrovací systém.
V předchozím kódu aplikace. Slouží ke konfiguraci vloženého middlewaru.
Následující kód ukazuje, že v závislosti na tom, kde app.Use
se v kanálu volá, nemusí existovat koncový bod:
// Location 1: before routing runs, endpoint is always null here.
app.Use(async (context, next) =>
{
Console.WriteLine($"1. Endpoint: {context.GetEndpoint()?.DisplayName ?? "(null)"}");
await next(context);
});
app.UseRouting();
// Location 2: after routing runs, endpoint will be non-null if routing found a match.
app.Use(async (context, next) =>
{
Console.WriteLine($"2. Endpoint: {context.GetEndpoint()?.DisplayName ?? "(null)"}");
await next(context);
});
// Location 3: runs when this endpoint matches
app.MapGet("/", (HttpContext context) =>
{
Console.WriteLine($"3. Endpoint: {context.GetEndpoint()?.DisplayName ?? "(null)"}");
return "Hello World!";
}).WithDisplayName("Hello");
app.UseEndpoints(_ => { });
// Location 4: runs after UseEndpoints - will only run if there was no match.
app.Use(async (context, next) =>
{
Console.WriteLine($"4. Endpoint: {context.GetEndpoint()?.DisplayName ?? "(null)"}");
await next(context);
});
Předchozí ukázka přidá Console.WriteLine
příkazy, které zobrazují, jestli byl vybrán koncový bod nebo ne. Pro přehlednost ukázka přiřadí zadaný koncový bod zobrazovaný název /
.
Předchozí ukázka také zahrnuje volání UseRouting
a UseEndpoints
řízení přesně toho, kdy se tyto middlewary spouští v rámci kanálu.
Spuštění tohoto kódu s adresou URL /
zobrazení:
1. Endpoint: (null)
2. Endpoint: Hello
3. Endpoint: Hello
Spuštění tohoto kódu s jakoukoli jinou adresou URL zobrazí:
1. Endpoint: (null)
2. Endpoint: (null)
4. Endpoint: (null)
Tento výstup ukazuje, že:
- Koncový bod je před zavolání vždy null
UseRouting
. - Pokud se najde shoda, koncový bod je mezi
UseRouting
a UseEndpoints. - Middleware
UseEndpoints
je terminál , když se najde shoda. Middleware terminálu je definován dále v tomto článku. - Middleware po spuštění pouze v
UseEndpoints
případě, že nebyla nalezena žádná shoda.
Middleware UseRouting
používá metodu SetEndpoint pro připojení koncového bodu k aktuálnímu kontextu. Middleware je možné nahradit UseRouting
vlastní logikou a přesto získat výhody používání koncových bodů. Koncové body jsou primitivní nízké úrovně, jako je middleware, a nejsou svázané s implementací směrování. Většina aplikací nemusí nahradit UseRouting
vlastní logikou.
Middleware UseEndpoints
je navržený tak, aby se používal společně s middlewarem UseRouting
. Základní logika pro spuštění koncového bodu není složitá. Slouží GetEndpoint k načtení koncového bodu a následnému vyvolání jeho RequestDelegate vlastnosti.
Následující kód ukazuje, jak může middleware ovlivnit nebo reagovat na směrování:
app.UseHttpMethodOverride();
app.UseRouting();
app.Use(async (context, next) =>
{
if (context.GetEndpoint()?.Metadata.GetMetadata<RequiresAuditAttribute>() is not null)
{
Console.WriteLine($"ACCESS TO SENSITIVE DATA AT: {DateTime.UtcNow}");
}
await next(context);
});
app.MapGet("/", () => "Audit isn't required.");
app.MapGet("/sensitive", () => "Audit required for sensitive data.")
.WithMetadata(new RequiresAuditAttribute());
public class RequiresAuditAttribute : Attribute { }
Předchozí příklad ukazuje dva důležité koncepty:
- Middleware se může spustit před
UseRouting
úpravou dat, se kterými směrování pracuje.- Obvykle middleware, který se zobrazí před úpravou směrování některé vlastnosti požadavku, například UseRewriter, UseHttpMethodOverridenebo UsePathBase.
- Middleware se může spustit mezi
UseRouting
směrováním a UseEndpoints zpracovat výsledky směrování před spuštěním koncového bodu.- Middleware, který běží mezi
UseRouting
aUseEndpoints
:- Obvykle kontroluje metadata, aby porozuměla koncovým bodům.
- Často provádí rozhodnutí o zabezpečení, jak to dělá
UseAuthorization
aUseCors
.
- Kombinace middlewaru a metadat umožňuje konfigurovat zásady pro jednotlivé koncové body.
- Middleware, který běží mezi
Předchozí kód ukazuje příklad vlastního middlewaru, který podporuje zásady pro jednotlivé koncové body. Middleware zapíše protokol auditu přístupu k citlivým datům do konzoly. Middleware je možné nakonfigurovat tak, aby auditoval koncový bod s RequiresAuditAttribute
metadaty. Tato ukázka ukazuje způsob vyjádření výslovného souhlasu, kdy se auditují jenom koncové body označené jako citlivé. Tuto logiku je možné definovat obráceně, auditovat všechno, co není označené jako bezpečné, například. Systém metadat koncového bodu je flexibilní. Tato logika by mohla být navržena jakýmkoli způsobem, který vyhovuje případu použití.
Předchozí vzorový kód je určený k předvedení základních konceptů koncových bodů. Ukázka není určená pro produkční použití. Ucelenější verze middlewaru protokolu auditu:
- Přihlaste se k souboru nebo databázi.
- Uveďte podrobnosti, jako je uživatel, IP adresa, název citlivého koncového bodu a další.
Metadata zásad auditu jsou definována RequiresAuditAttribute
jako Attribute
jednodušší použití s architekturami založenými na třídách, jako jsou kontrolery a SignalR. Při použití trasy ke kódu:
- Metadata jsou připojena pomocí rozhraní API tvůrce.
- Architektury založené na třídách zahrnují všechny atributy odpovídající metody a třídy při vytváření koncových bodů.
Osvědčenými postupy pro typy metadat je definovat buď jako rozhraní, nebo atributy. Rozhraní a atributy umožňují opakované použití kódu. Systém metadat je flexibilní a neukládá žádná omezení.
Porovnání middlewaru terminálu se směrováním
Následující příklad ukazuje terminálový middleware i směrování:
// Approach 1: Terminal Middleware.
app.Use(async (context, next) =>
{
if (context.Request.Path == "/")
{
await context.Response.WriteAsync("Terminal Middleware.");
return;
}
await next(context);
});
app.UseRouting();
// Approach 2: Routing.
app.MapGet("/Routing", () => "Routing.");
Styl middlewaru zobrazeného s terminálovým middlewarem Approach 1:
. Říká se tomu middleware terminálu, protože dělá odpovídající operaci:
- Odpovídající operace v předchozí ukázce je
Path == "/"
pro middleware aPath == "/Routing"
pro směrování. - Když je shoda úspěšná, spustí některé funkce a vrátí se místo vyvolání middlewaru
next
.
Říká se tomu middleware terminálu, protože ukončí hledání, spustí některé funkce a vrátí se.
Následující seznam porovnává middleware terminálu se směrováním:
- Oba přístupy umožňují ukončení kanálu zpracování:
- Middleware ukončí kanál tím, že se místo vyvolání
next
. - Koncové body jsou vždy terminálové.
- Middleware ukončí kanál tím, že se místo vyvolání
- Middleware terminálu umožňuje umístění middlewaru na libovolné místo v kanálu:
- Koncové body se provádějí na pozici UseEndpoints.
- Middleware terminálu umožňuje libovolnému kódu určit, kdy middleware odpovídá:
- Vlastní kód pro porovnávání tras může být podrobný a obtížně zapisuje správně.
- Směrování poskytuje jednoduchá řešení pro typické aplikace. Většina aplikací nevyžaduje vlastní kód pro porovnávání tras.
- Rozhraní koncových bodů s middlewarem, jako
UseAuthorization
je například aUseCors
.- Použití middlewaru terminálu s
UseAuthorization
autorizačním systémem neboUseCors
vyžaduje ruční propojení se systémem autorizace.
- Použití middlewaru terminálu s
Koncový bod definuje obojí:
- Delegát na zpracování požadavků.
- Kolekce libovolných metadat. Metadata se používají k implementaci průřezových aspektů na základě zásad a konfigurace připojených k jednotlivým koncovým bodům.
Terminálový middleware může být efektivní nástroj, ale může vyžadovat:
- Značné množství kódování a testování.
- Ruční integrace s jinými systémy za účelem dosažení požadované úrovně flexibility.
Před zápisem middlewaru terminálu zvažte integraci se směrováním.
Existující middleware terminálu, který se integruje s mapou , nebo MapWhen se obvykle dá převést na koncový bod podporující směrování. MapHealthChecks ukazuje vzor pro router-ware:
- Napište metodu rozšíření na IEndpointRouteBuilder.
- Vytvoření vnořeného kanálu middlewaru pomocí CreateApplicationBuilder.
- Připojte middleware k novému kanálu. V tomto případě . UseHealthChecks
- Buildmiddlewarový kanál do .RequestDelegate
- Zavolejte a poskytněte
Map
nový kanál middlewaru. - Vrátí objekt tvůrce poskytnutý
Map
metodou rozšíření.
Následující kód ukazuje použití MapHealthChecks:
app.UseAuthentication();
app.UseAuthorization();
app.MapHealthChecks("/healthz").RequireAuthorization();
Předchozí ukázka ukazuje, proč je vrácení objektu tvůrce důležité. Vrácení objektu tvůrce umožňuje vývojáři aplikací konfigurovat zásady, jako je autorizace pro koncový bod. V tomto příkladu nemá middleware kontroly stavu žádnou přímou integraci se systémem autorizace.
Systém metadat byl vytvořen v reakci na problémy zjištěné autory rozšiřitelnosti pomocí middlewaru terminálu. Pro každý middleware je problematické implementovat vlastní integraci s autorizačním systémem.
Porovnávání adres URL
- Je proces, kterým směrování odpovídá příchozímu požadavku na koncový bod.
- Je založená na datech v cestě URL a hlavičkách.
- Můžete ho rozšířit, abyste zvážili všechna data v požadavku.
Když se spustí middleware směrování, nastaví Endpoint
hodnotu požadavku na funkci HttpContext požadavku z aktuálního požadavku:
- Volání httpContext.GetEndpoint získá koncový bod.
HttpRequest.RouteValues
získá kolekci hodnot tras.
Middleware se spustí po spuštění middlewaru směrování, který může zkontrolovat koncový bod a provést akci. Například autorizační middleware může probrat kolekci metadat koncového bodu pro zásady autorizace. Po spuštění veškerého middlewaru v kanálu zpracování požadavků se vyvolá delegát vybraného koncového bodu.
Systém směrování ve směrování koncového bodu zodpovídá za veškerá rozhodnutí o odesílání. Vzhledem k tomu, že middleware používá zásady na základě vybraného koncového bodu, je důležité, aby:
- Jakékoli rozhodnutí, které může ovlivnit odesílání nebo použití zásad zabezpečení, se provádí v rámci systému směrování.
Upozorňující
V případě zpětné kompatibility se při spuštění delegáta koncového RouteContext.RouteData bodu kontroleru nebo Razor stránky nastaví vlastnosti na odpovídající hodnoty na základě dosud provedeného zpracování požadavku.
Typ RouteContext
bude v budoucí verzi označen jako zastaralý:
- Migrovat
RouteData.Values
naHttpRequest.RouteValues
. - Migrace
RouteData.DataTokens
pro načtení IDataTokensMetadata z metadat koncového bodu
Porovnávání adres URL funguje v konfigurovatelné sadě fází. V každé fázi je výstup sadou shod. Sadu shod lze dále zúžit v další fázi. Implementace směrování nezaručuje pořadí zpracování pro odpovídající koncové body. Všechny možné shody se zpracovávají najednou. Fáze porovnávání adres URL probíhají v následujícím pořadí. ASP.NET Core:
- Zpracovává cestu URL vůči sadě koncových bodů a jejich šablon tras a shromažďuje všechny shody.
- Vezme předchozí seznam a odebere shody, které selžou s použitými omezeními trasy.
- Vezme předchozí seznam a odebere shody, které sadu instancí selžou MatcherPolicy .
- EndpointSelector Použije k poslednímu rozhodnutí z předchozího seznamu.
Seznam koncových bodů má prioritu podle následujících:
- RouteEndpoint.Order
- Priorita šablony trasy
Všechny odpovídající koncové body se zpracovávají v každé fázi, dokud se nedosáhne EndpointSelector . Jedná se EndpointSelector
o konečnou fázi. Jako nejlepší shodu zvolí koncový bod s nejvyšší prioritou. Pokud existují jiné shody se stejnou prioritou jako nejlepší shoda, vyvolá se výjimka nejednoznačné shody.
Priorita trasy se vypočítá na základě konkrétnější šablony trasy, která má vyšší prioritu. Představte si například šablony /hello
a /{message}
:
- Obě odpovídají cestě
/hello
URL . /hello
je konkrétnější a proto vyšší priorita.
Obecně platí, že priorita trasy má dobrou úlohu při výběru nejvhodnější shody pro druhy schémat adres URL používaných v praxi. Používejte Order pouze v případě potřeby, abyste se vyhnuli nejednoznačnosti.
Vzhledem k druhům rozšiřitelnosti poskytované směrováním není možné, aby směrovací systém předem počítaly nejednoznačné trasy. Představte si příklad, jako jsou šablony /{message:alpha}
tras a /{message:int}
:
- Omezení
alpha
odpovídá pouze abecedním znakům. - Omezení
int
odpovídá pouze číslu. - Tyto šablony mají stejnou prioritu tras, ale obě adresy URL se neshodují.
- Pokud systém směrování nahlásil při spuštění nejednoznačnosti, zablokoval by tento platný případ použití.
Upozorňující
Pořadí operací uvnitř UseEndpoints nemá vliv na chování směrování, s jednou výjimkou. MapControllerRoute a MapAreaRoute automaticky přiřadí hodnotu objednávky ke svým koncovým bodům na základě pořadí, ve které jsou vyvolány. To simuluje dlouhodobé chování kontrolerů bez systému směrování, který poskytuje stejné záruky jako starší implementace směrování.
Směrování koncových bodů v ASP.NET Core:
- Nemá koncept tras.
- Neposkytuje záruky objednávání. Všechny koncové body se zpracovávají najednou.
Priorita šablony trasy a pořadí výběru koncového bodu
Priorita šablony trasy je systém, který každé šabloně trasy přiřadí hodnotu na základě toho, jak je konkrétní. Priorita šablony trasy:
- Vyhne se nutnosti upravovat pořadí koncových bodů v běžných případech.
- Snaží se shodovat s očekáváními obecného chování směrování.
Představte si například šablony /Products/List
a /Products/{id}
. Bylo by rozumné předpokládat, že /Products/List
je lepší shoda než /Products/{id}
pro cestu /Products/List
URL . To funguje, protože literálový segment /List
je považován za lepší prioritu než segment /{id}
parametru .
Podrobnosti o tom, jak funguje priorita, jsou svázány s tím, jak se definují šablony tras:
- Šablony s více segmenty jsou považovány za konkrétnější.
- Segment s literálovým textem se považuje za konkrétnější než segment parametru.
- Segment parametru s omezením se považuje za konkrétnější než jeden bez.
- Složitý segment se považuje za specifický jako segment parametru s omezením.
- Parametry pro zachytávání jsou nejmíň specifické. Důležité informace o trasách pro zachytávání všech tras najdete v části Šablony tras catch-all.
Koncepty generování adres URL
Generování adres URL:
- Je proces, pomocí kterého směrování může vytvořit cestu URL na základě sady hodnot tras.
- Umožňuje logické oddělení mezi koncovými body a adresami URL, které k nim přistupují.
Směrování koncových bodů zahrnuje LinkGenerator rozhraní API. LinkGenerator
je jednoúčelová služba, která je k dispozici z DI. Rozhraní LinkGenerator
API se dá použít mimo kontext spuštěného požadavku. Mvc.IUrlHelper a scénáře, které se spoléhají , IUrlHelperjako jsou pomocné rutiny značek, pomocné rutiny HTML a výsledky akcí, používají LinkGenerator
rozhraní API interně k poskytování možností generování odkazů.
Generátor odkazů je podporován konceptem adresního a adresního schématu. Schéma adres je způsob, jak určit koncové body, které by se měly zvážit pro generování propojení. Například scénáře názvu trasy a směrovacích hodnot, které mnoho uživatelů znáte z kontrolerů a Razor Stránky se implementují jako schéma adres.
Generátor odkazů může odkazovat na kontrolery a Razor stránky pomocí následujících rozšiřujících metod:
Přetížení těchto metod přijímají argumenty, které zahrnují HttpContext
. Tyto metody jsou funkčně ekvivalentní url.Action a Url.Page, ale nabízejí další flexibilitu a možnosti.
Metody GetPath*
jsou nejvíce podobné Url.Action
a Url.Page
v tom, že vygenerují identifikátor URI obsahující absolutní cestu. Metody GetUri*
vždy generují absolutní identifikátor URI obsahující schéma a hostitele. Metody, které přijímají HttpContext
vygenerování identifikátoru URI v kontextu prováděcího požadavku. Hodnoty okolní trasy, základní cesta URL, schéma a hostitel ze spuštěného požadavku se použijí, pokud je nepřepíšete.
LinkGenerator je volána s adresou. Generování identifikátoru URI probíhá ve dvou krocích:
- Adresa je svázaná se seznamem koncových bodů, které odpovídají adrese.
- Vyhodnocuje se RoutePattern každý koncový bod, dokud se nenajde vzor trasy, který odpovídá zadaným hodnotám. Výsledný výstup se zkombinuje s ostatními částmi identifikátoru URI zadanými do generátoru propojení a vrátí se.
Metody poskytované standardními možnostmi LinkGenerator generování propojení pro libovolný typ adresy. Nejpohodlnější způsob použití generátoru propojení je prostřednictvím rozšiřujících metod, které provádějí operace pro konkrétní typ adresy:
Extension – metoda | Popis |
---|---|
GetPathByAddress | Vygeneruje identifikátor URI s absolutní cestou na základě zadaných hodnot. |
GetUriByAddress | Vygeneruje absolutní identifikátor URI na základě zadaných hodnot. |
Upozorňující
Věnujte pozornost následujícím důsledkům volání LinkGenerator metod:
V konfiguraci aplikace používejte
GetUri*
metody rozšíření s opatrností, která neověřuje hlavičkuHost
příchozích požadavků. Pokud hlavičkaHost
příchozích požadavků není ověřená, může být nedůvěryhodný vstup požadavku odeslán zpět klientovi v identifikátorech URI v zobrazení nebo stránce. Doporučujeme, aby všechny produkční aplikace nakonfigurovaly svůj server tak, aby ověřovaly hlavičkuHost
proti známým platným hodnotám.Používejte LinkGenerator s opatrností v middlewaru v kombinaci s
Map
neboMapWhen
.Map*
změní základní cestu prováděcího požadavku, která má vliv na výstup generování propojení. LinkGenerator Všechna rozhraní API umožňují zadat základní cestu. Zadejte prázdnouMap*
základní cestu, která vrátí zpět vliv na generování propojení.
Příklad middlewaru
V následujícím příkladu middleware používá LinkGenerator rozhraní API k vytvoření odkazu na metodu akce, která obsahuje seznam produktů pro ukládání. Použití generátoru odkazů vložením do třídy a volání GenerateLink
je k dispozici pro libovolnou třídu v aplikaci:
public class ProductsMiddleware
{
private readonly LinkGenerator _linkGenerator;
public ProductsMiddleware(RequestDelegate next, LinkGenerator linkGenerator) =>
_linkGenerator = linkGenerator;
public async Task InvokeAsync(HttpContext httpContext)
{
httpContext.Response.ContentType = MediaTypeNames.Text.Plain;
var productsPath = _linkGenerator.GetPathByAction("Products", "Store");
await httpContext.Response.WriteAsync(
$"Go to {productsPath} to see our products.");
}
}
Šablony tras
Tokeny v rámci {}
definují parametry trasy, které jsou vázané, pokud se trasa shoduje. V segmentu trasy je možné definovat více než jeden parametr trasy, ale parametry trasy musí být oddělené hodnotou literálu. Příklad:
{controller=Home}{action=Index}
není platná trasa, protože neexistuje žádná hodnota literálu mezi {controller}
a {action}
. Parametry trasy musí mít název a mohou mít zadané další atributy.
Literál jiný než směrovací parametry (například {id}
) a oddělovač /
cesty musí odpovídat textu v adrese URL. Porovnávání textu nerozlišuje malá a velká písmena a vychází z dekódované reprezentace cesty adresy URL. Chcete-li se shodovat s oddělovačem {
parametru trasy literálu nebo }
, uchytáte oddělovač opakováním znaku. Například {{
nebo }}
.
Hvězdička *
nebo dvojitá hvězdička **
:
- Lze použít jako předponu parametru trasy pro vazbu na rest identifikátor URI.
- Nazývají se parametry catch-all. Příklad:
blog/{**slug}
- Odpovídá libovolnému identifikátoru
blog/
URI, který začíná a má za ním libovolnou hodnotu. - Následující hodnota
blog/
je přiřazena ke slug směrovací hodnotě.
- Odpovídá libovolnému identifikátoru
Upozorňující
Parametr catch-all může nesprávně odpovídat trasám kvůli chybě při směrování. Aplikace ovlivněné touto chybou mají následující charakteristiky:
- Například trasa pro zachytávání– vše
{**slug}"
- Trasa catch-all neodpovídá požadavkům, které by se měly shodovat.
- Odebráním jiných tras začne fungovat zachytávání všech tras.
Podívejte se na chyby GitHubu 18677 a 16579 , například případy, které tuto chybu narazily.
Oprava výslovného souhlasu s touto chybou je obsažená v sadě .NET Core 3.1.301 SDK a novějších verzích. Následující kód nastaví interní přepínač, který tuto chybu opraví:
public static void Main(string[] args)
{
AppContext.SetSwitch("Microsoft.AspNetCore.Routing.UseCorrectCatchAllBehavior",
true);
CreateHostBuilder(args).Build().Run();
}
// Remaining code removed for brevity.
Parametry catch-all mohou také odpovídat prázdnému řetězci.
Parametr catch-all umisťuje příslušné znaky při použití trasy k vygenerování adresy URL, včetně znaků oddělovače /
cest. Například trasa foo/{*path}
s hodnotami { path = "my/path" }
trasy generuje foo/my%2Fpath
. Všimněte si řídicího lomítka. Pokud chcete znaky oddělovače cest odezvy použít předponu parametru **
trasy. Trasa foo/{**path}
s { path = "my/path" }
vygenerovanými .foo/my/path
Vzory adres URL, které se pokoušejí zachytit název souboru s volitelnou příponou souboru, mají další důležité informace. Představte si například šablonu files/{filename}.{ext?}
. Když hodnoty obou filename
hodnot existují ext
, naplní se obě hodnoty. Pokud v adrese URL existuje jenom hodnota filename
, trasa se shoduje, protože koncové hodnoty .
jsou volitelné. Následující adresy URL odpovídají této trase:
/files/myFile.txt
/files/myFile
Parametry trasy můžou mít výchozí hodnoty určené zadáním výchozí hodnoty za názvem parametru odděleným symbolem rovná se (=
). Například {controller=Home}
definuje Home
jako výchozí hodnotu pro controller
. Výchozí hodnota se použije, pokud v adrese URL parametru není žádná hodnota. Parametry trasy jsou volitelné připojením otazníku (?
) na konec názvu parametru. Například id?
. Rozdíl mezi volitelnými hodnotami a výchozími parametry trasy je:
- Parametr trasy s výchozí hodnotou vždy vytvoří hodnotu.
- Volitelný parametr má hodnotu pouze v případě, že je hodnota poskytována adresou URL požadavku.
Parametry trasy můžou mít omezení, která musí odpovídat hodnotě trasy vázané z adresy URL. Přidání :
a omezení názvu za názvem parametru trasy určuje vložené omezení parametru trasy. Pokud omezení vyžaduje argumenty, jsou za názvem omezení uzavřeny v závorkách (...)
. Více vložených omezení lze zadat připojením jiného :
názvu a názvu omezení.
Název omezení a argumenty se předávají službě IInlineConstraintResolver , aby se vytvořila instance IRouteConstraint , která se má použít při zpracování adresy URL. Například šablona blog/{article:minlength(10)}
trasy určuje minlength
omezení s argumentem 10
. Další informace o omezeních tras a seznamu omezení poskytovaných architekturou najdete v části Omezení trasy.
Parametry trasy mohou mít také transformátory parametrů. Transformátory parametrů transformují hodnotu parametru při generování odkazů a odpovídajících akcí a stránek na adresy URL. Stejně jako omezení lze transformátory parametrů přidat do parametru trasy přidáním :
názvu a transformátoru za název parametru trasy. Například šablona blog/{article:slugify}
trasy určuje slugify
transformátor. Další informace o transformátorech parametrů naleznete v části Transformátory parametrů .
Následující tabulka ukazuje ukázkové šablony tras a jejich chování:
Šablona trasy | Příklad odpovídajícího identifikátoru URI | Identifikátor URI požadavku... |
---|---|---|
hello |
/hello |
Odpovídá pouze jedné cestě /hello . |
{Page=Home} |
/ |
Odpovídá a nastaví Page na Home . |
{Page=Home} |
/Contact |
Odpovídá a nastaví Page na Contact . |
{controller}/{action}/{id?} |
/Products/List |
Mapuje se na Products kontroler a List akci. |
{controller}/{action}/{id?} |
/Products/Details/123 |
Mapuje se Products na kontroler a Details akci s nastavenouid na hodnotu 123. |
{controller=Home}/{action=Index}/{id?} |
/ |
Mapuje se na kontroler a Index metoduHome . Vlastnost id je ignorována. |
{controller=Home}/{action=Index}/{id?} |
/Products |
Mapuje se na kontroler a Index metoduProducts . Vlastnost id je ignorována. |
Použití šablony je obecně nejjednodušším přístupem ke směrování. Omezení a výchozí hodnoty lze zadat také mimo šablonu trasy.
Komplexní segmenty
Komplexní segmenty se zpracovávají pomocí odpovídajících oddělovačů literálů zprava doleva způsobem, který není greedy . Jedná se například [Route("/a{b}c{d}")]
o složitý segment.
Složité segmenty fungují určitým způsobem, který je potřeba pochopit, aby je bylo možné úspěšně použít. Příklad v této části ukazuje, proč složité segmenty skutečně fungují dobře, když se text oddělovače nezobrazí uvnitř hodnot parametrů. Použití regulárního výrazu a ruční extrahování hodnot je potřeba pro složitější případy.
Upozorňující
Při zpracování System.Text.RegularExpressions nedůvěryhodného vstupu předejte vypršení časového limitu. Uživatel se zlými úmysly může poskytnout vstup, který RegularExpressions
způsobí útok na dostupnost služby. ASP.NET rozhraní API architektury Core, která používají RegularExpressions
vypršení časového limitu.
Toto je souhrn kroků, které směrování provádí pomocí šablony /a{b}c{d}
a cesty /abcd
URL . Slouží |
k vizualizaci fungování algoritmu:
- První literál, zprava doleva, je
c
. Hledá se tedy/abcd
zprava a najde/ab|c|d
. - Vše napravo (
d
) se teď shoduje s parametrem{d}
trasy . - Další literál, zprava doleva, je
a
. Takže/ab|c|d
je prohledáno od místa, kde jsme skončili, paka
je nalezen/|a|b|c|d
. - Hodnota vpravo (
b
) se teď shoduje s parametrem{b}
trasy . - Neexistuje žádný zbývající text a žádná zbývající šablona trasy, takže se jedná o shodu.
Tady je příklad záporného případu, který používá stejnou šablonu /a{b}c{d}
a cestu /aabcd
URL . Slouží |
k vizualizaci fungování algoritmu. Tento případ není shoda, která je vysvětlená stejným algoritmem:
- První literál, zprava doleva, je
c
. Hledá se tedy/aabcd
zprava a najde/aab|c|d
. - Vše napravo (
d
) se teď shoduje s parametrem{d}
trasy . - Další literál, zprava doleva, je
a
. Takže/aab|c|d
je prohledáno od místa, kde jsme skončili, paka
je nalezen/a|a|b|c|d
. - Hodnota vpravo (
b
) se teď shoduje s parametrem{b}
trasy . - V tomto okamžiku existuje zbývající text
a
, ale algoritmus vyčeráhl šablonu trasy, aby parsovala, takže se nejedná o shodu.
Vzhledem k tomu, že odpovídající algoritmus není greedy:
- Odpovídá nejmenšímu množství textu, který je možné v každém kroku.
- Případ, kdy se hodnota oddělovače zobrazí uvnitř hodnot parametrů, způsobí, že se neshoduje.
Regulární výrazy poskytují mnohem větší kontrolu nad jejich odpovídajícím chováním.
Párování Greedy, označované také jako opožděné párování, odpovídá největšímu možnému řetězci. Greedy odpovídá nejmenšímu možnému řetězci.
Směrování se speciálními znaky
Směrování se speciálními znaky může vést k neočekávaným výsledkům. Představte si například kontroler s následující metodou akce:
[HttpGet("{id?}/name")]
public async Task<ActionResult<string>> GetName(string id)
{
var todoItem = await _context.TodoItems.FindAsync(id);
if (todoItem == null || todoItem.Name == null)
{
return NotFound();
}
return todoItem.Name;
}
Pokud string id
obsahuje následující kódované hodnoty, mohou dojít k neočekávaným výsledkům:
ASCII | Encoded |
---|---|
/ |
%2F |
|
+ |
Parametry trasy nejsou vždy dekódovány adresou URL. Tento problém může být vyřešen v budoucnu. Další informace najdete v tomto problému na GitHubu.
Omezení trasy
Omezení směrování se provádějí, když došlo ke shodě s příchozí adresou URL a cesta url se tokenizuje do hodnot tras. Omezení tras obecně kontrolují hodnotu trasy přidruženou prostřednictvím šablony trasy a ověřte, jestli je hodnota přijatelná, nebo nepravdivá. Některá omezení trasy používají data mimo hodnotu trasy a zvažují, jestli je možné požadavek směrovat. Například HttpMethodRouteConstraint může přijmout nebo odmítnout požadavek na základě jeho příkazu HTTP. Omezení se používají v požadavcích směrování a generování propojení.
Upozorňující
Nepoužívejte omezení pro ověřování vstupu. Pokud se pro ověření vstupu používají omezení, výsledkem neplatného 404
vstupu je odpověď Nenalezena. Neplatný vstup by měl vytvořit chybný 400
požadavek s příslušnou chybovou zprávou. Omezení tras se používají k nejednoznačnosti podobných tras, nikoli k ověření vstupů pro konkrétní trasu.
Následující tabulka ukazuje ukázková omezení směrování a jejich očekávané chování:
omezení | Příklad | Příklady shod | Notes |
---|---|---|---|
int |
{id:int} |
123456789 , -123456789 |
Odpovídá libovolnému celočíselnému číslu. |
bool |
{active:bool} |
true , FALSE |
Shody true nebo false . Nerozlišují se malá a velká písmena |
datetime |
{dob:datetime} |
2016-12-31 , 2016-12-31 7:32pm |
Odpovídá platné DateTime hodnotě v invariantní jazykové verzi. Viz předchozí upozornění. |
decimal |
{price:decimal} |
49.99 , -1,000.01 |
Odpovídá platné decimal hodnotě v invariantní jazykové verzi. Viz předchozí upozornění. |
double |
{weight:double} |
1.234 , -1,001.01e8 |
Odpovídá platné double hodnotě v invariantní jazykové verzi. Viz předchozí upozornění. |
float |
{weight:float} |
1.234 , -1,001.01e8 |
Odpovídá platné float hodnotě v invariantní jazykové verzi. Viz předchozí upozornění. |
guid |
{id:guid} |
CD2C1638-1638-72D5-1638-DEADBEEF1638 |
Odpovídá platné Guid hodnotě. |
long |
{ticks:long} |
123456789 , -123456789 |
Odpovídá platné long hodnotě. |
minlength(value) |
{username:minlength(4)} |
Rick |
Řetězec musí mít alespoň 4 znaky. |
maxlength(value) |
{filename:maxlength(8)} |
MyFile |
Řetězec nesmí být delší než 8 znaků. |
length(length) |
{filename:length(12)} |
somefile.txt |
Řetězec musí mít přesně 12 znaků. |
length(min,max) |
{filename:length(8,16)} |
somefile.txt |
Řetězec musí mít maximálně 8 znaků a nesmí být delší než 16 znaků. |
min(value) |
{age:min(18)} |
19 |
Celočíselná hodnota musí být alespoň 18. |
max(value) |
{age:max(120)} |
91 |
Celočíselná hodnota nesmí být větší než 120. |
range(min,max) |
{age:range(18,120)} |
91 |
Celočíselná hodnota musí být alespoň 18, ale nesmí být větší než 120. |
alpha |
{name:alpha} |
Rick |
Řetězec musí obsahovat jeden nebo více abecedních znaků a -z a nerozlišuje velká a malá písmena. |
regex(expression) |
{ssn:regex(^\\d{{3}}-\\d{{2}}-\\d{{4}}$)} |
123-45-6789 |
Řetězec musí odpovídat regulárnímu výrazu. Podívejte se na tipy k definování regulárního výrazu. |
required |
{name:required} |
Rick |
Používá se k vynucení toho, aby během generování adresy URL byla přítomna hodnota, která není parametrem. |
Upozorňující
Při zpracování System.Text.RegularExpressions nedůvěryhodného vstupu předejte vypršení časového limitu. Uživatel se zlými úmysly může poskytnout vstup, který RegularExpressions
způsobí útok na dostupnost služby. ASP.NET rozhraní API architektury Core, která používají RegularExpressions
vypršení časového limitu.
Pro jeden parametr lze použít více omezení oddělených dvojtečkami. Například následující omezení omezuje parametr na celočíselnou hodnotu 1 nebo vyšší:
[Route("users/{id:int:min(1)}")]
public User GetUserById(int id) { }
Upozorňující
Omezení směrování, která ověřují adresu URL a jsou převedeny na typ CLR, vždy používají neutrální jazykovou verzi. Například převod na typ int
CLR nebo DateTime
. Tato omezení předpokládají, že adresa URL není lokalizovatelná. Omezení tras poskytovaná architekturou nemění hodnoty uložené v hodnotách tras. Všechny hodnoty směrování parsované z adresy URL se ukládají jako řetězce. Omezení se například pokusí převést hodnotu trasy na hodnotu float, ale převedená hodnota se použije pouze k ověření, float
že se dá převést na plovoucí hodnotu.
Regulární výrazy v omezeních
Upozorňující
Při zpracování System.Text.RegularExpressions nedůvěryhodného vstupu předejte vypršení časového limitu. Uživatel se zlými úmysly může poskytnout vstup, který RegularExpressions
způsobí útok na dostupnost služby. ASP.NET rozhraní API architektury Core, která používají RegularExpressions
vypršení časového limitu.
Regulární výrazy lze zadat jako vložená omezení pomocí regex(...)
omezení trasy. Metody v rodině MapControllerRoute také přijímají literál objektu omezení. Pokud se tento formulář použije, řetězcové hodnoty se interpretují jako regulární výrazy.
Následující kód používá omezení vložených regulárních výrazů:
app.MapGet("{message:regex(^\\d{{3}}-\\d{{2}}-\\d{{4}}$)}",
() => "Inline Regex Constraint Matched");
Následující kód používá literál objektu k určení omezení regulárního výrazu:
app.MapControllerRoute(
name: "people",
pattern: "people/{ssn}",
constraints: new { ssn = "^\\d{3}-\\d{2}-\\d{4}$", },
defaults: new { controller = "People", action = "List" });
Architektura ASP.NET Core přidává RegexOptions.IgnoreCase | RegexOptions.Compiled | RegexOptions.CultureInvariant
do konstruktoru regulárních výrazů. Podívejte RegexOptions se na popis těchto členů.
Regulární výrazy používají oddělovače a tokeny podobné těm používaným směrováním a jazykem C#. Tokeny regulárních výrazů musí být uchycené. Chcete-li použít regulární výraz ^\d{3}-\d{2}-\d{4}$
v vložené omezení, použijte jednu z následujících možností:
- Nahraďte
\
znaky zadané v řetězci jako\\
znaky ve zdrojovém souboru jazyka C#, aby bylo možné řídicí znak řetězce utéct\
. - Doslovné řetězcové literály.
Chcete-li uvozovat znaky {
oddělovače parametrů směrování , [
}
]
zdvojnásobit znaky ve výrazu, {{
například , }}
, , . ]]
[[
Následující tabulka ukazuje regulární výraz a jeho řídicí verzi:
Regulární výraz | Řídicí regulární výraz |
---|---|
^\d{3}-\d{2}-\d{4}$ |
^\\d{{3}}-\\d{{2}}-\\d{{4}}$ |
^[a-z]{2}$ |
^[[a-z]]{{2}}$ |
Regulární výrazy používané při směrování často začínají znakem ^
a odpovídají počáteční pozici řetězce. Výrazy často končí znakem $
a odpovídají konci řetězce. Znaky ^
a $
zajistěte, aby regulární výraz odpovídal celé hodnotě parametru trasy. ^
Bez znaků a $
znaků regulární výraz odpovídá jakémukoli podřetězci v řetězci, což je často nežádoucí. Následující tabulka obsahuje příklady a vysvětluje, proč se shodují nebo se neshodují:
Výraz | String | Párování | Komentář |
---|---|---|---|
[a-z]{2} |
dobrý den | Ano | Shoda podřetěžce |
[a-z]{2} |
123abc456 | Ano | Shoda podřetěžce |
[a-z]{2} |
mz | Ano | Odpovídá výrazu |
[a-z]{2} |
MZ | Ano | Nerozlišuje se malá a velká písmena. |
^[a-z]{2}$ |
dobrý den | No | Viz ^ a $ výše |
^[a-z]{2}$ |
123abc456 | No | Viz ^ a $ výše |
Další informace o syntaxi regulárních výrazů naleznete v tématu Regulární výrazy rozhraní .NET Framework.
Chcete-li omezit parametr na známou sadu možných hodnot, použijte regulární výraz. Například {action:regex(^(list|get|create)$)}
odpovídá pouze hodnotě action
trasy do list
, get
nebo create
. Pokud je řetězec předán do slovníku omezení, je řetězec ^(list|get|create)$
ekvivalentní. Omezení, která se předávají ve slovníku omezení, která neodpovídají některému ze známých omezení, se také považují za regulární výrazy. Omezení předaná v šabloně, která neodpovídají některému ze známých omezení, se považují za regulární výrazy.
Vlastní omezení trasy
Vlastní omezení trasy je možné vytvořit implementací IRouteConstraint rozhraní. Rozhraní IRouteConstraint
obsahuje Match, který vrátí true
, pokud je omezení splněno a false
jinak.
Vlastní omezení trasy jsou zřídka nutná. Před implementací vlastního omezení trasy zvažte alternativy, jako je například vazba modelu.
Složka ASP.NET Core Constraints poskytuje dobré příklady vytváření omezení. Například GuidRouteConstraint.
Pokud chcete použít vlastní IRouteConstraint
typ omezení trasy, musí být zaregistrovaný v kontejneru služby v aplikaci ConstraintMap . A ConstraintMap
je slovník, který mapuje klíče omezení směrování na IRouteConstraint
implementace, které tato omezení ověřují. Aplikaci ConstraintMap
je možné aktualizovat buď Program.cs
v rámci AddRouting hovoru, nebo konfigurací RouteOptions přímo pomocí builder.Services.Configure<RouteOptions>
. Příklad:
builder.Services.AddRouting(options =>
options.ConstraintMap.Add("noZeroes", typeof(NoZeroesRouteConstraint)));
Předchozí omezení se použije v následujícím kódu:
[ApiController]
[Route("api/[controller]")]
public class NoZeroesController : ControllerBase
{
[HttpGet("{id:noZeroes}")]
public IActionResult Get(string id) =>
Content(id);
}
Implementace NoZeroesRouteConstraint
brání 0
použití v parametru trasy:
public class NoZeroesRouteConstraint : IRouteConstraint
{
private static readonly Regex _regex = new(
@"^[1-9]*$",
RegexOptions.CultureInvariant | RegexOptions.IgnoreCase,
TimeSpan.FromMilliseconds(100));
public bool Match(
HttpContext? httpContext, IRouter? route, string routeKey,
RouteValueDictionary values, RouteDirection routeDirection)
{
if (!values.TryGetValue(routeKey, out var routeValue))
{
return false;
}
var routeValueString = Convert.ToString(routeValue, CultureInfo.InvariantCulture);
if (routeValueString is null)
{
return false;
}
return _regex.IsMatch(routeValueString);
}
}
Upozorňující
Při zpracování System.Text.RegularExpressions nedůvěryhodného vstupu předejte vypršení časového limitu. Uživatel se zlými úmysly může poskytnout vstup, který RegularExpressions
způsobí útok na dostupnost služby. ASP.NET rozhraní API architektury Core, která používají RegularExpressions
vypršení časového limitu.
Předchozí kód:
- Zabraňuje
0
v{id}
segmentu trasy. - Ukazuje se, že poskytuje základní příklad implementace vlastního omezení. Neměla by se používat v produkční aplikaci.
Následující kód je lepším přístupem k tomu, aby se zabránilo zpracování obsahujícího id
0
:
[HttpGet("{id}")]
public IActionResult Get(string id)
{
if (id.Contains('0'))
{
return StatusCode(StatusCodes.Status406NotAcceptable);
}
return Content(id);
}
Předchozí kód má oproti přístupu následující výhody NoZeroesRouteConstraint
:
- Nevyžaduje vlastní omezení.
- Vrátí popisnější chybu, pokud parametr trasy obsahuje
0
.
Transformátory parametrů
Transformátory parametrů:
- Spustí se při generování odkazu pomocí LinkGenerator.
- Implementovat Microsoft.AspNetCore.Routing.IOutboundParameterTransformer.
- Jsou nakonfigurovány pomocí ConstraintMap.
- Převezměte hodnotu trasy parametru a transformujte ji na novou řetězcovou hodnotu.
- Výsledkem je použití transformované hodnoty ve vygenerovaném odkazu.
Například vlastní slugify
transformátor parametru ve vzoru blog\{article:slugify}
trasy s Url.Action(new { article = "MyTestArticle" })
vygenerovanými blog\my-test-article
.
Zvažte následující IOutboundParameterTransformer
implementaci:
public class SlugifyParameterTransformer : IOutboundParameterTransformer
{
public string? TransformOutbound(object? value)
{
if (value is null)
{
return null;
}
return Regex.Replace(
value.ToString()!,
"([a-z])([A-Z])",
"$1-$2",
RegexOptions.CultureInvariant,
TimeSpan.FromMilliseconds(100))
.ToLowerInvariant();
}
}
Chcete-li použít transformátor parametrů ve vzoru trasy, nakonfigurujte ho pomocí :ConstraintMap Program.cs
builder.Services.AddRouting(options =>
options.ConstraintMap["slugify"] = typeof(SlugifyParameterTransformer));
Architektura ASP.NET Core používá transformátory parametrů k transformaci identifikátoru URI, kde se koncový bod překládá. Například transformátory parametrů transformují směrovací hodnoty použité ke shodě area
, controller
, action
a page
:
app.MapControllerRoute(
name: "default",
pattern: "{controller:slugify=Home}/{action:slugify=Index}/{id?}");
U předchozí šablony trasy se akce SubscriptionManagementController.GetAll
shoduje s identifikátorem URI /subscription-management/get-all
. Transformátor parametrů nemění směrovací hodnoty použité k vygenerování propojení. Například Url.Action("GetAll", "SubscriptionManagement")
výstupy /subscription-management/get-all
.
ASP.NET Core poskytuje konvence rozhraní API pro použití transformátorů parametrů se generovanými trasami:
- Konvence Microsoft.AspNetCore.Mvc.ApplicationModels.RouteTokenTransformerConvention MVC aplikuje zadaný transformátor parametrů na všechny trasy atributů v aplikaci. Parametr transformer transformuje tokeny směrování atributů při jejich nahrazení. Další informace naleznete v tématu Použití transformátoru parametrů k přizpůsobení nahrazení tokenu.
- Razor Stránky používají PageRouteTransformerConvention konvenci rozhraní API. Tato konvence aplikuje zadaný transformátor parametrů na všechny automaticky zjištěné Razor stránky. Transformátor parametru transformuje segmenty Razor složek a názvů souborů tras Pages. Další informace naleznete v tématu Použití transformátoru parametrů k přizpůsobení tras stránky.
Referenční informace ke generování adres URL
Tato část obsahuje odkaz na algoritmus implementovaný generováním adres URL. V praxi používají nejsložitější příklady generování adres URL kontrolery nebo Razor stránky. Další informace najdete v tématu Směrování v kontrolerů .
Proces generování adresy URL začíná voláním LinkGenerator.GetPathByAddress nebo podobnou metodou. Metoda je poskytována s adresou, sadou hodnot tras a volitelně informace o aktuálním požadavku z HttpContext
.
Prvním krokem je použití adresy k vyřešení sady kandidátských koncových bodů pomocí typu IEndpointAddressScheme<TAddress> adresy.
Jakmile sada kandidátů najde schéma adres, koncové body se objednávají a zpracovávají iterativním způsobem, dokud operace generování adresy URL nebude úspěšná. Generování adresy URL nekontroluje nejednoznačnosti, první vrácený výsledek je konečný výsledek.
Řešení potíží s generováním adres URL pomocí protokolování
Prvním krokem při generování adresy URL při řešení potíží je nastavení úrovně Microsoft.AspNetCore.Routing
protokolování na TRACE
. LinkGenerator
zaznamenává mnoho podrobností o jeho zpracování, které může být užitečné při řešení problémů.
Podrobnosti o generování adres URL najdete v referenčních informacích ke generování adres URL.
Adresy
Adresy jsou konceptem generování adres URL, které slouží k vytvoření vazby volání do generátoru odkazů na sadu kandidátských koncových bodů.
Adresy jsou rozšiřitelný koncept, který ve výchozím nastavení obsahuje dvě implementace:
- Jako adresu použijte název koncového bodu (
string
):- Poskytuje podobné funkce jako název trasy MVC.
- IEndpointNameMetadata Používá typ metadat.
- Vyřeší zadaný řetězec s metadaty všech registrovaných koncových bodů.
- Vyvolá výjimku při spuštění, pokud více koncových bodů používá stejný název.
- Doporučuje se pro obecné použití mimo kontrolery a Razor stránky.
- Použití hodnot směrování (RouteValuesAddress) jako adresy:
- Poskytuje podobné funkce jako kontrolery a Razor starší generace adres URL stránky.
- Velmi složité rozšířit a ladit.
- Poskytuje implementaci, kterou
IUrlHelper
používají pomocné rutiny značek, pomocné rutiny HTML, výsledky akcí atd.
Role schématu adres spočívá v přidružení mezi adresou a odpovídajícími koncovými body podle libovolných kritérií:
- Schéma názvu koncového bodu provádí základní vyhledávání slovníku.
- Schéma hodnot tras má komplexní nejlepší podmnožinu algoritmu sady.
Okolní hodnoty a explicitní hodnoty
Z aktuálního požadavku směrování přistupuje ke směrovacím hodnotám aktuálního požadavku HttpContext.Request.RouteValues
. Hodnoty přidružené k aktuálnímu požadavku se označují jako okolní hodnoty. Pro účely srozumitelnosti se dokumentace týká směrovacích hodnot předávaných metodám jako explicitních hodnot.
Následující příklad ukazuje okolní hodnoty a explicitní hodnoty. Poskytuje okolní hodnoty z aktuálního požadavku a explicitních hodnot:
public class WidgetController : ControllerBase
{
private readonly LinkGenerator _linkGenerator;
public WidgetController(LinkGenerator linkGenerator) =>
_linkGenerator = linkGenerator;
public IActionResult Index()
{
var indexPath = _linkGenerator.GetPathByAction(
HttpContext, values: new { id = 17 })!;
return Content(indexPath);
}
// ...
Předchozí kód:
- Návraty
/Widget/Index/17
- Získá LinkGenerator přes DI.
Následující kód poskytuje pouze explicitní hodnoty a žádné okolní hodnoty:
var subscribePath = _linkGenerator.GetPathByAction(
"Subscribe", "Home", new { id = 17 })!;
Předchozí metoda vrátí /Home/Subscribe/17
Následující kód ve návratu WidgetController
/Widget/Subscribe/17
:
var subscribePath = _linkGenerator.GetPathByAction(
HttpContext, "Subscribe", null, new { id = 17 });
Následující kód poskytuje kontroler z okolních hodnot v aktuálním požadavku a explicitní hodnoty:
public class GadgetController : ControllerBase
{
public IActionResult Index() =>
Content(Url.Action("Edit", new { id = 17 })!);
}
V předchozím kódu:
/Gadget/Edit/17
je vrácena.- UrlIUrlHelperzíská .
- Action vygeneruje adresu URL s absolutní cestou pro metodu akce. Adresa URL obsahuje zadaný
action
název aroute
hodnoty.
Následující kód poskytuje okolní hodnoty z aktuálního požadavku a explicitní hodnoty:
public class IndexModel : PageModel
{
public void OnGet()
{
var editUrl = Url.Page("./Edit", new { id = 17 });
// ...
}
}
Předchozí kód se nastaví url
, když /Edit/17
Edit Razor Page obsahuje následující direktivu stránky:
@page "{id:int}"
Pokud stránka Upravit neobsahuje "{id:int}"
šablonu trasy, url
je /Edit?id=17
.
Chování MVC IUrlHelper přidává kromě zde popsaných pravidel vrstvu složitosti:
IUrlHelper
vždy poskytuje směrovací hodnoty z aktuálního požadavku jako okolní hodnoty.- IUrlHelper.Action vždy zkopíruje aktuální
action
hodnoty acontroller
směrovací hodnoty jako explicitní hodnoty, pokud je nepřepíše vývojář. - IUrlHelper.Page vždy zkopíruje aktuální
page
hodnotu trasy jako explicitní hodnotu, pokud ji nepřepíšete. IUrlHelper.Page
vždy přepíše aktuálníhandler
hodnotunull
trasy jako explicitní hodnoty, pokud ji nepřepíšete.
Uživatelé jsou často překvapeni chováním okolních hodnot, protože MVC zdánlivě nedodržuje vlastní pravidla. Z historických důvodů a z důvodu kompatibility mají určité hodnoty tras, jako action
je , controller
, page
a handler
mají vlastní zvláštní chování.
Ekvivalentní funkce poskytované LinkGenerator.GetPathByAction
a LinkGenerator.GetPathByPage
duplikuje tyto anomálie z důvodu kompatibility IUrlHelper
.
Proces generování adres URL
Jakmile se najde sada kandidátských koncových bodů, algoritmus generování adres URL:
- Zpracovává koncové body iterativním způsobem.
- Vrátí první úspěšný výsledek.
Prvním krokem v tomto procesu je zneplatnění hodnoty trasy. Zneplatnění hodnoty trasy je proces, kterým směrování rozhodne, které hodnoty trasy z okolních hodnot se mají použít a které by se měly ignorovat. Každá okolní hodnota se považuje a buď v kombinaci s explicitními hodnotami, nebo je ignorována.
Nejlepším způsobem, jak přemýšlet o roli okolních hodnot, je, že se snaží uložit vývojáři aplikací psaní, v některých běžných případech. Scénáře, ve kterých jsou okolní hodnoty užitečné, se tradičně vztahují k MVC:
- Při propojení s jinou akcí ve stejném řadiči není nutné zadat název kontroleru.
- Při propojení s jiným řadičem ve stejné oblasti není nutné zadat název oblasti.
- Při propojení se stejnou metodou akce není nutné zadávat hodnoty tras.
- Při propojení s jinou částí aplikace nechcete přenášet hodnoty tras, které nemají v této části aplikace žádný význam.
Volání nebo LinkGenerator
IUrlHelper
vrácení jsou obvykle způsobená tím, že null
nerozumí neplatné hodnotě trasy. Při řešení potíží s neplatnou hodnotou trasy můžete explicitně zadat více hodnot tras, abyste zjistili, jestli se tím problém vyřeší.
Neplatná hodnota trasy funguje na předpokladu, že schéma adresy URL aplikace je hierarchické s hierarchií vytvořenou zleva doprava. Představte si šablonu {controller}/{action}/{id?}
směrování základního kontroleru, abyste získali intuitivní představu o tom, jak to funguje v praxi. Změna hodnoty zneplatní všechny směrovací hodnoty, které se zobrazují vpravo. To odráží předpoklad o hierarchii. Pokud má aplikace okolní hodnotu a id
operace určuje jinou hodnotu pro controller
:
id
nebude znovu použito, protože{controller}
je nalevo od{id?}
.
Několik příkladů demonstrujících tento princip:
- Pokud explicitní hodnoty obsahují hodnotu pro
id
, okolní hodnota jeid
ignorována. Okolní hodnoty acontroller
action
lze je použít. - Pokud explicitní hodnoty obsahují hodnotu pro
action
, je ignorována jakákoli okolní hodnota proaction
. Lze použít okolní hodnotycontroller
. Pokud se explicitní hodnota pro jinou než okolní hodnotaaction
action
pro ,id
hodnota se nepoužije. Pokud je explicitní hodnotaaction
stejná jako okolní hodnota proaction
,id
lze použít hodnotu. - Pokud explicitní hodnoty obsahují hodnotu pro
controller
, je ignorována jakákoli okolní hodnota procontroller
. Pokud se explicitní hodnota pro jinou než okolní hodnotacontroller
controller
pro ,action
hodnoty aid
hodnoty nebudou použity. Pokud je explicitní hodnotacontroller
stejná jako okolní hodnota procontroller
,action
lze použít hodnoty aid
hodnoty.
Tento proces je ještě složitější díky existenci tras atributů a vyhrazených konvenčních tras. Běžné trasy kontroleru, jako {controller}/{action}/{id?}
je například určení hierarchie pomocí parametrů trasy. Pro vyhrazené konvenční trasy a trasy atributů pro kontrolery a Razor stránky:
- Existuje hierarchie hodnot tras.
- Nezobrazují se v šabloně.
V těchto případech generování adresy URL definuje koncept požadovaných hodnot . Koncové body vytvořené kontrolery a Razor stránkami mají zadané požadované hodnoty, které umožňují zneplatnění hodnoty trasy.
Podrobný algoritmus zneplatnění hodnoty trasy:
- Požadované názvy hodnot se kombinují s parametry trasy a pak se zpracovávají zleva doprava.
- Pro každý parametr se porovná okolní hodnota a explicitní hodnota:
- Pokud je okolní hodnota a explicitní hodnota stejné, proces pokračuje.
- Pokud je okolní hodnota přítomná a explicitní hodnota není, použije se při generování adresy URL okolní hodnota.
- Pokud okolní hodnota není přítomná a explicitní hodnota je, zamítněte okolní hodnotu a všechny následné okolní hodnoty.
- Pokud se nachází okolí a explicitní hodnota a obě hodnoty jsou odlišné, zamítněte okolní hodnotu a všechny následné okolní hodnoty.
V tuto chvíli je operace generování adres URL připravená k vyhodnocení omezení trasy. Sada přijatých hodnot se zkombinuje s výchozími hodnotami parametrů, které jsou k dispozici pro omezení. Pokud všechna omezení projdou, operace bude pokračovat.
Dále je možné použít akceptované hodnoty k rozšíření šablony trasy. Šablona trasy se zpracuje:
- Zleva doprava.
- Každý parametr má jeho přijatou hodnotu nahrazenou.
- S následujícími zvláštními případy:
- Pokud přijaté hodnoty chybí hodnota a parametr má výchozí hodnotu, použije se výchozí hodnota.
- Pokud přijaté hodnoty chybí a parametr je nepovinný, zpracování pokračuje.
- Pokud některý parametr trasy napravo od chybějícího volitelného parametru má hodnotu, operace selže.
- Pokud je to možné, sbalí se souvislé parametry s výchozími hodnotami a volitelné parametry.
Hodnoty explicitně za předpokladu, že neodpovídají segmentu trasy, se přidají do řetězce dotazu. Následující tabulka ukazuje výsledek při použití šablony {controller}/{action}/{id?}
trasy .
Okolní hodnoty | Explicitní hodnoty | Výsledek |
---|---|---|
controller = "Home" | action = "O aplikaci" | /Home/About |
controller = "Home" | controller = "Order", action = "About" | /Order/About |
controller = "Home", color = "Red" | action = "O aplikaci" | /Home/About |
controller = "Home" | action = "O produktu", barva = "Červená" | /Home/About?color=Red |
Volitelné pořadí parametrů trasy
Volitelné parametry trasy musí pocházet po všech požadovaných parametrech trasy. V následujícím kódu id
name
musí parametry pocházet za parametrem color
:
using Microsoft.AspNetCore.Mvc;
namespace WebApplication1.Controllers;
[Route("api/[controller]")]
public class MyController : ControllerBase
{
// GET /api/my/red/2/joe
// GET /api/my/red/2
// GET /api/my
[HttpGet("{color}/{id:int?}/{name?}")]
public IActionResult GetByIdAndOptionalName(string color, int id = 1, string? name = null)
{
return Ok($"{color} {id} {name ?? ""}");
}
}
Problémy s neplatnou hodnotou trasy
Následující kód ukazuje příklad schématu generování adres URL, které není podporováno směrováním:
app.MapControllerRoute(
"default",
"{culture}/{controller=Home}/{action=Index}/{id?}");
app.MapControllerRoute(
"blog",
"{culture}/{**slug}",
new { controller = "Blog", action = "ReadPost" });
V předchozím kódu culture
se parametr trasy používá pro lokalizaci. Touha má parametr culture
vždy přijmout jako okolní hodnotu. Parametr culture
však není přijat jako okolní hodnota kvůli způsobu, jakým požadované hodnoty fungují:
"default"
V šabloněculture
trasy je parametr trasy vlevo odcontroller
, takže změnycontroller
nebudouculture
neplatné ."blog"
V šabloněculture
trasy se parametr trasy považuje za napravo odcontroller
parametru trasy, který se zobrazí v požadovaných hodnotách.
Parsování cest URL pomocí LinkParser
Třída LinkParser přidává podporu analýzy cesty URL do sady hodnot tras. Metoda ParsePathByEndpointName přebírá název koncového bodu a cestu URL a vrátí sadu hodnot tras extrahovaných z cesty URL.
V následujícím příkladu kontroler akce GetProduct
používá šablonu api/Products/{id}
trasy a má Name :GetProduct
[ApiController]
[Route("api/[controller]")]
public class ProductsController : ControllerBase
{
[HttpGet("{id}", Name = nameof(GetProduct))]
public IActionResult GetProduct(string id)
{
// ...
Ve stejné třídě AddRelatedProduct
kontroleru akce očekává cestu URL, pathToRelatedProduct
kterou lze poskytnout jako parametr řetězce dotazu:
[HttpPost("{id}/Related")]
public IActionResult AddRelatedProduct(
string id, string pathToRelatedProduct, [FromServices] LinkParser linkParser)
{
var routeValues = linkParser.ParsePathByEndpointName(
nameof(GetProduct), pathToRelatedProduct);
var relatedProductId = routeValues?["id"];
// ...
V předchozím příkladu AddRelatedProduct
akce extrahuje id
hodnotu trasy z cesty URL. Například s cestou /api/Products/1
URL , relatedProductId
hodnota je nastavena na 1
. Tento přístup umožňuje klientům rozhraní API používat cesty url při odkazování na prostředky, aniž by museli vědět, jak je taková adresa URL strukturovaná.
Konfigurace metadat koncového bodu
Následující odkazy obsahují informace o konfiguraci metadat koncového bodu:
- Povolení Cors se směrováním koncových bodů
- Ukázka IAuthorizationPolicyProvider pomocí vlastního
[MinimumAgeAuthorize]
atributu - Testování ověřování pomocí atributu [Authorize]
- RequireAuthorization
- Výběr schématu s atributem [Authorize]
- Použití zásad pomocí atributu [Authorize]
- Autorizace na základě rolí v ASP.NET Core
Porovnávání hostitelů v trasách pomocí RequireHost
RequireHost použije omezení na trasu, která vyžaduje zadaného hostitele. Parametrem RequireHost
[Host] může být:
- Hostitel:
www.domain.com
, odpovídáwww.domain.com
libovolnému portu. - Hostitel se zástupným znakem:
*.domain.com
, shodywww.domain.com
,subdomain.domain.com
nebowww.subdomain.domain.com
na libovolném portu. - Port:
*:5000
Odpovídá portu 5000 s libovolným hostitelem. - Hostitel a port:
www.domain.com:5000
nebo*.domain.com:5000
odpovídá hostiteli a portu.
Lze zadat více parametrů pomocí RequireHost
nebo [Host]
. Omezení odpovídá hostitelům platným pro některý z parametrů. Například [Host("domain.com", "*.domain.com")]
shody domain.com
, www.domain.com
a subdomain.domain.com
.
Následující kód používá RequireHost
k vyžadování zadaného hostitele na trase:
app.MapGet("/", () => "Contoso").RequireHost("contoso.com");
app.MapGet("/", () => "AdventureWorks").RequireHost("adventure-works.com");
app.MapHealthChecks("/healthz").RequireHost("*:8080");
Následující kód používá [Host]
atribut na kontroleru k vyžadování některého ze zadaných hostitelů:
[Host("contoso.com", "adventure-works.com")]
public class HostsController : Controller
{
public IActionResult Index() =>
View();
[Host("example.com")]
public IActionResult Example() =>
View();
}
[Host]
Když se atribut použije na metodu kontroleru i akce:
- Použije se atribut akce.
- Atribut kontroleru je ignorován.
Skupiny tras
Metoda MapGroup rozšíření pomáhá uspořádat skupiny koncových bodů s běžnou předponou. Snižuje opakující se kód a umožňuje přizpůsobit celé skupiny koncových bodů jediným voláním metod, jako RequireAuthorization jsou a WithMetadata které přidávají metadata koncového bodu.
Například následující kód vytvoří dvě podobné skupiny koncových bodů:
app.MapGroup("/public/todos")
.MapTodosApi()
.WithTags("Public");
app.MapGroup("/private/todos")
.MapTodosApi()
.WithTags("Private")
.AddEndpointFilterFactory(QueryPrivateTodos)
.RequireAuthorization();
EndpointFilterDelegate QueryPrivateTodos(EndpointFilterFactoryContext factoryContext, EndpointFilterDelegate next)
{
var dbContextIndex = -1;
foreach (var argument in factoryContext.MethodInfo.GetParameters())
{
if (argument.ParameterType == typeof(TodoDb))
{
dbContextIndex = argument.Position;
break;
}
}
// Skip filter if the method doesn't have a TodoDb parameter.
if (dbContextIndex < 0)
{
return next;
}
return async invocationContext =>
{
var dbContext = invocationContext.GetArgument<TodoDb>(dbContextIndex);
dbContext.IsPrivate = true;
try
{
return await next(invocationContext);
}
finally
{
// This should only be relevant if you're pooling or otherwise reusing the DbContext instance.
dbContext.IsPrivate = false;
}
};
}
public static RouteGroupBuilder MapTodosApi(this RouteGroupBuilder group)
{
group.MapGet("/", GetAllTodos);
group.MapGet("/{id}", GetTodo);
group.MapPost("/", CreateTodo);
group.MapPut("/{id}", UpdateTodo);
group.MapDelete("/{id}", DeleteTodo);
return group;
}
V tomto scénáři můžete použít relativní adresu hlavičky Location
ve výsledku 201 Created
:
public static async Task<Created<Todo>> CreateTodo(Todo todo, TodoDb database)
{
await database.AddAsync(todo);
await database.SaveChangesAsync();
return TypedResults.Created($"{todo.Id}", todo);
}
První skupina koncových bodů se bude shodovat pouze s požadavky s předponou /public/todos
a jsou přístupná bez ověřování. Druhá skupina koncových bodů bude odpovídat pouze požadavkům s předponou /private/todos
a vyžaduje ověření.
Objekt QueryPrivateTodos
pro filtrování koncových bodů je místní funkce, která upravuje parametry obslužné rutiny TodoDb
trasy tak, aby umožňovala přístup k privátním datům úkolů a jejich ukládání.
Skupiny tras také podporují vnořené skupiny a složité vzory předpon s parametry trasy a omezeními. V následujícím příkladu a obslužná rutina trasy namapovaná na user
skupinu může zachytit {org}
parametry a {group}
parametry trasy definované v předponách vnější skupiny.
Předpona může být také prázdná. To může být užitečné pro přidání metadat koncového bodu nebo filtrů do skupiny koncových bodů beze změny vzoru trasy.
var all = app.MapGroup("").WithOpenApi();
var org = all.MapGroup("{org}");
var user = org.MapGroup("{user}");
user.MapGet("", (string org, string user) => $"{org}/{user}");
Přidání filtrů nebo metadat do skupiny se chová stejně jako jejich individuální přidání do každého koncového bodu před přidáním dalších filtrů nebo metadat, které mohly být přidány do vnitřní skupiny nebo konkrétního koncového bodu.
var outer = app.MapGroup("/outer");
var inner = outer.MapGroup("/inner");
inner.AddEndpointFilter((context, next) =>
{
app.Logger.LogInformation("/inner group filter");
return next(context);
});
outer.AddEndpointFilter((context, next) =>
{
app.Logger.LogInformation("/outer group filter");
return next(context);
});
inner.MapGet("/", () => "Hi!").AddEndpointFilter((context, next) =>
{
app.Logger.LogInformation("MapGet filter");
return next(context);
});
V předchozím příkladu vnější filtr zapíše příchozí požadavek před vnitřním filtrem, i když byl přidán druhý. Vzhledem k tomu, že filtry byly použity u různých skupin, pořadí, které byly přidány vzhledem k sobě, nezáleží. Přidají se filtry objednávek bez ohledu na to, jestli se použije na stejnou skupinu nebo konkrétní koncový bod.
Žádost o /outer/inner/
protokolování bude následující:
/outer group filter
/inner group filter
MapGet filter
Doprovodné materiály k výkonu pro směrování
Pokud má aplikace problémy s výkonem, směrování se často považuje za problém. Důvodem je podezření, že architektury, jako jsou kontrolery a Razor stránky, hlásí dobu strávenou uvnitř rozhraní v protokolovacích zprávách. Pokud je mezi časem hlášeným kontrolery a celkovým časem požadavku významný rozdíl:
- Vývojáři eliminují kód aplikace jako zdroj problému.
- Běžně se předpokládá, že příčinou je směrování.
Směrování je testované výkonem pomocí tisíců koncových bodů. Je nepravděpodobné, že by typická aplikace narazila na problém s výkonem jenom tím, že je příliš velká. Nejčastější hlavní příčinou pomalého směrování je obvykle špatně se chovající vlastní middleware.
Následující ukázka kódu ukazuje základní techniku zúžení zdroje zpoždění:
var logger = app.Services.GetRequiredService<ILogger<Program>>();
app.Use(async (context, next) =>
{
var stopwatch = Stopwatch.StartNew();
await next(context);
stopwatch.Stop();
logger.LogInformation("Time 1: {ElapsedMilliseconds}ms", stopwatch.ElapsedMilliseconds);
});
app.UseRouting();
app.Use(async (context, next) =>
{
var stopwatch = Stopwatch.StartNew();
await next(context);
stopwatch.Stop();
logger.LogInformation("Time 2: {ElapsedMilliseconds}ms", stopwatch.ElapsedMilliseconds);
});
app.UseAuthorization();
app.Use(async (context, next) =>
{
var stopwatch = Stopwatch.StartNew();
await next(context);
stopwatch.Stop();
logger.LogInformation("Time 3: {ElapsedMilliseconds}ms", stopwatch.ElapsedMilliseconds);
});
app.MapGet("/", () => "Timing Test.");
Směrování podle času:
- Prokládání každého middlewaru pomocí kopie middlewaru časování zobrazeného v předchozím kódu.
- Přidejte jedinečný identifikátor pro korelaci dat časování s kódem.
Jedná se o základní způsob, jak zúžit zpoždění, pokud je významné, například více než 10ms
. Odečítá Time 2
se od Time 1
sestav čas strávený v middlewaru UseRouting
.
Následující kód používá kompaktnější přístup k předchozímu kódu časování:
public sealed class AutoStopwatch : IDisposable
{
private readonly ILogger _logger;
private readonly string _message;
private readonly Stopwatch _stopwatch;
private bool _disposed;
public AutoStopwatch(ILogger logger, string message) =>
(_logger, _message, _stopwatch) = (logger, message, Stopwatch.StartNew());
public void Dispose()
{
if (_disposed)
{
return;
}
_logger.LogInformation("{Message}: {ElapsedMilliseconds}ms",
_message, _stopwatch.ElapsedMilliseconds);
_disposed = true;
}
}
var logger = app.Services.GetRequiredService<ILogger<Program>>();
var timerCount = 0;
app.Use(async (context, next) =>
{
using (new AutoStopwatch(logger, $"Time {++timerCount}"))
{
await next(context);
}
});
app.UseRouting();
app.Use(async (context, next) =>
{
using (new AutoStopwatch(logger, $"Time {++timerCount}"))
{
await next(context);
}
});
app.UseAuthorization();
app.Use(async (context, next) =>
{
using (new AutoStopwatch(logger, $"Time {++timerCount}"))
{
await next(context);
}
});
app.MapGet("/", () => "Timing Test.");
Potenciálně nákladné funkce směrování
Následující seznam obsahuje přehled o funkcích směrování, které jsou relativně drahé v porovnání se základními šablonami tras:
- Regulární výrazy: Je možné psát regulární výrazy, které jsou složité nebo mají dlouhou dobu trvání s malým množstvím vstupu.
- Komplexní segmenty (
{x}-{y}-{z}
):- Jsou výrazně dražší než analýza běžného segmentu cesty URL.
- Výsledkem je přidělení mnoha dalších podřetěžců.
- Synchronní přístup k datům: Mnoho složitých aplikací má v rámci směrování přístup k databázi. Použijte body rozšiřitelnosti, například MatcherPolicy a EndpointSelectorContext, které jsou asynchronní.
Pokyny pro velké směrovací tabulky
Ve výchozím nastavení ASP.NET Core používá algoritmus směrování, který obchoduje s pamětí za čas procesoru. To má pěkný účinek, že čas porovnávání tras závisí pouze na délce cesty, která se má shodovat, a ne na počtu tras. Tento přístup ale může být v některých případech problematický, když má aplikace velký počet tras (v tisících) a v trasách existuje velké množství předpon proměnných. Například pokud trasy mají parametry v počátečních segmentech trasy, například {parameter}/some/literal
.
Je nepravděpodobné, že by aplikace narazila na situaci, kdy se jedná o problém, pokud:
- V aplikaci existuje velký počet tras, které tento model používají.
- V aplikaci je velký počet tras.
Jak zjistit, jestli aplikace narazí na problém s velkou směrovací tabulkou
- Existují dva příznaky, které je třeba hledat:
- Aplikace se pomalu spustí při prvním požadavku.
- Mějte na paměti, že je to povinné, ale nestačí. Existuje mnoho dalších problémů, které se nesměrují, než může způsobit pomalé spuštění aplikace. Zkontrolujte níže uvedený stav, abyste přesně zjistili, jestli aplikace v této situaci neběží.
- Aplikace během spouštění spotřebovává velké množství paměti a výpis paměti zobrazuje velký počet
Microsoft.AspNetCore.Routing.Matching.DfaNode
instancí.
- Aplikace se pomalu spustí při prvním požadavku.
Jak tento problém vyřešit
U tras lze použít několik technik a optimalizací, které tento scénář z velké části zlepší:
- Pokud je to možné, použijte omezení trasy na parametry, například
{parameter:int}
{parameter:guid}
,{parameter:regex(\\d+)}
, atd.- To umožňuje algoritmus směrování interně optimalizovat struktury používané pro porovnávání a výrazně snížit využitou paměť.
- Ve většině případů to stačí, abyste se vrátili k přijatelnému chování.
- Změňte trasy tak, aby se parametry přesunuly do pozdějších segmentů v šabloně.
- Tím se sníží počet možných cest tak, aby odpovídal koncovému bodu dané cestě.
- Použijte dynamickou trasu a dynamicky proveďte mapování na kontroler nebo stránku.
- Toho lze dosáhnout pomocí
MapDynamicControllerRoute
aMapDynamicPageRoute
.
- Toho lze dosáhnout pomocí
Pokyny pro autory knihoven
Tato část obsahuje pokyny pro autory knihoven, kteří vycházejí ze směrování. Cílem těchto podrobností je zajistit, aby vývojáři aplikací měli dobré zkušenosti s používáním knihoven a architektur, které rozšiřují směrování.
Definování koncových bodů
Pokud chcete vytvořit architekturu, která používá směrování pro porovnávání adres URL, začněte definováním uživatelského prostředí, které je postavené na UseEndpoints.
DO staví na vrcholu IEndpointRouteBuilder. To umožňuje uživatelům vytvářet architekturu s jinými funkcemi ASP.NET Core bez nejasností. Každá šablona ASP.NET Core zahrnuje směrování. Předpokládejme, že směrování je pro uživatele k dispozici a známé.
// Your framework
app.MapMyFramework(...);
app.MapHealthChecks("/healthz");
DO vrátit zapečetěný beton typ z volání MapMyFramework(...)
, které implementuje IEndpointConventionBuilder. Většina metod architektury Map...
tento vzor dodržuje. Rozhraní IEndpointConventionBuilder
:
- Umožňuje složená metadata.
- Cílí na různé rozšiřující metody.
Deklarování vlastního typu umožňuje do tvůrce přidat vlastní funkce specifické pro architekturu. Je v pořádku zabalit tvůrce deklarovaného architekturou a předat do něj volání.
// Your framework
app.MapMyFramework(...)
.RequireAuthorization()
.WithMyFrameworkFeature(awesome: true);
app.MapHealthChecks("/healthz");
ZVAŽTE psaní vlastního EndpointDataSource. EndpointDataSource
je primitivní úroveň nízké úrovně pro deklarování a aktualizaci kolekce koncových bodů. EndpointDataSource
je výkonné rozhraní API používané kontrolery a Razor stránkami.
Testy směrování mají základní příklad neaktualizuje zdroje dat.
ZVAŽTE implementaci GetGroupedEndpoints. Tím získáte úplnou kontrolu nad spouštěním konvencí skupin a konečnými metadaty ve seskupených koncových bodech. To například umožňuje vlastní EndpointDataSource
implementaci spouštět filtry koncových bodů přidané do skupin.
VE výchozím nastavení se nepokoušejte EndpointDataSource
o registraci. Vyžadovat, aby uživatelé zaregistrovali vaši architekturu v UseEndpoints. Filozofie směrování spočívá v tom, že ve výchozím nastavení se nic nezahrnuje a je to UseEndpoints
místo pro registraci koncových bodů.
Vytvoření middlewaru integrovaného se směrováním
ZVAŽTE definování typů metadat jako rozhraní.
Umožňuje použít typy metadat jako atribut tříd a metod.
public interface ICoolMetadata
{
bool IsCool { get; }
}
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
public class CoolMetadataAttribute : Attribute, ICoolMetadata
{
public bool IsCool => true;
}
Architektury, jako jsou kontrolery a Razor stránky, podporují použití atributů metadat na typy a metody. Pokud deklarujete typy metadat:
- Zpřístupní je jako atributy.
- Většina uživatelů má zkušenosti s používáním atributů.
Deklarace typu metadat jako rozhraní přidává další vrstvu flexibility:
- Rozhraní jsou kompozibilní.
- Vývojáři můžou deklarovat své vlastní typy, které kombinují více zásad.
Umožňuje přepsat metadata, jak je znázorněno v následujícím příkladu:
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
public class SuppressCoolMetadataAttribute : Attribute, ICoolMetadata
{
public bool IsCool => false;
}
[CoolMetadata]
public class MyController : Controller
{
public void MyCool() { }
[SuppressCoolMetadata]
public void Uncool() { }
}
Nejlepší způsob, jak postupovat podle těchto pokynů, je vyhnout se definování metadat značek:
- Nehledáte jenom přítomnost typu metadat.
- Definujte vlastnost metadat a zkontrolujte vlastnost.
Kolekce metadat je seřazená a podporuje přepsání podle priority. V případě kontrolerů jsou metadata pro metodu akce nejvýraznější.
Do make middleware užitečný s a bez směrování:
app.UseAuthorization(new AuthorizationPolicy() { ... });
// Your framework
app.MapMyFramework(...).RequireAuthorization();
Jako příklad tohoto návodu UseAuthorization
zvažte middleware. Middleware pro autorizaci umožňuje předávat záložní zásady. Záložní zásada, pokud je zadaná, platí pro obě:
- Koncové body bez zadané zásady
- Požadavky, které neodpovídají koncovému bodu.
Díky tomu je middleware autorizace užitečný mimo kontext směrování. Autorizační middleware lze použít pro tradiční programování middlewaru.
Ladění diagnostiky
Podrobný výstup diagnostiky směrování nastavíte Logging:LogLevel:Microsoft
na Debug
hodnotu . Ve vývojovém prostředí nastavte úroveň protokolu v appsettings.Development.json
:
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Debug",
"Microsoft.Hosting.Lifetime": "Information"
}
}
}
Další materiály
Směrování zodpovídá za porovnávání příchozích požadavků HTTP a odesílání těchto požadavků do spustitelných koncových bodů aplikace. Koncové body jsou jednotky spustitelného kódu zpracování požadavků. Koncové body se definují v aplikaci a konfigurují se při spuštění aplikace. Proces porovnávání koncových bodů může extrahovat hodnoty z adresy URL požadavku a poskytnout tyto hodnoty pro zpracování požadavků. Pomocí informací o koncovém bodu z aplikace je směrování také schopné generovat adresy URL, které se mapují na koncové body.
Aplikace můžou nakonfigurovat směrování pomocí:
- Kontrolery
- Razor Pages
- SignalR
- gRPC Services
- Middleware s povoleným koncovým bodem, jako jsou kontroly stavu.
- Delegáti a lambda zaregistrované ve směrování
Tento článek se zabývá podrobnostmi nízké úrovně směrování ASP.NET Core. Informace o konfiguraci směrování:
- Informace o kontroleru najdete v tématu Směrování na akce kontroleru v ASP.NET Core.
- Konvence Razor stránek najdete v tématu Razor Stránky trasy a konvence aplikací v ASP.NET Core.
Základy směrování
Následující kód ukazuje základní příklad směrování:
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
app.MapGet("/", () => "Hello World!");
app.Run();
Předchozí příklad obsahuje jeden koncový bod pomocí MapGet metody:
- Při odeslání požadavku HTTP
GET
na kořenovou adresu URL/
:- Delegát požadavku se spustí.
Hello World!
je zapsán do odpovědi HTTP.
- Pokud metoda požadavku není
GET
nebo kořenová adresa URL není/
, žádná trasa neodpovídá a vrátí se http 404.
Směrování používá dvojici middlewaru, zaregistrovaného uživatelem UseRouting a UseEndpoints:
UseRouting
přidá trasu odpovídající kanálu middlewaru. Tento middleware se podívá na sadu koncových bodů definovaných v aplikaci a vybere nejlepší shodu na základě požadavku.UseEndpoints
přidá spuštění koncového bodu do kanálu middlewaru. Spustí delegáta přidruženého k vybranému koncovému bodu.
Aplikace obvykle nemusí volat UseRouting
ani UseEndpoints
. WebApplicationBuilder konfiguruje middlewarový kanál, který zabalí middleware přidaný do Program.cs
UseRouting
a UseEndpoints
. Aplikace ale můžou změnit pořadí, ve kterém UseRouting
se budou spouštět, UseEndpoints
a to explicitním voláním těchto metod. Například následující kód provede explicitní volání UseRouting
:
app.Use(async (context, next) =>
{
// ...
await next(context);
});
app.UseRouting();
app.MapGet("/", () => "Hello World!");
V předchozím kódu:
- Volání pro
app.Use
registraci vlastního middlewaru, který se spouští na začátku kanálu. - Volání konfiguruje
UseRouting
middleware odpovídající směrování tak, aby se spustil po vlastním middlewaru. - Koncový bod zaregistrovaný na
MapGet
konci kanálu se spustí.
Pokud by předchozí příklad nezahrnoval volání UseRouting
, vlastní middleware by se spustil za middlewarem odpovídajícím trasě.
Koncové body
Metoda MapGet
se používá k definování koncového bodu. Koncový bod je něco, co může být:
- Vybráno tak, že se shoduje s adresou URL a metodou HTTP.
- Spustí se spuštěním delegáta.
Koncové body, které se dají spárovat a spouštět aplikací, jsou nakonfigurované v UseEndpoints
. Například MapGet, MapPosta podobné metody připojit žádosti delegáty do systému směrování. Další metody lze použít k připojení funkcí architektury ASP.NET Core ke směrovacímu systému:
- MapRazorPages for Razor Pages
- MapControllers pro kontrolery
- MapHub THub<> forSignalR
- MapGrpcService TService<> pro gRPC
Následující příklad ukazuje směrování s sofistikovanější šablonou trasy:
app.MapGet("/hello/{name:alpha}", (string name) => $"Hello {name}!");
Řetězec /hello/{name:alpha}
je šablona trasy. Ke konfiguraci shody koncového bodu se používá šablona trasy. V tomto případě šablona odpovídá:
- Adresa URL, jako je
/hello/Docs
- Všechny cesty URL, které začínají
/hello/
posloupností abecedních znaků.:alpha
použije omezení trasy, které odpovídá pouze abecedním znakům. Omezení tras jsou vysvětlena dále v tomto článku.
Druhý segment cesty URL: {name:alpha}
- Je vázán na
name
parametr. - Je zachycen a uložen v HttpRequest.RouteValues.
Následující příklad ukazuje směrování s kontrolami stavu a autorizací:
app.UseAuthentication();
app.UseAuthorization();
app.MapHealthChecks("/healthz").RequireAuthorization();
app.MapGet("/", () => "Hello World!");
Předchozí příklad ukazuje, jak:
- S směrováním je možné použít autorizační middleware.
- Koncové body je možné použít ke konfiguraci chování autorizace.
Volání MapHealthChecks přidá koncový bod kontroly stavu. Při zřetězování RequireAuthorization k tomuto volání se ke koncovému bodu připojí zásady autorizace.
Volání UseAuthentication a UseAuthorization přidání middlewaru pro ověřování a autorizaci Tyto middleware jsou umístěny mezi UseRouting a UseEndpoints
tak, aby mohly:
- Podívejte se, který koncový bod vybral
UseRouting
. - Před odesláním do koncového bodu použijte zásadu UseEndpoints autorizace.
Metadata koncového bodu
V předchozím příkladu existují dva koncové body, ale k autorizační zásadě jsou připojené jenom koncové body kontroly stavu. Pokud požadavek odpovídá koncovému bodu kontroly stavu, /healthz
provede se kontrola autorizace. To ukazuje, že koncové body můžou mít připojená další data. Tato další data se nazývají metadata koncového bodu:
- Metadata je možné zpracovat pomocí middlewaru pracujícího se směrováním.
- Metadata můžou být libovolného typu .NET.
Koncepty směrování
Systém směrování vychází z kanálu middlewaru přidáním výkonného konceptu koncového bodu . Koncové body představují jednotky funkcí aplikace, které se vzájemně liší z hlediska směrování, autorizace a libovolného počtu systémů ASP.NET Core.
Definice koncového bodu ASP.NET Core
Koncový bod ASP.NET Core je:
- Spustitelný soubor: Má .RequestDelegate
- Rozšiřitelný: Má kolekci metadat .
- Možnost výběru: Volitelně obsahuje informace o směrování.
- Výčet: Kolekci koncových bodů je možné uvést načtením EndpointDataSource z DI.
Následující kód ukazuje, jak načíst a zkontrolovat koncový bod odpovídající aktuálnímu požadavku:
app.Use(async (context, next) =>
{
var currentEndpoint = context.GetEndpoint();
if (currentEndpoint is null)
{
await next(context);
return;
}
Console.WriteLine($"Endpoint: {currentEndpoint.DisplayName}");
if (currentEndpoint is RouteEndpoint routeEndpoint)
{
Console.WriteLine($" - Route Pattern: {routeEndpoint.RoutePattern}");
}
foreach (var endpointMetadata in currentEndpoint.Metadata)
{
Console.WriteLine($" - Metadata: {endpointMetadata}");
}
await next(context);
});
app.MapGet("/", () => "Inspect Endpoint.");
Koncový bod, pokud je vybraný, lze načíst z objektu HttpContext
. Jeho vlastnosti je možné zkontrolovat. Objekty koncového bodu jsou neměnné a po vytvoření není možné je změnit. Nejběžnějším typem RouteEndpointkoncového bodu je . RouteEndpoint
obsahuje informace, které mu umožní vybrat směrovací systém.
V předchozím kódu aplikace. Slouží ke konfiguraci vloženého middlewaru.
Následující kód ukazuje, že v závislosti na tom, kde app.Use
se v kanálu volá, nemusí existovat koncový bod:
// Location 1: before routing runs, endpoint is always null here.
app.Use(async (context, next) =>
{
Console.WriteLine($"1. Endpoint: {context.GetEndpoint()?.DisplayName ?? "(null)"}");
await next(context);
});
app.UseRouting();
// Location 2: after routing runs, endpoint will be non-null if routing found a match.
app.Use(async (context, next) =>
{
Console.WriteLine($"2. Endpoint: {context.GetEndpoint()?.DisplayName ?? "(null)"}");
await next(context);
});
// Location 3: runs when this endpoint matches
app.MapGet("/", (HttpContext context) =>
{
Console.WriteLine($"3. Endpoint: {context.GetEndpoint()?.DisplayName ?? "(null)"}");
return "Hello World!";
}).WithDisplayName("Hello");
app.UseEndpoints(_ => { });
// Location 4: runs after UseEndpoints - will only run if there was no match.
app.Use(async (context, next) =>
{
Console.WriteLine($"4. Endpoint: {context.GetEndpoint()?.DisplayName ?? "(null)"}");
await next(context);
});
Předchozí ukázka přidá Console.WriteLine
příkazy, které zobrazují, jestli byl vybrán koncový bod nebo ne. Pro přehlednost ukázka přiřadí zadaný koncový bod zobrazovaný název /
.
Předchozí ukázka také zahrnuje volání UseRouting
a UseEndpoints
řízení přesně toho, kdy se tyto middlewary spouští v rámci kanálu.
Spuštění tohoto kódu s adresou URL /
zobrazení:
1. Endpoint: (null)
2. Endpoint: Hello
3. Endpoint: Hello
Spuštění tohoto kódu s jakoukoli jinou adresou URL zobrazí:
1. Endpoint: (null)
2. Endpoint: (null)
4. Endpoint: (null)
Tento výstup ukazuje, že:
- Koncový bod je před zavolání vždy null
UseRouting
. - Pokud se najde shoda, koncový bod je mezi
UseRouting
a UseEndpoints. - Middleware
UseEndpoints
je terminál , když se najde shoda. Middleware terminálu je definován dále v tomto článku. - Middleware po spuštění pouze v
UseEndpoints
případě, že nebyla nalezena žádná shoda.
Middleware UseRouting
používá metodu SetEndpoint pro připojení koncového bodu k aktuálnímu kontextu. Middleware je možné nahradit UseRouting
vlastní logikou a přesto získat výhody používání koncových bodů. Koncové body jsou primitivní nízké úrovně, jako je middleware, a nejsou svázané s implementací směrování. Většina aplikací nemusí nahradit UseRouting
vlastní logikou.
Middleware UseEndpoints
je navržený tak, aby se používal společně s middlewarem UseRouting
. Základní logika pro spuštění koncového bodu není složitá. Slouží GetEndpoint k načtení koncového bodu a následnému vyvolání jeho RequestDelegate vlastnosti.
Následující kód ukazuje, jak může middleware ovlivnit nebo reagovat na směrování:
app.UseHttpMethodOverride();
app.UseRouting();
app.Use(async (context, next) =>
{
if (context.GetEndpoint()?.Metadata.GetMetadata<RequiresAuditAttribute>() is not null)
{
Console.WriteLine($"ACCESS TO SENSITIVE DATA AT: {DateTime.UtcNow}");
}
await next(context);
});
app.MapGet("/", () => "Audit isn't required.");
app.MapGet("/sensitive", () => "Audit required for sensitive data.")
.WithMetadata(new RequiresAuditAttribute());
public class RequiresAuditAttribute : Attribute { }
Předchozí příklad ukazuje dva důležité koncepty:
- Middleware se může spustit před
UseRouting
úpravou dat, se kterými směrování pracuje.- Obvykle middleware, který se zobrazí před úpravou směrování některé vlastnosti požadavku, například UseRewriter, UseHttpMethodOverridenebo UsePathBase.
- Middleware se může spustit mezi
UseRouting
směrováním a UseEndpoints zpracovat výsledky směrování před spuštěním koncového bodu.- Middleware, který běží mezi
UseRouting
aUseEndpoints
:- Obvykle kontroluje metadata, aby porozuměla koncovým bodům.
- Často provádí rozhodnutí o zabezpečení, jak to dělá
UseAuthorization
aUseCors
.
- Kombinace middlewaru a metadat umožňuje konfigurovat zásady pro jednotlivé koncové body.
- Middleware, který běží mezi
Předchozí kód ukazuje příklad vlastního middlewaru, který podporuje zásady pro jednotlivé koncové body. Middleware zapíše protokol auditu přístupu k citlivým datům do konzoly. Middleware je možné nakonfigurovat tak, aby auditoval koncový bod s RequiresAuditAttribute
metadaty. Tato ukázka ukazuje způsob vyjádření výslovného souhlasu, kdy se auditují jenom koncové body označené jako citlivé. Tuto logiku je možné definovat obráceně, auditovat všechno, co není označené jako bezpečné, například. Systém metadat koncového bodu je flexibilní. Tato logika by mohla být navržena jakýmkoli způsobem, který vyhovuje případu použití.
Předchozí vzorový kód je určený k předvedení základních konceptů koncových bodů. Ukázka není určená pro produkční použití. Ucelenější verze middlewaru protokolu auditu:
- Přihlaste se k souboru nebo databázi.
- Uveďte podrobnosti, jako je uživatel, IP adresa, název citlivého koncového bodu a další.
Metadata zásad auditu jsou definována RequiresAuditAttribute
jako Attribute
jednodušší použití s architekturami založenými na třídách, jako jsou kontrolery a SignalR. Při použití trasy ke kódu:
- Metadata jsou připojena pomocí rozhraní API tvůrce.
- Architektury založené na třídách zahrnují všechny atributy odpovídající metody a třídy při vytváření koncových bodů.
Osvědčenými postupy pro typy metadat je definovat buď jako rozhraní, nebo atributy. Rozhraní a atributy umožňují opakované použití kódu. Systém metadat je flexibilní a neukládá žádná omezení.
Porovnání middlewaru terminálu se směrováním
Následující příklad ukazuje terminálový middleware i směrování:
// Approach 1: Terminal Middleware.
app.Use(async (context, next) =>
{
if (context.Request.Path == "/")
{
await context.Response.WriteAsync("Terminal Middleware.");
return;
}
await next(context);
});
app.UseRouting();
// Approach 2: Routing.
app.MapGet("/Routing", () => "Routing.");
Styl middlewaru zobrazeného s terminálovým middlewarem Approach 1:
. Říká se tomu middleware terminálu, protože dělá odpovídající operaci:
- Odpovídající operace v předchozí ukázce je
Path == "/"
pro middleware aPath == "/Routing"
pro směrování. - Když je shoda úspěšná, spustí některé funkce a vrátí se místo vyvolání middlewaru
next
.
Říká se tomu middleware terminálu, protože ukončí hledání, spustí některé funkce a vrátí se.
Následující seznam porovnává middleware terminálu se směrováním:
- Oba přístupy umožňují ukončení kanálu zpracování:
- Middleware ukončí kanál tím, že se místo vyvolání
next
. - Koncové body jsou vždy terminálové.
- Middleware ukončí kanál tím, že se místo vyvolání
- Middleware terminálu umožňuje umístění middlewaru na libovolné místo v kanálu:
- Koncové body se provádějí na pozici UseEndpoints.
- Middleware terminálu umožňuje libovolnému kódu určit, kdy middleware odpovídá:
- Vlastní kód pro porovnávání tras může být podrobný a obtížně zapisuje správně.
- Směrování poskytuje jednoduchá řešení pro typické aplikace. Většina aplikací nevyžaduje vlastní kód pro porovnávání tras.
- Rozhraní koncových bodů s middlewarem, jako
UseAuthorization
je například aUseCors
.- Použití middlewaru terminálu s
UseAuthorization
autorizačním systémem neboUseCors
vyžaduje ruční propojení se systémem autorizace.
- Použití middlewaru terminálu s
Koncový bod definuje obojí:
- Delegát na zpracování požadavků.
- Kolekce libovolných metadat. Metadata se používají k implementaci průřezových aspektů na základě zásad a konfigurace připojených k jednotlivým koncovým bodům.
Terminálový middleware může být efektivní nástroj, ale může vyžadovat:
- Značné množství kódování a testování.
- Ruční integrace s jinými systémy za účelem dosažení požadované úrovně flexibility.
Před zápisem middlewaru terminálu zvažte integraci se směrováním.
Existující middleware terminálu, který se integruje s mapou , nebo MapWhen se obvykle dá převést na koncový bod podporující směrování. MapHealthChecks ukazuje vzor pro router-ware:
- Napište metodu rozšíření na IEndpointRouteBuilder.
- Vytvoření vnořeného kanálu middlewaru pomocí CreateApplicationBuilder.
- Připojte middleware k novému kanálu. V tomto případě . UseHealthChecks
- Buildmiddlewarový kanál do .RequestDelegate
- Zavolejte a poskytněte
Map
nový kanál middlewaru. - Vrátí objekt tvůrce poskytnutý
Map
metodou rozšíření.
Následující kód ukazuje použití MapHealthChecks:
app.UseAuthentication();
app.UseAuthorization();
app.MapHealthChecks("/healthz").RequireAuthorization();
Předchozí ukázka ukazuje, proč je vrácení objektu tvůrce důležité. Vrácení objektu tvůrce umožňuje vývojáři aplikací konfigurovat zásady, jako je autorizace pro koncový bod. V tomto příkladu nemá middleware kontroly stavu žádnou přímou integraci se systémem autorizace.
Systém metadat byl vytvořen v reakci na problémy zjištěné autory rozšiřitelnosti pomocí middlewaru terminálu. Pro každý middleware je problematické implementovat vlastní integraci s autorizačním systémem.
Porovnávání adres URL
- Je proces, kterým směrování odpovídá příchozímu požadavku na koncový bod.
- Je založená na datech v cestě URL a hlavičkách.
- Můžete ho rozšířit, abyste zvážili všechna data v požadavku.
Když se spustí middleware směrování, nastaví Endpoint
hodnotu požadavku na funkci HttpContext požadavku z aktuálního požadavku:
- Volání httpContext.GetEndpoint získá koncový bod.
HttpRequest.RouteValues
získá kolekci hodnot tras.
Middleware se spustí po spuštění middlewaru směrování, který může zkontrolovat koncový bod a provést akci. Například autorizační middleware může probrat kolekci metadat koncového bodu pro zásady autorizace. Po spuštění veškerého middlewaru v kanálu zpracování požadavků se vyvolá delegát vybraného koncového bodu.
Systém směrování ve směrování koncového bodu zodpovídá za veškerá rozhodnutí o odesílání. Vzhledem k tomu, že middleware používá zásady na základě vybraného koncového bodu, je důležité, aby:
- Jakékoli rozhodnutí, které může ovlivnit odesílání nebo použití zásad zabezpečení, se provádí v rámci systému směrování.
Upozorňující
V případě zpětné kompatibility se při spuštění delegáta koncového RouteContext.RouteData bodu kontroleru nebo Razor stránky nastaví vlastnosti na odpovídající hodnoty na základě dosud provedeného zpracování požadavku.
Typ RouteContext
bude v budoucí verzi označen jako zastaralý:
- Migrovat
RouteData.Values
naHttpRequest.RouteValues
. - Migrace
RouteData.DataTokens
pro načtení IDataTokensMetadata z metadat koncového bodu
Porovnávání adres URL funguje v konfigurovatelné sadě fází. V každé fázi je výstup sadou shod. Sadu shod lze dále zúžit v další fázi. Implementace směrování nezaručuje pořadí zpracování pro odpovídající koncové body. Všechny možné shody se zpracovávají najednou. Fáze porovnávání adres URL probíhají v následujícím pořadí. ASP.NET Core:
- Zpracovává cestu URL vůči sadě koncových bodů a jejich šablon tras a shromažďuje všechny shody.
- Vezme předchozí seznam a odebere shody, které selžou s použitými omezeními trasy.
- Vezme předchozí seznam a odebere shody, které sadu instancí selžou MatcherPolicy .
- EndpointSelector Použije k poslednímu rozhodnutí z předchozího seznamu.
Seznam koncových bodů má prioritu podle následujících:
- RouteEndpoint.Order
- Priorita šablony trasy
Všechny odpovídající koncové body se zpracovávají v každé fázi, dokud se nedosáhne EndpointSelector . Jedná se EndpointSelector
o konečnou fázi. Jako nejlepší shodu zvolí koncový bod s nejvyšší prioritou. Pokud existují jiné shody se stejnou prioritou jako nejlepší shoda, vyvolá se výjimka nejednoznačné shody.
Priorita trasy se vypočítá na základě konkrétnější šablony trasy, která má vyšší prioritu. Představte si například šablony /hello
a /{message}
:
- Obě odpovídají cestě
/hello
URL . /hello
je konkrétnější a proto vyšší priorita.
Obecně platí, že priorita trasy má dobrou úlohu při výběru nejvhodnější shody pro druhy schémat adres URL používaných v praxi. Používejte Order pouze v případě potřeby, abyste se vyhnuli nejednoznačnosti.
Vzhledem k druhům rozšiřitelnosti poskytované směrováním není možné, aby směrovací systém předem počítaly nejednoznačné trasy. Představte si příklad, jako jsou šablony /{message:alpha}
tras a /{message:int}
:
- Omezení
alpha
odpovídá pouze abecedním znakům. - Omezení
int
odpovídá pouze číslu. - Tyto šablony mají stejnou prioritu tras, ale obě adresy URL se neshodují.
- Pokud systém směrování nahlásil při spuštění nejednoznačnosti, zablokoval by tento platný případ použití.
Upozorňující
Pořadí operací uvnitř UseEndpoints nemá vliv na chování směrování, s jednou výjimkou. MapControllerRoute a MapAreaRoute automaticky přiřadí hodnotu objednávky ke svým koncovým bodům na základě pořadí, ve které jsou vyvolány. To simuluje dlouhodobé chování kontrolerů bez systému směrování, který poskytuje stejné záruky jako starší implementace směrování.
Směrování koncových bodů v ASP.NET Core:
- Nemá koncept tras.
- Neposkytuje záruky objednávání. Všechny koncové body se zpracovávají najednou.
Priorita šablony trasy a pořadí výběru koncového bodu
Priorita šablony trasy je systém, který každé šabloně trasy přiřadí hodnotu na základě toho, jak je konkrétní. Priorita šablony trasy:
- Vyhne se nutnosti upravovat pořadí koncových bodů v běžných případech.
- Snaží se shodovat s očekáváními obecného chování směrování.
Představte si například šablony /Products/List
a /Products/{id}
. Bylo by rozumné předpokládat, že /Products/List
je lepší shoda než /Products/{id}
pro cestu /Products/List
URL . To funguje, protože literálový segment /List
je považován za lepší prioritu než segment /{id}
parametru .
Podrobnosti o tom, jak funguje priorita, jsou svázány s tím, jak se definují šablony tras:
- Šablony s více segmenty jsou považovány za konkrétnější.
- Segment s literálovým textem se považuje za konkrétnější než segment parametru.
- Segment parametru s omezením se považuje za konkrétnější než jeden bez.
- Složitý segment se považuje za specifický jako segment parametru s omezením.
- Parametry pro zachytávání jsou nejmíň specifické. Důležité informace o trasách pro zachytávání všech tras najdete v části Šablony tras catch-all.
Koncepty generování adres URL
Generování adres URL:
- Je proces, pomocí kterého směrování může vytvořit cestu URL na základě sady hodnot tras.
- Umožňuje logické oddělení mezi koncovými body a adresami URL, které k nim přistupují.
Směrování koncových bodů zahrnuje LinkGenerator rozhraní API. LinkGenerator
je jednoúčelová služba, která je k dispozici z DI. Rozhraní LinkGenerator
API se dá použít mimo kontext spuštěného požadavku. Mvc.IUrlHelper a scénáře, které se spoléhají , IUrlHelperjako jsou pomocné rutiny značek, pomocné rutiny HTML a výsledky akcí, používají LinkGenerator
rozhraní API interně k poskytování možností generování odkazů.
Generátor odkazů je podporován konceptem adresního a adresního schématu. Schéma adres je způsob, jak určit koncové body, které by se měly zvážit pro generování propojení. Například scénáře názvu trasy a směrovacích hodnot, které mnoho uživatelů znáte z kontrolerů a Razor Stránky se implementují jako schéma adres.
Generátor odkazů může odkazovat na kontrolery a Razor stránky pomocí následujících rozšiřujících metod:
Přetížení těchto metod přijímají argumenty, které zahrnují HttpContext
. Tyto metody jsou funkčně ekvivalentní url.Action a Url.Page, ale nabízejí další flexibilitu a možnosti.
Metody GetPath*
jsou nejvíce podobné Url.Action
a Url.Page
v tom, že vygenerují identifikátor URI obsahující absolutní cestu. Metody GetUri*
vždy generují absolutní identifikátor URI obsahující schéma a hostitele. Metody, které přijímají HttpContext
vygenerování identifikátoru URI v kontextu prováděcího požadavku. Hodnoty okolní trasy, základní cesta URL, schéma a hostitel ze spuštěného požadavku se použijí, pokud je nepřepíšete.
LinkGenerator je volána s adresou. Generování identifikátoru URI probíhá ve dvou krocích:
- Adresa je svázaná se seznamem koncových bodů, které odpovídají adrese.
- Vyhodnocuje se RoutePattern každý koncový bod, dokud se nenajde vzor trasy, který odpovídá zadaným hodnotám. Výsledný výstup se zkombinuje s ostatními částmi identifikátoru URI zadanými do generátoru propojení a vrátí se.
Metody poskytované standardními možnostmi LinkGenerator generování propojení pro libovolný typ adresy. Nejpohodlnější způsob použití generátoru propojení je prostřednictvím rozšiřujících metod, které provádějí operace pro konkrétní typ adresy:
Extension – metoda | Popis |
---|---|
GetPathByAddress | Vygeneruje identifikátor URI s absolutní cestou na základě zadaných hodnot. |
GetUriByAddress | Vygeneruje absolutní identifikátor URI na základě zadaných hodnot. |
Upozorňující
Věnujte pozornost následujícím důsledkům volání LinkGenerator metod:
V konfiguraci aplikace používejte
GetUri*
metody rozšíření s opatrností, která neověřuje hlavičkuHost
příchozích požadavků. Pokud hlavičkaHost
příchozích požadavků není ověřená, může být nedůvěryhodný vstup požadavku odeslán zpět klientovi v identifikátorech URI v zobrazení nebo stránce. Doporučujeme, aby všechny produkční aplikace nakonfigurovaly svůj server tak, aby ověřovaly hlavičkuHost
proti známým platným hodnotám.Používejte LinkGenerator s opatrností v middlewaru v kombinaci s
Map
neboMapWhen
.Map*
změní základní cestu prováděcího požadavku, která má vliv na výstup generování propojení. LinkGenerator Všechna rozhraní API umožňují zadat základní cestu. Zadejte prázdnouMap*
základní cestu, která vrátí zpět vliv na generování propojení.
Příklad middlewaru
V následujícím příkladu middleware používá LinkGenerator rozhraní API k vytvoření odkazu na metodu akce, která obsahuje seznam produktů pro ukládání. Použití generátoru odkazů vložením do třídy a volání GenerateLink
je k dispozici pro libovolnou třídu v aplikaci:
public class ProductsMiddleware
{
private readonly LinkGenerator _linkGenerator;
public ProductsMiddleware(RequestDelegate next, LinkGenerator linkGenerator) =>
_linkGenerator = linkGenerator;
public async Task InvokeAsync(HttpContext httpContext)
{
httpContext.Response.ContentType = MediaTypeNames.Text.Plain;
var productsPath = _linkGenerator.GetPathByAction("Products", "Store");
await httpContext.Response.WriteAsync(
$"Go to {productsPath} to see our products.");
}
}
Šablony tras
Tokeny v rámci {}
definují parametry trasy, které jsou vázané, pokud se trasa shoduje. V segmentu trasy je možné definovat více než jeden parametr trasy, ale parametry trasy musí být oddělené hodnotou literálu. Příklad:
{controller=Home}{action=Index}
není platná trasa, protože neexistuje žádná hodnota literálu mezi {controller}
a {action}
. Parametry trasy musí mít název a mohou mít zadané další atributy.
Literál jiný než směrovací parametry (například {id}
) a oddělovač /
cesty musí odpovídat textu v adrese URL. Porovnávání textu nerozlišuje malá a velká písmena a vychází z dekódované reprezentace cesty adresy URL. Chcete-li se shodovat s oddělovačem {
parametru trasy literálu nebo }
, uchytáte oddělovač opakováním znaku. Například {{
nebo }}
.
Hvězdička *
nebo dvojitá hvězdička **
:
- Lze použít jako předponu parametru trasy pro vazbu na rest identifikátor URI.
- Nazývají se parametry catch-all. Příklad:
blog/{**slug}
- Odpovídá libovolnému identifikátoru
blog/
URI, který začíná a má za ním libovolnou hodnotu. - Následující hodnota
blog/
je přiřazena ke slug směrovací hodnotě.
- Odpovídá libovolnému identifikátoru
Upozorňující
Parametr catch-all může nesprávně odpovídat trasám kvůli chybě při směrování. Aplikace ovlivněné touto chybou mají následující charakteristiky:
- Například trasa pro zachytávání– vše
{**slug}"
- Trasa catch-all neodpovídá požadavkům, které by se měly shodovat.
- Odebráním jiných tras začne fungovat zachytávání všech tras.
Podívejte se na chyby GitHubu 18677 a 16579 , například případy, které tuto chybu narazily.
Oprava výslovného souhlasu s touto chybou je obsažená v sadě .NET Core 3.1.301 SDK a novějších verzích. Následující kód nastaví interní přepínač, který tuto chybu opraví:
public static void Main(string[] args)
{
AppContext.SetSwitch("Microsoft.AspNetCore.Routing.UseCorrectCatchAllBehavior",
true);
CreateHostBuilder(args).Build().Run();
}
// Remaining code removed for brevity.
Parametry catch-all mohou také odpovídat prázdnému řetězci.
Parametr catch-all umisťuje příslušné znaky při použití trasy k vygenerování adresy URL, včetně znaků oddělovače /
cest. Například trasa foo/{*path}
s hodnotami { path = "my/path" }
trasy generuje foo/my%2Fpath
. Všimněte si řídicího lomítka. Pokud chcete znaky oddělovače cest odezvy použít předponu parametru **
trasy. Trasa foo/{**path}
s { path = "my/path" }
vygenerovanými .foo/my/path
Vzory adres URL, které se pokoušejí zachytit název souboru s volitelnou příponou souboru, mají další důležité informace. Představte si například šablonu files/{filename}.{ext?}
. Když hodnoty obou filename
hodnot existují ext
, naplní se obě hodnoty. Pokud v adrese URL existuje jenom hodnota filename
, trasa se shoduje, protože koncové hodnoty .
jsou volitelné. Následující adresy URL odpovídají této trase:
/files/myFile.txt
/files/myFile
Parametry trasy můžou mít výchozí hodnoty určené zadáním výchozí hodnoty za názvem parametru odděleným symbolem rovná se (=
). Například {controller=Home}
definuje Home
jako výchozí hodnotu pro controller
. Výchozí hodnota se použije, pokud v adrese URL parametru není žádná hodnota. Parametry trasy jsou volitelné připojením otazníku (?
) na konec názvu parametru. Například id?
. Rozdíl mezi volitelnými hodnotami a výchozími parametry trasy je:
- Parametr trasy s výchozí hodnotou vždy vytvoří hodnotu.
- Volitelný parametr má hodnotu pouze v případě, že je hodnota poskytována adresou URL požadavku.
Parametry trasy můžou mít omezení, která musí odpovídat hodnotě trasy vázané z adresy URL. Přidání :
a omezení názvu za názvem parametru trasy určuje vložené omezení parametru trasy. Pokud omezení vyžaduje argumenty, jsou za názvem omezení uzavřeny v závorkách (...)
. Více vložených omezení lze zadat připojením jiného :
názvu a názvu omezení.
Název omezení a argumenty se předávají službě IInlineConstraintResolver , aby se vytvořila instance IRouteConstraint , která se má použít při zpracování adresy URL. Například šablona blog/{article:minlength(10)}
trasy určuje minlength
omezení s argumentem 10
. Další informace o omezeních tras a seznamu omezení poskytovaných architekturou najdete v části Omezení trasy.
Parametry trasy mohou mít také transformátory parametrů. Transformátory parametrů transformují hodnotu parametru při generování odkazů a odpovídajících akcí a stránek na adresy URL. Stejně jako omezení lze transformátory parametrů přidat do parametru trasy přidáním :
názvu a transformátoru za název parametru trasy. Například šablona blog/{article:slugify}
trasy určuje slugify
transformátor. Další informace o transformátorech parametrů naleznete v části Transformátory parametrů .
Následující tabulka ukazuje ukázkové šablony tras a jejich chování:
Šablona trasy | Příklad odpovídajícího identifikátoru URI | Identifikátor URI požadavku... |
---|---|---|
hello |
/hello |
Odpovídá pouze jedné cestě /hello . |
{Page=Home} |
/ |
Odpovídá a nastaví Page na Home . |
{Page=Home} |
/Contact |
Odpovídá a nastaví Page na Contact . |
{controller}/{action}/{id?} |
/Products/List |
Mapuje se na Products kontroler a List akci. |
{controller}/{action}/{id?} |
/Products/Details/123 |
Mapuje se Products na kontroler a Details akci s nastavenouid na hodnotu 123. |
{controller=Home}/{action=Index}/{id?} |
/ |
Mapuje se na kontroler a Index metoduHome . Vlastnost id je ignorována. |
{controller=Home}/{action=Index}/{id?} |
/Products |
Mapuje se na kontroler a Index metoduProducts . Vlastnost id je ignorována. |
Použití šablony je obecně nejjednodušším přístupem ke směrování. Omezení a výchozí hodnoty lze zadat také mimo šablonu trasy.
Komplexní segmenty
Komplexní segmenty se zpracovávají pomocí odpovídajících oddělovačů literálů zprava doleva způsobem, který není greedy . Jedná se například [Route("/a{b}c{d}")]
o složitý segment.
Složité segmenty fungují určitým způsobem, který je potřeba pochopit, aby je bylo možné úspěšně použít. Příklad v této části ukazuje, proč složité segmenty skutečně fungují dobře, když se text oddělovače nezobrazí uvnitř hodnot parametrů. Použití regulárního výrazu a ruční extrahování hodnot je potřeba pro složitější případy.
Upozorňující
Při zpracování System.Text.RegularExpressions nedůvěryhodného vstupu předejte vypršení časového limitu. Uživatel se zlými úmysly může poskytnout vstup, který RegularExpressions
způsobí útok na dostupnost služby. ASP.NET rozhraní API architektury Core, která používají RegularExpressions
vypršení časového limitu.
Toto je souhrn kroků, které směrování provádí pomocí šablony /a{b}c{d}
a cesty /abcd
URL . Slouží |
k vizualizaci fungování algoritmu:
- První literál, zprava doleva, je
c
. Hledá se tedy/abcd
zprava a najde/ab|c|d
. - Vše napravo (
d
) se teď shoduje s parametrem{d}
trasy . - Další literál, zprava doleva, je
a
. Takže/ab|c|d
je prohledáno od místa, kde jsme skončili, paka
je nalezen/|a|b|c|d
. - Hodnota vpravo (
b
) se teď shoduje s parametrem{b}
trasy . - Neexistuje žádný zbývající text a žádná zbývající šablona trasy, takže se jedná o shodu.
Tady je příklad záporného případu, který používá stejnou šablonu /a{b}c{d}
a cestu /aabcd
URL . Slouží |
k vizualizaci fungování algoritmu. Tento případ není shoda, která je vysvětlená stejným algoritmem:
- První literál, zprava doleva, je
c
. Hledá se tedy/aabcd
zprava a najde/aab|c|d
. - Vše napravo (
d
) se teď shoduje s parametrem{d}
trasy . - Další literál, zprava doleva, je
a
. Takže/aab|c|d
je prohledáno od místa, kde jsme skončili, paka
je nalezen/a|a|b|c|d
. - Hodnota vpravo (
b
) se teď shoduje s parametrem{b}
trasy . - V tomto okamžiku existuje zbývající text
a
, ale algoritmus vyčeráhl šablonu trasy, aby parsovala, takže se nejedná o shodu.
Vzhledem k tomu, že odpovídající algoritmus není greedy:
- Odpovídá nejmenšímu množství textu, který je možné v každém kroku.
- Případ, kdy se hodnota oddělovače zobrazí uvnitř hodnot parametrů, způsobí, že se neshoduje.
Regulární výrazy poskytují mnohem větší kontrolu nad jejich odpovídajícím chováním.
Párování Greedy, označované také jako opožděné párování, odpovídá největšímu možnému řetězci. Greedy odpovídá nejmenšímu možnému řetězci.
Směrování se speciálními znaky
Směrování se speciálními znaky může vést k neočekávaným výsledkům. Představte si například kontroler s následující metodou akce:
[HttpGet("{id?}/name")]
public async Task<ActionResult<string>> GetName(string id)
{
var todoItem = await _context.TodoItems.FindAsync(id);
if (todoItem == null || todoItem.Name == null)
{
return NotFound();
}
return todoItem.Name;
}
Pokud string id
obsahuje následující kódované hodnoty, mohou dojít k neočekávaným výsledkům:
ASCII | Encoded |
---|---|
/ |
%2F |
|
+ |
Parametry trasy nejsou vždy dekódovány adresou URL. Tento problém může být vyřešen v budoucnu. Další informace najdete v tomto problému na GitHubu.
Omezení trasy
Omezení směrování se provádějí, když došlo ke shodě s příchozí adresou URL a cesta url se tokenizuje do hodnot tras. Omezení tras obecně kontrolují hodnotu trasy přidruženou prostřednictvím šablony trasy a ověřte, jestli je hodnota přijatelná, nebo nepravdivá. Některá omezení trasy používají data mimo hodnotu trasy a zvažují, jestli je možné požadavek směrovat. Například HttpMethodRouteConstraint může přijmout nebo odmítnout požadavek na základě jeho příkazu HTTP. Omezení se používají v požadavcích směrování a generování propojení.
Upozorňující
Nepoužívejte omezení pro ověřování vstupu. Pokud se pro ověření vstupu používají omezení, výsledkem neplatného 404
vstupu je odpověď Nenalezena. Neplatný vstup by měl vytvořit chybný 400
požadavek s příslušnou chybovou zprávou. Omezení tras se používají k nejednoznačnosti podobných tras, nikoli k ověření vstupů pro konkrétní trasu.
Následující tabulka ukazuje ukázková omezení směrování a jejich očekávané chování:
omezení | Příklad | Příklady shod | Notes |
---|---|---|---|
int |
{id:int} |
123456789 , -123456789 |
Odpovídá libovolnému celočíselnému číslu. |
bool |
{active:bool} |
true , FALSE |
Shody true nebo false . Nerozlišují se malá a velká písmena |
datetime |
{dob:datetime} |
2016-12-31 , 2016-12-31 7:32pm |
Odpovídá platné DateTime hodnotě v invariantní jazykové verzi. Viz předchozí upozornění. |
decimal |
{price:decimal} |
49.99 , -1,000.01 |
Odpovídá platné decimal hodnotě v invariantní jazykové verzi. Viz předchozí upozornění. |
double |
{weight:double} |
1.234 , -1,001.01e8 |
Odpovídá platné double hodnotě v invariantní jazykové verzi. Viz předchozí upozornění. |
float |
{weight:float} |
1.234 , -1,001.01e8 |
Odpovídá platné float hodnotě v invariantní jazykové verzi. Viz předchozí upozornění. |
guid |
{id:guid} |
CD2C1638-1638-72D5-1638-DEADBEEF1638 |
Odpovídá platné Guid hodnotě. |
long |
{ticks:long} |
123456789 , -123456789 |
Odpovídá platné long hodnotě. |
minlength(value) |
{username:minlength(4)} |
Rick |
Řetězec musí mít alespoň 4 znaky. |
maxlength(value) |
{filename:maxlength(8)} |
MyFile |
Řetězec nesmí být delší než 8 znaků. |
length(length) |
{filename:length(12)} |
somefile.txt |
Řetězec musí mít přesně 12 znaků. |
length(min,max) |
{filename:length(8,16)} |
somefile.txt |
Řetězec musí mít maximálně 8 znaků a nesmí být delší než 16 znaků. |
min(value) |
{age:min(18)} |
19 |
Celočíselná hodnota musí být alespoň 18. |
max(value) |
{age:max(120)} |
91 |
Celočíselná hodnota nesmí být větší než 120. |
range(min,max) |
{age:range(18,120)} |
91 |
Celočíselná hodnota musí být alespoň 18, ale nesmí být větší než 120. |
alpha |
{name:alpha} |
Rick |
Řetězec musí obsahovat jeden nebo více abecedních znaků a -z a nerozlišuje velká a malá písmena. |
regex(expression) |
{ssn:regex(^\\d{{3}}-\\d{{2}}-\\d{{4}}$)} |
123-45-6789 |
Řetězec musí odpovídat regulárnímu výrazu. Podívejte se na tipy k definování regulárního výrazu. |
required |
{name:required} |
Rick |
Používá se k vynucení toho, aby během generování adresy URL byla přítomna hodnota, která není parametrem. |
Upozorňující
Při zpracování System.Text.RegularExpressions nedůvěryhodného vstupu předejte vypršení časového limitu. Uživatel se zlými úmysly může poskytnout vstup, který RegularExpressions
způsobí útok na dostupnost služby. ASP.NET rozhraní API architektury Core, která používají RegularExpressions
vypršení časového limitu.
Pro jeden parametr lze použít více omezení oddělených dvojtečkami. Například následující omezení omezuje parametr na celočíselnou hodnotu 1 nebo vyšší:
[Route("users/{id:int:min(1)}")]
public User GetUserById(int id) { }
Upozorňující
Omezení směrování, která ověřují adresu URL a jsou převedeny na typ CLR, vždy používají neutrální jazykovou verzi. Například převod na typ int
CLR nebo DateTime
. Tato omezení předpokládají, že adresa URL není lokalizovatelná. Omezení tras poskytovaná architekturou nemění hodnoty uložené v hodnotách tras. Všechny hodnoty směrování parsované z adresy URL se ukládají jako řetězce. Omezení se například pokusí převést hodnotu trasy na hodnotu float, ale převedená hodnota se použije pouze k ověření, float
že se dá převést na plovoucí hodnotu.
Regulární výrazy v omezeních
Upozorňující
Při zpracování System.Text.RegularExpressions nedůvěryhodného vstupu předejte vypršení časového limitu. Uživatel se zlými úmysly může poskytnout vstup, který RegularExpressions
způsobí útok na dostupnost služby. ASP.NET rozhraní API architektury Core, která používají RegularExpressions
vypršení časového limitu.
Regulární výrazy lze zadat jako vložená omezení pomocí regex(...)
omezení trasy. Metody v rodině MapControllerRoute také přijímají literál objektu omezení. Pokud se tento formulář použije, řetězcové hodnoty se interpretují jako regulární výrazy.
Následující kód používá omezení vložených regulárních výrazů:
app.MapGet("{message:regex(^\\d{{3}}-\\d{{2}}-\\d{{4}}$)}",
() => "Inline Regex Constraint Matched");
Následující kód používá literál objektu k určení omezení regulárního výrazu:
app.MapControllerRoute(
name: "people",
pattern: "people/{ssn}",
constraints: new { ssn = "^\\d{3}-\\d{2}-\\d{4}$", },
defaults: new { controller = "People", action = "List" });
Architektura ASP.NET Core přidává RegexOptions.IgnoreCase | RegexOptions.Compiled | RegexOptions.CultureInvariant
do konstruktoru regulárních výrazů. Podívejte RegexOptions se na popis těchto členů.
Regulární výrazy používají oddělovače a tokeny podobné těm používaným směrováním a jazykem C#. Tokeny regulárních výrazů musí být uchycené. Chcete-li použít regulární výraz ^\d{3}-\d{2}-\d{4}$
v vložené omezení, použijte jednu z následujících možností:
- Nahraďte
\
znaky zadané v řetězci jako\\
znaky ve zdrojovém souboru jazyka C#, aby bylo možné řídicí znak řetězce utéct\
. - Doslovné řetězcové literály.
Chcete-li uvozovat znaky {
oddělovače parametrů směrování , [
}
]
zdvojnásobit znaky ve výrazu, {{
například , }}
, , . ]]
[[
Následující tabulka ukazuje regulární výraz a jeho řídicí verzi:
Regulární výraz | Řídicí regulární výraz |
---|---|
^\d{3}-\d{2}-\d{4}$ |
^\\d{{3}}-\\d{{2}}-\\d{{4}}$ |
^[a-z]{2}$ |
^[[a-z]]{{2}}$ |
Regulární výrazy používané při směrování často začínají znakem ^
a odpovídají počáteční pozici řetězce. Výrazy často končí znakem $
a odpovídají konci řetězce. Znaky ^
a $
zajistěte, aby regulární výraz odpovídal celé hodnotě parametru trasy. ^
Bez znaků a $
znaků regulární výraz odpovídá jakémukoli podřetězci v řetězci, což je často nežádoucí. Následující tabulka obsahuje příklady a vysvětluje, proč se shodují nebo se neshodují:
Výraz | String | Párování | Komentář |
---|---|---|---|
[a-z]{2} |
dobrý den | Ano | Shoda podřetěžce |
[a-z]{2} |
123abc456 | Ano | Shoda podřetěžce |
[a-z]{2} |
mz | Ano | Odpovídá výrazu |
[a-z]{2} |
MZ | Ano | Nerozlišuje se malá a velká písmena. |
^[a-z]{2}$ |
dobrý den | No | Viz ^ a $ výše |
^[a-z]{2}$ |
123abc456 | No | Viz ^ a $ výše |
Další informace o syntaxi regulárních výrazů naleznete v tématu Regulární výrazy rozhraní .NET Framework.
Chcete-li omezit parametr na známou sadu možných hodnot, použijte regulární výraz. Například {action:regex(^(list|get|create)$)}
odpovídá pouze hodnotě action
trasy do list
, get
nebo create
. Pokud je řetězec předán do slovníku omezení, je řetězec ^(list|get|create)$
ekvivalentní. Omezení, která se předávají ve slovníku omezení, která neodpovídají některému ze známých omezení, se také považují za regulární výrazy. Omezení předaná v šabloně, která neodpovídají některému ze známých omezení, se považují za regulární výrazy.
Vlastní omezení trasy
Vlastní omezení trasy je možné vytvořit implementací IRouteConstraint rozhraní. Rozhraní IRouteConstraint
obsahuje Match, který vrátí true
, pokud je omezení splněno a false
jinak.
Vlastní omezení trasy jsou zřídka nutná. Před implementací vlastního omezení trasy zvažte alternativy, jako je například vazba modelu.
Složka ASP.NET Core Constraints poskytuje dobré příklady vytváření omezení. Například GuidRouteConstraint.
Pokud chcete použít vlastní IRouteConstraint
typ omezení trasy, musí být zaregistrovaný v kontejneru služby v aplikaci ConstraintMap . A ConstraintMap
je slovník, který mapuje klíče omezení směrování na IRouteConstraint
implementace, které tato omezení ověřují. Aplikaci ConstraintMap
je možné aktualizovat buď Program.cs
v rámci AddRouting hovoru, nebo konfigurací RouteOptions přímo pomocí builder.Services.Configure<RouteOptions>
. Příklad:
builder.Services.AddRouting(options =>
options.ConstraintMap.Add("noZeroes", typeof(NoZeroesRouteConstraint)));
Předchozí omezení se použije v následujícím kódu:
[ApiController]
[Route("api/[controller]")]
public class NoZeroesController : ControllerBase
{
[HttpGet("{id:noZeroes}")]
public IActionResult Get(string id) =>
Content(id);
}
Implementace NoZeroesRouteConstraint
brání 0
použití v parametru trasy:
public class NoZeroesRouteConstraint : IRouteConstraint
{
private static readonly Regex _regex = new(
@"^[1-9]*$",
RegexOptions.CultureInvariant | RegexOptions.IgnoreCase,
TimeSpan.FromMilliseconds(100));
public bool Match(
HttpContext? httpContext, IRouter? route, string routeKey,
RouteValueDictionary values, RouteDirection routeDirection)
{
if (!values.TryGetValue(routeKey, out var routeValue))
{
return false;
}
var routeValueString = Convert.ToString(routeValue, CultureInfo.InvariantCulture);
if (routeValueString is null)
{
return false;
}
return _regex.IsMatch(routeValueString);
}
}
Upozorňující
Při zpracování System.Text.RegularExpressions nedůvěryhodného vstupu předejte vypršení časového limitu. Uživatel se zlými úmysly může poskytnout vstup, který RegularExpressions
způsobí útok na dostupnost služby. ASP.NET rozhraní API architektury Core, která používají RegularExpressions
vypršení časového limitu.
Předchozí kód:
- Zabraňuje
0
v{id}
segmentu trasy. - Ukazuje se, že poskytuje základní příklad implementace vlastního omezení. Neměla by se používat v produkční aplikaci.
Následující kód je lepším přístupem k tomu, aby se zabránilo zpracování obsahujícího id
0
:
[HttpGet("{id}")]
public IActionResult Get(string id)
{
if (id.Contains('0'))
{
return StatusCode(StatusCodes.Status406NotAcceptable);
}
return Content(id);
}
Předchozí kód má oproti přístupu následující výhody NoZeroesRouteConstraint
:
- Nevyžaduje vlastní omezení.
- Vrátí popisnější chybu, pokud parametr trasy obsahuje
0
.
Transformátory parametrů
Transformátory parametrů:
- Spustí se při generování odkazu pomocí LinkGenerator.
- Implementovat Microsoft.AspNetCore.Routing.IOutboundParameterTransformer.
- Jsou nakonfigurovány pomocí ConstraintMap.
- Převezměte hodnotu trasy parametru a transformujte ji na novou řetězcovou hodnotu.
- Výsledkem je použití transformované hodnoty ve vygenerovaném odkazu.
Například vlastní slugify
transformátor parametru ve vzoru blog\{article:slugify}
trasy s Url.Action(new { article = "MyTestArticle" })
vygenerovanými blog\my-test-article
.
Zvažte následující IOutboundParameterTransformer
implementaci:
public class SlugifyParameterTransformer : IOutboundParameterTransformer
{
public string? TransformOutbound(object? value)
{
if (value is null)
{
return null;
}
return Regex.Replace(
value.ToString()!,
"([a-z])([A-Z])",
"$1-$2",
RegexOptions.CultureInvariant,
TimeSpan.FromMilliseconds(100))
.ToLowerInvariant();
}
}
Chcete-li použít transformátor parametrů ve vzoru trasy, nakonfigurujte ho pomocí :ConstraintMap Program.cs
builder.Services.AddRouting(options =>
options.ConstraintMap["slugify"] = typeof(SlugifyParameterTransformer));
Architektura ASP.NET Core používá transformátory parametrů k transformaci identifikátoru URI, kde se koncový bod překládá. Například transformátory parametrů transformují směrovací hodnoty použité ke shodě area
, controller
, action
a page
:
app.MapControllerRoute(
name: "default",
pattern: "{controller:slugify=Home}/{action:slugify=Index}/{id?}");
U předchozí šablony trasy se akce SubscriptionManagementController.GetAll
shoduje s identifikátorem URI /subscription-management/get-all
. Transformátor parametrů nemění směrovací hodnoty použité k vygenerování propojení. Například Url.Action("GetAll", "SubscriptionManagement")
výstupy /subscription-management/get-all
.
ASP.NET Core poskytuje konvence rozhraní API pro použití transformátorů parametrů se generovanými trasami:
- Konvence Microsoft.AspNetCore.Mvc.ApplicationModels.RouteTokenTransformerConvention MVC aplikuje zadaný transformátor parametrů na všechny trasy atributů v aplikaci. Parametr transformer transformuje tokeny směrování atributů při jejich nahrazení. Další informace naleznete v tématu Použití transformátoru parametrů k přizpůsobení nahrazení tokenu.
- Razor Stránky používají PageRouteTransformerConvention konvenci rozhraní API. Tato konvence aplikuje zadaný transformátor parametrů na všechny automaticky zjištěné Razor stránky. Transformátor parametru transformuje segmenty Razor složek a názvů souborů tras Pages. Další informace naleznete v tématu Použití transformátoru parametrů k přizpůsobení tras stránky.
Referenční informace ke generování adres URL
Tato část obsahuje odkaz na algoritmus implementovaný generováním adres URL. V praxi používají nejsložitější příklady generování adres URL kontrolery nebo Razor stránky. Další informace najdete v tématu Směrování v kontrolerů .
Proces generování adresy URL začíná voláním LinkGenerator.GetPathByAddress nebo podobnou metodou. Metoda je poskytována s adresou, sadou hodnot tras a volitelně informace o aktuálním požadavku z HttpContext
.
Prvním krokem je použití adresy k vyřešení sady kandidátských koncových bodů pomocí typu IEndpointAddressScheme<TAddress> adresy.
Jakmile sada kandidátů najde schéma adres, koncové body se objednávají a zpracovávají iterativním způsobem, dokud operace generování adresy URL nebude úspěšná. Generování adresy URL nekontroluje nejednoznačnosti, první vrácený výsledek je konečný výsledek.
Řešení potíží s generováním adres URL pomocí protokolování
Prvním krokem při generování adresy URL při řešení potíží je nastavení úrovně Microsoft.AspNetCore.Routing
protokolování na TRACE
. LinkGenerator
zaznamenává mnoho podrobností o jeho zpracování, které může být užitečné při řešení problémů.
Podrobnosti o generování adres URL najdete v referenčních informacích ke generování adres URL.
Adresy
Adresy jsou konceptem generování adres URL, které slouží k vytvoření vazby volání do generátoru odkazů na sadu kandidátských koncových bodů.
Adresy jsou rozšiřitelný koncept, který ve výchozím nastavení obsahuje dvě implementace:
- Jako adresu použijte název koncového bodu (
string
):- Poskytuje podobné funkce jako název trasy MVC.
- IEndpointNameMetadata Používá typ metadat.
- Vyřeší zadaný řetězec s metadaty všech registrovaných koncových bodů.
- Vyvolá výjimku při spuštění, pokud více koncových bodů používá stejný název.
- Doporučuje se pro obecné použití mimo kontrolery a Razor stránky.
- Použití hodnot směrování (RouteValuesAddress) jako adresy:
- Poskytuje podobné funkce jako kontrolery a Razor starší generace adres URL stránky.
- Velmi složité rozšířit a ladit.
- Poskytuje implementaci, kterou
IUrlHelper
používají pomocné rutiny značek, pomocné rutiny HTML, výsledky akcí atd.
Role schématu adres spočívá v přidružení mezi adresou a odpovídajícími koncovými body podle libovolných kritérií:
- Schéma názvu koncového bodu provádí základní vyhledávání slovníku.
- Schéma hodnot tras má komplexní nejlepší podmnožinu algoritmu sady.
Okolní hodnoty a explicitní hodnoty
Z aktuálního požadavku směrování přistupuje ke směrovacím hodnotám aktuálního požadavku HttpContext.Request.RouteValues
. Hodnoty přidružené k aktuálnímu požadavku se označují jako okolní hodnoty. Pro účely srozumitelnosti se dokumentace týká směrovacích hodnot předávaných metodám jako explicitních hodnot.
Následující příklad ukazuje okolní hodnoty a explicitní hodnoty. Poskytuje okolní hodnoty z aktuálního požadavku a explicitních hodnot:
public class WidgetController : ControllerBase
{
private readonly LinkGenerator _linkGenerator;
public WidgetController(LinkGenerator linkGenerator) =>
_linkGenerator = linkGenerator;
public IActionResult Index()
{
var indexPath = _linkGenerator.GetPathByAction(
HttpContext, values: new { id = 17 })!;
return Content(indexPath);
}
// ...
Předchozí kód:
- Návraty
/Widget/Index/17
- Získá LinkGenerator přes DI.
Následující kód poskytuje pouze explicitní hodnoty a žádné okolní hodnoty:
var subscribePath = _linkGenerator.GetPathByAction(
"Subscribe", "Home", new { id = 17 })!;
Předchozí metoda vrátí /Home/Subscribe/17
Následující kód ve návratu WidgetController
/Widget/Subscribe/17
:
var subscribePath = _linkGenerator.GetPathByAction(
HttpContext, "Subscribe", null, new { id = 17 });
Následující kód poskytuje kontroler z okolních hodnot v aktuálním požadavku a explicitní hodnoty:
public class GadgetController : ControllerBase
{
public IActionResult Index() =>
Content(Url.Action("Edit", new { id = 17 })!);
}
V předchozím kódu:
/Gadget/Edit/17
je vrácena.- UrlIUrlHelperzíská .
- Action vygeneruje adresu URL s absolutní cestou pro metodu akce. Adresa URL obsahuje zadaný
action
název aroute
hodnoty.
Následující kód poskytuje okolní hodnoty z aktuálního požadavku a explicitní hodnoty:
public class IndexModel : PageModel
{
public void OnGet()
{
var editUrl = Url.Page("./Edit", new { id = 17 });
// ...
}
}
Předchozí kód se nastaví url
, když /Edit/17
Edit Razor Page obsahuje následující direktivu stránky:
@page "{id:int}"
Pokud stránka Upravit neobsahuje "{id:int}"
šablonu trasy, url
je /Edit?id=17
.
Chování MVC IUrlHelper přidává kromě zde popsaných pravidel vrstvu složitosti:
IUrlHelper
vždy poskytuje směrovací hodnoty z aktuálního požadavku jako okolní hodnoty.- IUrlHelper.Action vždy zkopíruje aktuální
action
hodnoty acontroller
směrovací hodnoty jako explicitní hodnoty, pokud je nepřepíše vývojář. - IUrlHelper.Page vždy zkopíruje aktuální
page
hodnotu trasy jako explicitní hodnotu, pokud ji nepřepíšete. IUrlHelper.Page
vždy přepíše aktuálníhandler
hodnotunull
trasy jako explicitní hodnoty, pokud ji nepřepíšete.
Uživatelé jsou často překvapeni chováním okolních hodnot, protože MVC zdánlivě nedodržuje vlastní pravidla. Z historických důvodů a z důvodu kompatibility mají určité hodnoty tras, jako action
je , controller
, page
a handler
mají vlastní zvláštní chování.
Ekvivalentní funkce poskytované LinkGenerator.GetPathByAction
a LinkGenerator.GetPathByPage
duplikuje tyto anomálie z důvodu kompatibility IUrlHelper
.
Proces generování adres URL
Jakmile se najde sada kandidátských koncových bodů, algoritmus generování adres URL:
- Zpracovává koncové body iterativním způsobem.
- Vrátí první úspěšný výsledek.
Prvním krokem v tomto procesu je zneplatnění hodnoty trasy. Zneplatnění hodnoty trasy je proces, kterým směrování rozhodne, které hodnoty trasy z okolních hodnot se mají použít a které by se měly ignorovat. Každá okolní hodnota se považuje a buď v kombinaci s explicitními hodnotami, nebo je ignorována.
Nejlepším způsobem, jak přemýšlet o roli okolních hodnot, je, že se snaží uložit vývojáři aplikací psaní, v některých běžných případech. Scénáře, ve kterých jsou okolní hodnoty užitečné, se tradičně vztahují k MVC:
- Při propojení s jinou akcí ve stejném řadiči není nutné zadat název kontroleru.
- Při propojení s jiným řadičem ve stejné oblasti není nutné zadat název oblasti.
- Při propojení se stejnou metodou akce není nutné zadávat hodnoty tras.
- Při propojení s jinou částí aplikace nechcete přenášet hodnoty tras, které nemají v této části aplikace žádný význam.
Volání nebo LinkGenerator
IUrlHelper
vrácení jsou obvykle způsobená tím, že null
nerozumí neplatné hodnotě trasy. Při řešení potíží s neplatnou hodnotou trasy můžete explicitně zadat více hodnot tras, abyste zjistili, jestli se tím problém vyřeší.
Neplatná hodnota trasy funguje na předpokladu, že schéma adresy URL aplikace je hierarchické s hierarchií vytvořenou zleva doprava. Představte si šablonu {controller}/{action}/{id?}
směrování základního kontroleru, abyste získali intuitivní představu o tom, jak to funguje v praxi. Změna hodnoty zneplatní všechny směrovací hodnoty, které se zobrazují vpravo. To odráží předpoklad o hierarchii. Pokud má aplikace okolní hodnotu a id
operace určuje jinou hodnotu pro controller
:
id
nebude znovu použito, protože{controller}
je nalevo od{id?}
.
Několik příkladů demonstrujících tento princip:
- Pokud explicitní hodnoty obsahují hodnotu pro
id
, okolní hodnota jeid
ignorována. Okolní hodnoty acontroller
action
lze je použít. - Pokud explicitní hodnoty obsahují hodnotu pro
action
, je ignorována jakákoli okolní hodnota proaction
. Lze použít okolní hodnotycontroller
. Pokud se explicitní hodnota pro jinou než okolní hodnotaaction
action
pro ,id
hodnota se nepoužije. Pokud je explicitní hodnotaaction
stejná jako okolní hodnota proaction
,id
lze použít hodnotu. - Pokud explicitní hodnoty obsahují hodnotu pro
controller
, je ignorována jakákoli okolní hodnota procontroller
. Pokud se explicitní hodnota pro jinou než okolní hodnotacontroller
controller
pro ,action
hodnoty aid
hodnoty nebudou použity. Pokud je explicitní hodnotacontroller
stejná jako okolní hodnota procontroller
,action
lze použít hodnoty aid
hodnoty.
Tento proces je ještě složitější díky existenci tras atributů a vyhrazených konvenčních tras. Běžné trasy kontroleru, jako {controller}/{action}/{id?}
je například určení hierarchie pomocí parametrů trasy. Pro vyhrazené konvenční trasy a trasy atributů pro kontrolery a Razor stránky:
- Existuje hierarchie hodnot tras.
- Nezobrazují se v šabloně.
V těchto případech generování adresy URL definuje koncept požadovaných hodnot . Koncové body vytvořené kontrolery a Razor stránkami mají zadané požadované hodnoty, které umožňují zneplatnění hodnoty trasy.
Podrobný algoritmus zneplatnění hodnoty trasy:
- Požadované názvy hodnot se kombinují s parametry trasy a pak se zpracovávají zleva doprava.
- Pro každý parametr se porovná okolní hodnota a explicitní hodnota:
- Pokud je okolní hodnota a explicitní hodnota stejné, proces pokračuje.
- Pokud je okolní hodnota přítomná a explicitní hodnota není, použije se při generování adresy URL okolní hodnota.
- Pokud okolní hodnota není přítomná a explicitní hodnota je, zamítněte okolní hodnotu a všechny následné okolní hodnoty.
- Pokud se nachází okolí a explicitní hodnota a obě hodnoty jsou odlišné, zamítněte okolní hodnotu a všechny následné okolní hodnoty.
V tuto chvíli je operace generování adres URL připravená k vyhodnocení omezení trasy. Sada přijatých hodnot se zkombinuje s výchozími hodnotami parametrů, které jsou k dispozici pro omezení. Pokud všechna omezení projdou, operace bude pokračovat.
Dále je možné použít akceptované hodnoty k rozšíření šablony trasy. Šablona trasy se zpracuje:
- Zleva doprava.
- Každý parametr má jeho přijatou hodnotu nahrazenou.
- S následujícími zvláštními případy:
- Pokud přijaté hodnoty chybí hodnota a parametr má výchozí hodnotu, použije se výchozí hodnota.
- Pokud přijaté hodnoty chybí a parametr je nepovinný, zpracování pokračuje.
- Pokud některý parametr trasy napravo od chybějícího volitelného parametru má hodnotu, operace selže.
- Pokud je to možné, sbalí se souvislé parametry s výchozími hodnotami a volitelné parametry.
Hodnoty explicitně za předpokladu, že neodpovídají segmentu trasy, se přidají do řetězce dotazu. Následující tabulka ukazuje výsledek při použití šablony {controller}/{action}/{id?}
trasy .
Okolní hodnoty | Explicitní hodnoty | Výsledek |
---|---|---|
controller = "Home" | action = "O aplikaci" | /Home/About |
controller = "Home" | controller = "Order", action = "About" | /Order/About |
controller = "Home", color = "Red" | action = "O aplikaci" | /Home/About |
controller = "Home" | action = "O produktu", barva = "Červená" | /Home/About?color=Red |
Problémy s neplatnou hodnotou trasy
Následující kód ukazuje příklad schématu generování adres URL, které není podporováno směrováním:
app.MapControllerRoute(
"default",
"{culture}/{controller=Home}/{action=Index}/{id?}");
app.MapControllerRoute(
"blog",
"{culture}/{**slug}",
new { controller = "Blog", action = "ReadPost" });
V předchozím kódu culture
se parametr trasy používá pro lokalizaci. Touha má parametr culture
vždy přijmout jako okolní hodnotu. Parametr culture
však není přijat jako okolní hodnota kvůli způsobu, jakým požadované hodnoty fungují:
"default"
V šabloněculture
trasy je parametr trasy vlevo odcontroller
, takže změnycontroller
nebudouculture
neplatné ."blog"
V šabloněculture
trasy se parametr trasy považuje za napravo odcontroller
parametru trasy, který se zobrazí v požadovaných hodnotách.
Parsování cest URL pomocí LinkParser
Třída LinkParser přidává podporu analýzy cesty URL do sady hodnot tras. Metoda ParsePathByEndpointName přebírá název koncového bodu a cestu URL a vrátí sadu hodnot tras extrahovaných z cesty URL.
V následujícím příkladu kontroler akce GetProduct
používá šablonu api/Products/{id}
trasy a má Name :GetProduct
[ApiController]
[Route("api/[controller]")]
public class ProductsController : ControllerBase
{
[HttpGet("{id}", Name = nameof(GetProduct))]
public IActionResult GetProduct(string id)
{
// ...
Ve stejné třídě AddRelatedProduct
kontroleru akce očekává cestu URL, pathToRelatedProduct
kterou lze poskytnout jako parametr řetězce dotazu:
[HttpPost("{id}/Related")]
public IActionResult AddRelatedProduct(
string id, string pathToRelatedProduct, [FromServices] LinkParser linkParser)
{
var routeValues = linkParser.ParsePathByEndpointName(
nameof(GetProduct), pathToRelatedProduct);
var relatedProductId = routeValues?["id"];
// ...
V předchozím příkladu AddRelatedProduct
akce extrahuje id
hodnotu trasy z cesty URL. Například s cestou /api/Products/1
URL , relatedProductId
hodnota je nastavena na 1
. Tento přístup umožňuje klientům rozhraní API používat cesty url při odkazování na prostředky, aniž by museli vědět, jak je taková adresa URL strukturovaná.
Konfigurace metadat koncového bodu
Následující odkazy obsahují informace o konfiguraci metadat koncového bodu:
- Povolení Cors se směrováním koncových bodů
- Ukázka IAuthorizationPolicyProvider pomocí vlastního
[MinimumAgeAuthorize]
atributu - Testování ověřování pomocí atributu [Authorize]
- RequireAuthorization
- Výběr schématu s atributem [Authorize]
- Použití zásad pomocí atributu [Authorize]
- Autorizace na základě rolí v ASP.NET Core
Porovnávání hostitelů v trasách pomocí RequireHost
RequireHost použije omezení na trasu, která vyžaduje zadaného hostitele. Parametrem RequireHost
[Host] může být:
- Hostitel:
www.domain.com
, odpovídáwww.domain.com
libovolnému portu. - Hostitel se zástupným znakem:
*.domain.com
, shodywww.domain.com
,subdomain.domain.com
nebowww.subdomain.domain.com
na libovolném portu. - Port:
*:5000
Odpovídá portu 5000 s libovolným hostitelem. - Hostitel a port:
www.domain.com:5000
nebo*.domain.com:5000
odpovídá hostiteli a portu.
Lze zadat více parametrů pomocí RequireHost
nebo [Host]
. Omezení odpovídá hostitelům platným pro některý z parametrů. Například [Host("domain.com", "*.domain.com")]
shody domain.com
, www.domain.com
a subdomain.domain.com
.
Následující kód používá RequireHost
k vyžadování zadaného hostitele na trase:
app.MapGet("/", () => "Contoso").RequireHost("contoso.com");
app.MapGet("/", () => "AdventureWorks").RequireHost("adventure-works.com");
app.MapHealthChecks("/healthz").RequireHost("*:8080");
Následující kód používá [Host]
atribut na kontroleru k vyžadování některého ze zadaných hostitelů:
[Host("contoso.com", "adventure-works.com")]
public class HostsController : Controller
{
public IActionResult Index() =>
View();
[Host("example.com")]
public IActionResult Example() =>
View();
}
[Host]
Když se atribut použije na metodu kontroleru i akce:
- Použije se atribut akce.
- Atribut kontroleru je ignorován.
Doprovodné materiály k výkonu pro směrování
Pokud má aplikace problémy s výkonem, směrování se často považuje za problém. Důvodem je podezření, že architektury, jako jsou kontrolery a Razor stránky, hlásí dobu strávenou uvnitř rozhraní v protokolovacích zprávách. Pokud je mezi časem hlášeným kontrolery a celkovým časem požadavku významný rozdíl:
- Vývojáři eliminují kód aplikace jako zdroj problému.
- Běžně se předpokládá, že příčinou je směrování.
Směrování je testované výkonem pomocí tisíců koncových bodů. Je nepravděpodobné, že by typická aplikace narazila na problém s výkonem jenom tím, že je příliš velká. Nejčastější hlavní příčinou pomalého směrování je obvykle špatně se chovající vlastní middleware.
Následující ukázka kódu ukazuje základní techniku zúžení zdroje zpoždění:
var logger = app.Services.GetRequiredService<ILogger<Program>>();
app.Use(async (context, next) =>
{
var stopwatch = Stopwatch.StartNew();
await next(context);
stopwatch.Stop();
logger.LogInformation("Time 1: {ElapsedMilliseconds}ms", stopwatch.ElapsedMilliseconds);
});
app.UseRouting();
app.Use(async (context, next) =>
{
var stopwatch = Stopwatch.StartNew();
await next(context);
stopwatch.Stop();
logger.LogInformation("Time 2: {ElapsedMilliseconds}ms", stopwatch.ElapsedMilliseconds);
});
app.UseAuthorization();
app.Use(async (context, next) =>
{
var stopwatch = Stopwatch.StartNew();
await next(context);
stopwatch.Stop();
logger.LogInformation("Time 3: {ElapsedMilliseconds}ms", stopwatch.ElapsedMilliseconds);
});
app.MapGet("/", () => "Timing Test.");
Směrování podle času:
- Prokládání každého middlewaru pomocí kopie middlewaru časování zobrazeného v předchozím kódu.
- Přidejte jedinečný identifikátor pro korelaci dat časování s kódem.
Jedná se o základní způsob, jak zúžit zpoždění, pokud je významné, například více než 10ms
. Odečítá Time 2
se od Time 1
sestav čas strávený v middlewaru UseRouting
.
Následující kód používá kompaktnější přístup k předchozímu kódu časování:
public sealed class AutoStopwatch : IDisposable
{
private readonly ILogger _logger;
private readonly string _message;
private readonly Stopwatch _stopwatch;
private bool _disposed;
public AutoStopwatch(ILogger logger, string message) =>
(_logger, _message, _stopwatch) = (logger, message, Stopwatch.StartNew());
public void Dispose()
{
if (_disposed)
{
return;
}
_logger.LogInformation("{Message}: {ElapsedMilliseconds}ms",
_message, _stopwatch.ElapsedMilliseconds);
_disposed = true;
}
}
var logger = app.Services.GetRequiredService<ILogger<Program>>();
var timerCount = 0;
app.Use(async (context, next) =>
{
using (new AutoStopwatch(logger, $"Time {++timerCount}"))
{
await next(context);
}
});
app.UseRouting();
app.Use(async (context, next) =>
{
using (new AutoStopwatch(logger, $"Time {++timerCount}"))
{
await next(context);
}
});
app.UseAuthorization();
app.Use(async (context, next) =>
{
using (new AutoStopwatch(logger, $"Time {++timerCount}"))
{
await next(context);
}
});
app.MapGet("/", () => "Timing Test.");
Potenciálně nákladné funkce směrování
Následující seznam obsahuje přehled o funkcích směrování, které jsou relativně drahé v porovnání se základními šablonami tras:
- Regulární výrazy: Je možné psát regulární výrazy, které jsou složité nebo mají dlouhou dobu trvání s malým množstvím vstupu.
- Komplexní segmenty (
{x}-{y}-{z}
):- Jsou výrazně dražší než analýza běžného segmentu cesty URL.
- Výsledkem je přidělení mnoha dalších podřetěžců.
- Synchronní přístup k datům: Mnoho složitých aplikací má v rámci směrování přístup k databázi. Použijte body rozšiřitelnosti, například MatcherPolicy a EndpointSelectorContext, které jsou asynchronní.
Pokyny pro velké směrovací tabulky
Ve výchozím nastavení ASP.NET Core používá algoritmus směrování, který obchoduje s pamětí za čas procesoru. To má pěkný účinek, že čas porovnávání tras závisí pouze na délce cesty, která se má shodovat, a ne na počtu tras. Tento přístup ale může být v některých případech problematický, když má aplikace velký počet tras (v tisících) a v trasách existuje velké množství předpon proměnných. Například pokud trasy mají parametry v počátečních segmentech trasy, například {parameter}/some/literal
.
Je nepravděpodobné, že by aplikace narazila na situaci, kdy se jedná o problém, pokud:
- V aplikaci existuje velký počet tras, které tento model používají.
- V aplikaci je velký počet tras.
Jak zjistit, jestli aplikace narazí na problém s velkou směrovací tabulkou
- Existují dva příznaky, které je třeba hledat:
- Aplikace se pomalu spustí při prvním požadavku.
- Mějte na paměti, že je to povinné, ale nestačí. Existuje mnoho dalších problémů, které se nesměrují, než může způsobit pomalé spuštění aplikace. Zkontrolujte níže uvedený stav, abyste přesně zjistili, jestli aplikace v této situaci neběží.
- Aplikace během spouštění spotřebovává velké množství paměti a výpis paměti zobrazuje velký počet
Microsoft.AspNetCore.Routing.Matching.DfaNode
instancí.
- Aplikace se pomalu spustí při prvním požadavku.
Jak tento problém vyřešit
U tras lze použít několik technik a optimalizací, které tento scénář z velké části zlepší:
- Pokud je to možné, použijte omezení trasy na parametry, například
{parameter:int}
{parameter:guid}
,{parameter:regex(\\d+)}
, atd.- To umožňuje algoritmus směrování interně optimalizovat struktury používané pro porovnávání a výrazně snížit využitou paměť.
- Ve většině případů to stačí, abyste se vrátili k přijatelnému chování.
- Změňte trasy tak, aby se parametry přesunuly do pozdějších segmentů v šabloně.
- Tím se sníží počet možných cest tak, aby odpovídal koncovému bodu dané cestě.
- Použijte dynamickou trasu a dynamicky proveďte mapování na kontroler nebo stránku.
- Toho lze dosáhnout pomocí
MapDynamicControllerRoute
aMapDynamicPageRoute
.
- Toho lze dosáhnout pomocí
Pokyny pro autory knihoven
Tato část obsahuje pokyny pro autory knihoven, kteří vycházejí ze směrování. Cílem těchto podrobností je zajistit, aby vývojáři aplikací měli dobré zkušenosti s používáním knihoven a architektur, které rozšiřují směrování.
Definování koncových bodů
Pokud chcete vytvořit architekturu, která používá směrování pro porovnávání adres URL, začněte definováním uživatelského prostředí, které je postavené na UseEndpoints.
DO staví na vrcholu IEndpointRouteBuilder. To umožňuje uživatelům vytvářet architekturu s jinými funkcemi ASP.NET Core bez nejasností. Každá šablona ASP.NET Core zahrnuje směrování. Předpokládejme, že směrování je pro uživatele k dispozici a známé.
// Your framework
app.MapMyFramework(...);
app.MapHealthChecks("/healthz");
DO vrátit zapečetěný beton typ z volání MapMyFramework(...)
, které implementuje IEndpointConventionBuilder. Většina metod architektury Map...
tento vzor dodržuje. Rozhraní IEndpointConventionBuilder
:
- Umožňuje složená metadata.
- Cílí na různé rozšiřující metody.
Deklarování vlastního typu umožňuje do tvůrce přidat vlastní funkce specifické pro architekturu. Je v pořádku zabalit tvůrce deklarovaného architekturou a předat do něj volání.
// Your framework
app.MapMyFramework(...)
.RequireAuthorization()
.WithMyFrameworkFeature(awesome: true);
app.MapHealthChecks("/healthz");
ZVAŽTE psaní vlastního EndpointDataSource. EndpointDataSource
je primitivní úroveň nízké úrovně pro deklarování a aktualizaci kolekce koncových bodů. EndpointDataSource
je výkonné rozhraní API používané kontrolery a Razor stránkami.
Testy směrování mají základní příklad neaktualizuje zdroje dat.
VE výchozím nastavení se nepokoušejte EndpointDataSource
o registraci. Vyžadovat, aby uživatelé zaregistrovali vaši architekturu v UseEndpoints. Filozofie směrování spočívá v tom, že ve výchozím nastavení se nic nezahrnuje a je to UseEndpoints
místo pro registraci koncových bodů.
Vytvoření middlewaru integrovaného se směrováním
ZVAŽTE definování typů metadat jako rozhraní.
Umožňuje použít typy metadat jako atribut tříd a metod.
public interface ICoolMetadata
{
bool IsCool { get; }
}
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
public class CoolMetadataAttribute : Attribute, ICoolMetadata
{
public bool IsCool => true;
}
Architektury, jako jsou kontrolery a Razor stránky, podporují použití atributů metadat na typy a metody. Pokud deklarujete typy metadat:
- Zpřístupní je jako atributy.
- Většina uživatelů má zkušenosti s používáním atributů.
Deklarace typu metadat jako rozhraní přidává další vrstvu flexibility:
- Rozhraní jsou kompozibilní.
- Vývojáři můžou deklarovat své vlastní typy, které kombinují více zásad.
Umožňuje přepsat metadata, jak je znázorněno v následujícím příkladu:
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
public class SuppressCoolMetadataAttribute : Attribute, ICoolMetadata
{
public bool IsCool => false;
}
[CoolMetadata]
public class MyController : Controller
{
public void MyCool() { }
[SuppressCoolMetadata]
public void Uncool() { }
}
Nejlepší způsob, jak postupovat podle těchto pokynů, je vyhnout se definování metadat značek:
- Nehledáte jenom přítomnost typu metadat.
- Definujte vlastnost metadat a zkontrolujte vlastnost.
Kolekce metadat je seřazená a podporuje přepsání podle priority. V případě kontrolerů jsou metadata pro metodu akce nejvýraznější.
Do make middleware užitečný s a bez směrování:
app.UseAuthorization(new AuthorizationPolicy() { ... });
// Your framework
app.MapMyFramework(...).RequireAuthorization();
Jako příklad tohoto návodu UseAuthorization
zvažte middleware. Middleware pro autorizaci umožňuje předávat záložní zásady. Záložní zásada, pokud je zadaná, platí pro obě:
- Koncové body bez zadané zásady
- Požadavky, které neodpovídají koncovému bodu.
Díky tomu je middleware autorizace užitečný mimo kontext směrování. Autorizační middleware lze použít pro tradiční programování middlewaru.
Ladění diagnostiky
Podrobný výstup diagnostiky směrování nastavíte Logging:LogLevel:Microsoft
na Debug
hodnotu . Ve vývojovém prostředí nastavte úroveň protokolu v appsettings.Development.json
:
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Debug",
"Microsoft.Hosting.Lifetime": "Information"
}
}
}
Další materiály
Směrování zodpovídá za porovnávání příchozích požadavků HTTP a odesílání těchto požadavků do spustitelných koncových bodů aplikace. Koncové body jsou jednotky spustitelného kódu zpracování požadavků. Koncové body se definují v aplikaci a konfigurují se při spuštění aplikace. Proces porovnávání koncových bodů může extrahovat hodnoty z adresy URL požadavku a poskytnout tyto hodnoty pro zpracování požadavků. Pomocí informací o koncovém bodu z aplikace je směrování také schopné generovat adresy URL, které se mapují na koncové body.
Aplikace můžou nakonfigurovat směrování pomocí:
- Kontrolery
- Razor Pages
- SignalR
- gRPC Services
- Middleware s povoleným koncovým bodem, jako jsou kontroly stavu.
- Delegáti a lambda zaregistrované ve směrování
Tento dokument popisuje podrobnosti nízké úrovně směrování ASP.NET Core. Informace o konfiguraci směrování:
- Informace o kontroleru najdete v tématu Směrování na akce kontroleru v ASP.NET Core.
- Konvence Razor stránek najdete v tématu Razor Stránky trasy a konvence aplikací v ASP.NET Core.
Systém směrování koncových bodů popsaný v tomto dokumentu platí pro ASP.NET Core 3.0 a novější. Informace o předchozím systému směrování založeném na IRouternástroji , vyberte verzi ASP.NET Core 2.1 pomocí jednoho z následujících přístupů:
- Selektor verzí pro předchozí verzi.
- Vyberte směrování ASP.NET Core 2.1.
Zobrazení nebo stažení ukázkového kódu (postup stažení)
Ukázky stahování pro tento dokument jsou povoleny konkrétní Startup
třídou. Pokud chcete spustit konkrétní ukázku, upravte Program.cs
volání požadované Startup
třídy.
Základy směrování
Všechny šablony ASP.NET Core zahrnují směrování do vygenerovaného kódu. Směrování je registrováno v kanálu middlewaru v Startup.Configure
.
Následující kód ukazuje základní příklad směrování:
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseRouting();
app.UseEndpoints(endpoints =>
{
endpoints.MapGet("/", async context =>
{
await context.Response.WriteAsync("Hello World!");
});
});
}
Směrování používá dvojici middlewaru, zaregistrovaného uživatelem UseRouting a UseEndpoints:
UseRouting
přidá trasu odpovídající kanálu middlewaru. Tento middleware se podívá na sadu koncových bodů definovaných v aplikaci a vybere nejlepší shodu na základě požadavku.UseEndpoints
přidá spuštění koncového bodu do kanálu middlewaru. Spustí delegáta přidruženého k vybranému koncovému bodu.
Předchozí příklad obsahuje jednu trasu ke koncovému bodu kódu pomocí metody MapGet :
- Při odeslání požadavku HTTP
GET
na kořenovou adresu URL/
:- Spustí se delegát požadavku.
Hello World!
je zapsán do odpovědi HTTP. Ve výchozím nastavení jehttps://localhost:5001/
kořenová adresa URL/
.
- Pokud metoda požadavku není
GET
nebo kořenová adresa URL není/
, žádná trasa neodpovídá a vrátí se http 404.
Koncový bod
Metoda MapGet
se používá k definování koncového bodu. Koncový bod je něco, co může být:
- Vybráno tak, že se shoduje s adresou URL a metodou HTTP.
- Spustí se spuštěním delegáta.
Koncové body, které se dají spárovat a spouštět aplikací, jsou nakonfigurované v UseEndpoints
. Například MapGet, MapPosta podobné metody připojit žádosti delegáty do systému směrování. Další metody lze použít k připojení funkcí architektury ASP.NET Core ke směrovacímu systému:
- MapRazorPages for Razor Pages
- MapControllers pro kontrolery
- MapHub THub<> forSignalR
- MapGrpcService TService<> pro gRPC
Následující příklad ukazuje směrování s sofistikovanější šablonou trasy:
app.UseEndpoints(endpoints =>
{
endpoints.MapGet("/hello/{name:alpha}", async context =>
{
var name = context.Request.RouteValues["name"];
await context.Response.WriteAsync($"Hello {name}!");
});
});
Řetězec /hello/{name:alpha}
je šablona trasy. Slouží ke konfiguraci shody koncového bodu. V tomto případě šablona odpovídá:
- Adresa URL, jako je
/hello/Ryan
- Všechny cesty URL, které začínají
/hello/
posloupností abecedních znaků.:alpha
použije omezení trasy, které odpovídá pouze abecedním znakům. Omezení tras jsou vysvětlena dále v tomto dokumentu.
Druhý segment cesty URL: {name:alpha}
- Je vázán na
name
parametr. - Je zachycen a uložen v HttpRequest.RouteValues.
Systém směrování koncových bodů popsaný v tomto dokumentu je od ASP.NET Core 3.0 nový. Všechny verze ASP.NET Core ale podporují stejnou sadu funkcí šablon tras a omezení tras.
Následující příklad ukazuje směrování s kontrolami stavu a autorizací:
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
// Matches request to an endpoint.
app.UseRouting();
// Endpoint aware middleware.
// Middleware can use metadata from the matched endpoint.
app.UseAuthentication();
app.UseAuthorization();
// Execute the matched endpoint.
app.UseEndpoints(endpoints =>
{
// Configure the Health Check endpoint and require an authorized user.
endpoints.MapHealthChecks("/healthz").RequireAuthorization();
// Configure another endpoint, no authorization requirements.
endpoints.MapGet("/", async context =>
{
await context.Response.WriteAsync("Hello World!");
});
});
}
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.
Předchozí příklad ukazuje, jak:
- S směrováním je možné použít autorizační middleware.
- Koncové body je možné použít ke konfiguraci chování autorizace.
Volání MapHealthChecks přidá koncový bod kontroly stavu. Při zřetězování RequireAuthorization k tomuto volání se ke koncovému bodu připojí zásady autorizace.
Volání UseAuthentication a UseAuthorization přidání middlewaru pro ověřování a autorizaci Tyto middleware jsou umístěny mezi UseRouting a UseEndpoints
tak, aby mohly:
- Podívejte se, který koncový bod vybral
UseRouting
. - Před odesláním do koncového bodu použijte zásadu UseEndpoints autorizace.
Metadata koncového bodu
V předchozím příkladu existují dva koncové body, ale k autorizační zásadě jsou připojené jenom koncové body kontroly stavu. Pokud požadavek odpovídá koncovému bodu kontroly stavu, /healthz
provede se kontrola autorizace. To ukazuje, že koncové body můžou mít připojená další data. Tato další data se nazývají metadata koncového bodu:
- Metadata je možné zpracovat pomocí middlewaru pracujícího se směrováním.
- Metadata můžou být libovolného typu .NET.
Koncepty směrování
Systém směrování vychází z kanálu middlewaru přidáním výkonného konceptu koncového bodu . Koncové body představují jednotky funkcí aplikace, které se vzájemně liší z hlediska směrování, autorizace a libovolného počtu systémů ASP.NET Core.
Definice koncového bodu ASP.NET Core
Koncový bod ASP.NET Core je:
- Spustitelný soubor: Má .RequestDelegate
- Rozšiřitelný: Má kolekci metadat .
- Možnost výběru: Volitelně obsahuje informace o směrování.
- Výčet: Kolekci koncových bodů je možné uvést načtením EndpointDataSource z DI.
Následující kód ukazuje, jak načíst a zkontrolovat koncový bod odpovídající aktuálnímu požadavku:
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseRouting();
app.Use(next => context =>
{
var endpoint = context.GetEndpoint();
if (endpoint is null)
{
return Task.CompletedTask;
}
Console.WriteLine($"Endpoint: {endpoint.DisplayName}");
if (endpoint is RouteEndpoint routeEndpoint)
{
Console.WriteLine("Endpoint has route pattern: " +
routeEndpoint.RoutePattern.RawText);
}
foreach (var metadata in endpoint.Metadata)
{
Console.WriteLine($"Endpoint has metadata: {metadata}");
}
return Task.CompletedTask;
});
app.UseEndpoints(endpoints =>
{
endpoints.MapGet("/", async context =>
{
await context.Response.WriteAsync("Hello World!");
});
});
}
Koncový bod, pokud je vybraný, lze načíst z objektu HttpContext
. Jeho vlastnosti je možné zkontrolovat. Objekty koncového bodu jsou neměnné a po vytvoření není možné je změnit. Nejběžnějším typem RouteEndpointkoncového bodu je . RouteEndpoint
obsahuje informace, které mu umožní vybrat směrovací systém.
V předchozím kódu aplikace. Slouží ke konfiguraci in-line middlewaru.
Následující kód ukazuje, že v závislosti na tom, kde app.Use
se v kanálu volá, nemusí existovat koncový bod:
// Location 1: before routing runs, endpoint is always null here
app.Use(next => context =>
{
Console.WriteLine($"1. Endpoint: {context.GetEndpoint()?.DisplayName ?? "(null)"}");
return next(context);
});
app.UseRouting();
// Location 2: after routing runs, endpoint will be non-null if routing found a match
app.Use(next => context =>
{
Console.WriteLine($"2. Endpoint: {context.GetEndpoint()?.DisplayName ?? "(null)"}");
return next(context);
});
app.UseEndpoints(endpoints =>
{
// Location 3: runs when this endpoint matches
endpoints.MapGet("/", context =>
{
Console.WriteLine(
$"3. Endpoint: {context.GetEndpoint()?.DisplayName ?? "(null)"}");
return Task.CompletedTask;
}).WithDisplayName("Hello");
});
// Location 4: runs after UseEndpoints - will only run if there was no match
app.Use(next => context =>
{
Console.WriteLine($"4. Endpoint: {context.GetEndpoint()?.DisplayName ?? "(null)"}");
return next(context);
});
Tato předchozí ukázka přidá Console.WriteLine
příkazy, které zobrazují, jestli byl vybrán koncový bod nebo ne. Pro přehlednost ukázka přiřadí zadaný koncový bod zobrazovaný název /
.
Spuštění tohoto kódu s adresou URL /
zobrazení:
1. Endpoint: (null)
2. Endpoint: Hello
3. Endpoint: Hello
Spuštění tohoto kódu s jakoukoli jinou adresou URL zobrazí:
1. Endpoint: (null)
2. Endpoint: (null)
4. Endpoint: (null)
Tento výstup ukazuje, že:
- Koncový bod je před zavolání vždy null
UseRouting
. - Pokud se najde shoda, koncový bod je mezi
UseRouting
a UseEndpoints. - Middleware
UseEndpoints
je terminál , když se najde shoda. Middleware terminálu je definován dále v tomto dokumentu. - Middleware po spuštění pouze v
UseEndpoints
případě, že nebyla nalezena žádná shoda.
Middleware UseRouting
používá metodu SetEndpoint k připojení koncového bodu k aktuálnímu kontextu. Middleware je možné nahradit UseRouting
vlastní logikou a přesto získat výhody používání koncových bodů. Koncové body jsou primitivní nízké úrovně, jako je middleware, a nejsou svázané s implementací směrování. Většina aplikací nemusí nahradit UseRouting
vlastní logikou.
Middleware UseEndpoints
je navržený tak, aby se používal společně s middlewarem UseRouting
. Základní logika pro spuštění koncového bodu není složitá. Slouží GetEndpoint k načtení koncového bodu a následnému vyvolání jeho RequestDelegate vlastnosti.
Následující kód ukazuje, jak může middleware ovlivnit nebo reagovat na směrování:
public class IntegratedMiddlewareStartup
{
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
// Location 1: Before routing runs. Can influence request before routing runs.
app.UseHttpMethodOverride();
app.UseRouting();
// Location 2: After routing runs. Middleware can match based on metadata.
app.Use(next => context =>
{
var endpoint = context.GetEndpoint();
if (endpoint?.Metadata.GetMetadata<AuditPolicyAttribute>()?.NeedsAudit
== true)
{
Console.WriteLine($"ACCESS TO SENSITIVE DATA AT: {DateTime.UtcNow}");
}
return next(context);
});
app.UseEndpoints(endpoints =>
{
endpoints.MapGet("/", async context =>
{
await context.Response.WriteAsync("Hello world!");
});
// Using metadata to configure the audit policy.
endpoints.MapGet("/sensitive", async context =>
{
await context.Response.WriteAsync("sensitive data");
})
.WithMetadata(new AuditPolicyAttribute(needsAudit: true));
});
}
}
public class AuditPolicyAttribute : Attribute
{
public AuditPolicyAttribute(bool needsAudit)
{
NeedsAudit = needsAudit;
}
public bool NeedsAudit { get; }
}
Předchozí příklad ukazuje dva důležité koncepty:
- Middleware se může spustit před
UseRouting
úpravou dat, se kterými směrování pracuje.- Obvykle middleware, který se zobrazí před úpravou směrování některé vlastnosti požadavku, například UseRewriter, UseHttpMethodOverridenebo UsePathBase.
- Middleware se může spustit mezi
UseRouting
směrováním a UseEndpoints zpracovat výsledky směrování před spuštěním koncového bodu.- Middleware, který běží mezi
UseRouting
aUseEndpoints
:- Obvykle kontroluje metadata, aby porozuměla koncovým bodům.
- Často provádí rozhodnutí o zabezpečení, jak to dělá
UseAuthorization
aUseCors
.
- Kombinace middlewaru a metadat umožňuje konfigurovat zásady pro jednotlivé koncové body.
- Middleware, který běží mezi
Předchozí kód ukazuje příklad vlastního middlewaru, který podporuje zásady pro jednotlivé koncové body. Middleware zapíše protokol auditu přístupu k citlivým datům do konzoly. Middleware je možné nakonfigurovat tak, aby auditoval koncový bod s AuditPolicyAttribute
metadaty. Tato ukázka ukazuje způsob vyjádření výslovného souhlasu, kdy se auditují jenom koncové body označené jako citlivé. Tuto logiku je možné definovat obráceně, auditovat všechno, co není označené jako bezpečné, například. Systém metadat koncového bodu je flexibilní. Tato logika by mohla být navržena jakýmkoli způsobem, který vyhovuje případu použití.
Předchozí vzorový kód je určený k předvedení základních konceptů koncových bodů. Ukázka není určená pro produkční použití. Ucelenější verze middlewaru protokolu auditu:
- Přihlaste se k souboru nebo databázi.
- Uveďte podrobnosti, jako je uživatel, IP adresa, název citlivého koncového bodu a další.
Metadata zásad auditu jsou definována AuditPolicyAttribute
jako Attribute
jednodušší použití s architekturami založenými na třídách, jako jsou kontrolery a SignalR. Při použití trasy ke kódu:
- Metadata jsou připojena pomocí rozhraní API tvůrce.
- Architektury založené na třídách zahrnují všechny atributy odpovídající metody a třídy při vytváření koncových bodů.
Osvědčenými postupy pro typy metadat je definovat buď jako rozhraní, nebo atributy. Rozhraní a atributy umožňují opakované použití kódu. Systém metadat je flexibilní a neukládá žádná omezení.
Porovnání middlewaru terminálu a směrování
Následující ukázka kódu kontrastuje pomocí middlewaru se směrováním:
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
// Approach 1: Writing a terminal middleware.
app.Use(next => async context =>
{
if (context.Request.Path == "/")
{
await context.Response.WriteAsync("Hello terminal middleware!");
return;
}
await next(context);
});
app.UseRouting();
app.UseEndpoints(endpoints =>
{
// Approach 2: Using routing.
endpoints.MapGet("/Movie", async context =>
{
await context.Response.WriteAsync("Hello routing!");
});
});
}
Styl middlewaru zobrazeného s terminálovým middlewarem Approach 1:
. Říká se tomu middleware terminálu, protože dělá odpovídající operaci:
- Odpovídající operace v předchozí ukázce je
Path == "/"
pro middleware aPath == "/Movie"
pro směrování. - Když je shoda úspěšná, spustí některé funkce a vrátí se místo vyvolání middlewaru
next
.
Říká se tomu middleware terminálu, protože ukončí hledání, spustí některé funkce a vrátí se.
Porovnání middlewaru terminálu a směrování:
- Oba přístupy umožňují ukončení kanálu zpracování:
- Middleware ukončí kanál tím, že se místo vyvolání
next
. - Koncové body jsou vždy terminálové.
- Middleware ukončí kanál tím, že se místo vyvolání
- Middleware terminálu umožňuje umístění middlewaru na libovolné místo v kanálu:
- Koncové body se provádějí na pozici UseEndpoints.
- Middleware terminálu umožňuje libovolnému kódu určit, kdy middleware odpovídá:
- Vlastní kód pro porovnávání tras může být podrobný a obtížně zapisuje správně.
- Směrování poskytuje jednoduchá řešení pro typické aplikace. Většina aplikací nevyžaduje vlastní kód pro porovnávání tras.
- Rozhraní koncových bodů s middlewarem, jako
UseAuthorization
je například aUseCors
.- Použití middlewaru terminálu s
UseAuthorization
autorizačním systémem neboUseCors
vyžaduje ruční propojení se systémem autorizace.
- Použití middlewaru terminálu s
Koncový bod definuje obojí:
- Delegát na zpracování požadavků.
- Kolekce libovolných metadat. Metadata se používají k implementaci průřezových aspektů na základě zásad a konfigurace připojených k jednotlivým koncovým bodům.
Terminálový middleware může být efektivní nástroj, ale může vyžadovat:
- Značné množství kódování a testování.
- Ruční integrace s jinými systémy za účelem dosažení požadované úrovně flexibility.
Před zápisem middlewaru terminálu zvažte integraci se směrováním.
Existující middleware terminálu, který se integruje s mapou , nebo MapWhen se obvykle dá převést na koncový bod podporující směrování. MapHealthChecks ukazuje vzor pro router-ware:
- Napište metodu rozšíření na IEndpointRouteBuilder.
- Vytvoření vnořeného kanálu middlewaru pomocí CreateApplicationBuilder.
- Připojte middleware k novému kanálu. V tomto případě . UseHealthChecks
- Buildmiddlewarový kanál do .RequestDelegate
- Zavolejte a poskytněte
Map
nový kanál middlewaru. - Vrátí objekt tvůrce poskytnutý
Map
metodou rozšíření.
Následující kód ukazuje použití MapHealthChecks:
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
// Matches request to an endpoint.
app.UseRouting();
// Endpoint aware middleware.
// Middleware can use metadata from the matched endpoint.
app.UseAuthentication();
app.UseAuthorization();
// Execute the matched endpoint.
app.UseEndpoints(endpoints =>
{
// Configure the Health Check endpoint and require an authorized user.
endpoints.MapHealthChecks("/healthz").RequireAuthorization();
// Configure another endpoint, no authorization requirements.
endpoints.MapGet("/", async context =>
{
await context.Response.WriteAsync("Hello World!");
});
});
}
Předchozí ukázka ukazuje, proč je vrácení objektu tvůrce důležité. Vrácení objektu tvůrce umožňuje vývojáři aplikací konfigurovat zásady, jako je autorizace pro koncový bod. V tomto příkladu nemá middleware kontroly stavu žádnou přímou integraci se systémem autorizace.
Systém metadat byl vytvořen v reakci na problémy zjištěné autory rozšiřitelnosti pomocí middlewaru terminálu. Pro každý middleware je problematické implementovat vlastní integraci s autorizačním systémem.
Porovnávání adres URL
- Je proces, kterým směrování odpovídá příchozímu požadavku na koncový bod.
- Je založená na datech v cestě URL a hlavičkách.
- Můžete ho rozšířit, abyste zvážili všechna data v požadavku.
Když se spustí middleware směrování, nastaví Endpoint
hodnotu požadavku na funkci HttpContext požadavku z aktuálního požadavku:
- Volání httpContext.GetEndpoint získá koncový bod.
HttpRequest.RouteValues
získá kolekci hodnot tras.
Middleware se spustí po spuštění middlewaru směrování, který může zkontrolovat koncový bod a provést akci. Například autorizační middleware může probrat kolekci metadat koncového bodu pro zásady autorizace. Po spuštění veškerého middlewaru v kanálu zpracování požadavků se vyvolá delegát vybraného koncového bodu.
Systém směrování ve směrování koncového bodu zodpovídá za veškerá rozhodnutí o odesílání. Vzhledem k tomu, že middleware používá zásady na základě vybraného koncového bodu, je důležité, aby:
- Jakékoli rozhodnutí, které může ovlivnit odesílání nebo použití zásad zabezpečení, se provádí v rámci systému směrování.
Upozorňující
V případě zpětné kompatibility jsou při spuštění delegáta koncového bodu kontroleru nebo Razor stránky vlastnosti RouteContext.RouteData nastaveny na odpovídající hodnoty na základě dosud provedeného zpracování požadavků.
Typ RouteContext
bude v budoucí verzi označen jako zastaralý:
- Migrovat
RouteData.Values
naHttpRequest.RouteValues
. - Migrujte
RouteData.DataTokens
a načtěte IDataTokensMetadata z metadat koncového bodu.
Porovnávání adres URL funguje v konfigurovatelné sadě fází. V každé fázi je výstup sadou shod. Sadu shod lze dále zúžit v další fázi. Implementace směrování nezaručuje pořadí zpracování pro odpovídající koncové body. Všechny možné shody se zpracovávají najednou. Fáze porovnávání adres URL probíhají v následujícím pořadí. ASP.NET Core:
- Zpracovává cestu URL vůči sadě koncových bodů a jejich šablon tras a shromažďuje všechny shody.
- Vezme předchozí seznam a odebere shody, které selžou s použitými omezeními trasy.
- Vezme předchozí seznam a odebere shody, které selžou sadu instancí MatcherPolicy .
- Pomocí endpointSelectoru provede konečné rozhodnutí z předchozího seznamu.
Seznam koncových bodů má prioritu podle následujících:
- RouteEndpoint.Order
- Priorita šablony trasy
Všechny odpovídající koncové body se zpracovávají v každé fázi, dokud se nedosáhne EndpointSelector . Jedná se EndpointSelector
o konečnou fázi. Jako nejlepší shodu zvolí koncový bod s nejvyšší prioritou. Pokud existují jiné shody se stejnou prioritou jako nejlepší shoda, vyvolá se výjimka nejednoznačné shody.
Priorita trasy se vypočítá na základě konkrétnější šablony trasy, která má vyšší prioritu. Představte si například šablony /hello
a /{message}
:
- Obě odpovídají cestě
/hello
URL . /hello
je konkrétnější a proto vyšší priorita.
Obecně platí, že priorita trasy má dobrou úlohu při výběru nejvhodnější shody pro druhy schémat adres URL používaných v praxi. Používejte Order pouze v případě potřeby, abyste se vyhnuli nejednoznačnosti.
Vzhledem k druhům rozšiřitelnosti poskytované směrováním není možné, aby směrovací systém předem počítaly nejednoznačné trasy. Představte si příklad, jako jsou šablony /{message:alpha}
tras a /{message:int}
:
- Omezení
alpha
odpovídá pouze abecedním znakům. - Omezení
int
odpovídá pouze číslu. - Tyto šablony mají stejnou prioritu tras, ale obě adresy URL se neshodují.
- Pokud systém směrování nahlásil při spuštění nejednoznačnosti, zablokoval by tento platný případ použití.
Upozorňující
Pořadí operací uvnitř UseEndpoints nemá vliv na chování směrování, s jednou výjimkou. MapControllerRoute a MapAreaRoute automaticky přiřadí hodnotu objednávky ke svým koncovým bodům na základě pořadí, ve které jsou vyvolány. To simuluje dlouhodobé chování kontrolerů bez systému směrování, který poskytuje stejné záruky jako starší implementace směrování.
Ve starší implementaci směrování je možné implementovat rozšiřitelnost směrování, která má závislost na pořadí, ve kterém se trasy zpracovávají. Směrování koncových bodů v ASP.NET Core 3.0 a novější:
- Nemá koncept tras.
- Neposkytuje záruky objednávání. Všechny koncové body se zpracovávají najednou.
Priorita šablony trasy a pořadí výběru koncového bodu
Priorita šablony trasy je systém, který každé šabloně trasy přiřadí hodnotu na základě toho, jak je konkrétní. Priorita šablony trasy:
- Vyhne se nutnosti upravovat pořadí koncových bodů v běžných případech.
- Snaží se shodovat s očekáváními obecného chování směrování.
Představte si například šablony /Products/List
a /Products/{id}
. Bylo by rozumné předpokládat, že /Products/List
je lepší shoda než /Products/{id}
pro cestu /Products/List
URL . To funguje, protože literálový segment /List
je považován za lepší prioritu než segment /{id}
parametru .
Podrobnosti o tom, jak funguje priorita, jsou svázány s tím, jak se definují šablony tras:
- Šablony s více segmenty jsou považovány za konkrétnější.
- Segment s literálovým textem se považuje za konkrétnější než segment parametru.
- Segment parametru s omezením se považuje za konkrétnější než jeden bez.
- Složitý segment se považuje za specifický jako segment parametru s omezením.
- Parametry pro zachytávání jsou nejmíň specifické. Důležité informaceoch
Referenční informace o přesných hodnotách najdete ve zdrojovém kódu na GitHubu .
Koncepty generování adres URL
Generování adres URL:
- Je proces, pomocí kterého směrování může vytvořit cestu URL na základě sady hodnot tras.
- Umožňuje logické oddělení mezi koncovými body a adresami URL, které k nim přistupují.
Směrování koncových bodů zahrnuje LinkGenerator rozhraní API. LinkGenerator
je jednoúčelová služba, která je k dispozici z DI. Rozhraní LinkGenerator
API se dá použít mimo kontext spuštěného požadavku. Mvc.IUrlHelper a scénáře, které se spoléhají , IUrlHelperjako jsou pomocné rutiny značek, pomocné rutiny HTML a výsledky akcí, používají LinkGenerator
rozhraní API interně k poskytování možností generování odkazů.
Generátor odkazů je podporován konceptem adresního a adresního schématu. Schéma adres je způsob, jak určit koncové body, které by se měly zvážit pro generování propojení. Například scénáře názvu trasy a směrovacích hodnot, které mnoho uživatelů znáte z kontrolerů a Razor Stránky se implementují jako schéma adres.
Generátor odkazů může odkazovat na kontrolery a Razor stránky pomocí následujících rozšiřujících metod:
Přetížení těchto metod přijímají argumenty, které zahrnují HttpContext
. Tyto metody jsou funkčně ekvivalentní url.Action a Url.Page, ale nabízejí další flexibilitu a možnosti.
Metody GetPath*
jsou nejvíce podobné Url.Action
a Url.Page
v tom, že vygenerují identifikátor URI obsahující absolutní cestu. Metody GetUri*
vždy generují absolutní identifikátor URI obsahující schéma a hostitele. Metody, které přijímají HttpContext
vygenerování identifikátoru URI v kontextu prováděcího požadavku. Hodnoty okolní trasy, základní cesta URL, schéma a hostitel ze spuštěného požadavku se použijí, pokud je nepřepíšete.
LinkGenerator je volána s adresou. Generování identifikátoru URI probíhá ve dvou krocích:
- Adresa je svázaná se seznamem koncových bodů, které odpovídají adrese.
- Vyhodnocuje se RoutePattern každý koncový bod, dokud se nenajde vzor trasy, který odpovídá zadaným hodnotám. Výsledný výstup se zkombinuje s ostatními částmi identifikátoru URI zadanými do generátoru propojení a vrátí se.
Metody poskytované standardními možnostmi LinkGenerator generování propojení pro libovolný typ adresy. Nejpohodlnější způsob použití generátoru propojení je prostřednictvím rozšiřujících metod, které provádějí operace pro konkrétní typ adresy:
Extension – metoda | Popis |
---|---|
GetPathByAddress | Vygeneruje identifikátor URI s absolutní cestou na základě zadaných hodnot. |
GetUriByAddress | Vygeneruje absolutní identifikátor URI na základě zadaných hodnot. |
Upozorňující
Věnujte pozornost následujícím důsledkům volání LinkGenerator metod:
V konfiguraci aplikace používejte
GetUri*
metody rozšíření s opatrností, která neověřuje hlavičkuHost
příchozích požadavků. Pokud hlavičkaHost
příchozích požadavků není ověřená, může být nedůvěryhodný vstup požadavku odeslán zpět klientovi v identifikátorech URI v zobrazení nebo stránce. Doporučujeme, aby všechny produkční aplikace nakonfigurovaly svůj server tak, aby ověřovaly hlavičkuHost
proti známým platným hodnotám.Používejte LinkGenerator s opatrností v middlewaru v kombinaci s
Map
neboMapWhen
.Map*
změní základní cestu prováděcího požadavku, která má vliv na výstup generování propojení. LinkGenerator Všechna rozhraní API umožňují zadat základní cestu. Zadejte prázdnouMap*
základní cestu, která vrátí zpět vliv na generování propojení.
Příklad middlewaru
V následujícím příkladu middleware používá LinkGenerator rozhraní API k vytvoření odkazu na metodu akce, která obsahuje seznam produktů pro ukládání. Použití generátoru odkazů vložením do třídy a volání GenerateLink
je k dispozici pro libovolnou třídu v aplikaci:
public class ProductsLinkMiddleware
{
private readonly LinkGenerator _linkGenerator;
public ProductsLinkMiddleware(RequestDelegate next, LinkGenerator linkGenerator)
{
_linkGenerator = linkGenerator;
}
public async Task InvokeAsync(HttpContext httpContext)
{
var url = _linkGenerator.GetPathByAction("ListProducts", "Store");
httpContext.Response.ContentType = "text/plain";
await httpContext.Response.WriteAsync($"Go to {url} to see our products.");
}
}
Referenční informace k šabloně trasy
Tokeny v rámci {}
definují parametry trasy, které jsou vázané, pokud se trasa shoduje. V segmentu trasy je možné definovat více než jeden parametr trasy, ale parametry trasy musí být oddělené hodnotou literálu. Například {controller=Home}{action=Index}
není platná trasa, protože neexistuje žádná hodnota literálu mezi {controller}
a {action}
. Parametry trasy musí mít název a mohou mít zadané další atributy.
Literál jiný než směrovací parametry (například {id}
) a oddělovač /
cesty musí odpovídat textu v adrese URL. Porovnávání textu nerozlišuje malá a velká písmena a vychází z dekódované reprezentace cesty adresy URL. Chcete-li se shodovat s oddělovačem {
parametru trasy literálu nebo }
, uchytáte oddělovač opakováním znaku. Například {{
nebo }}
.
Hvězdička *
nebo dvojitá hvězdička **
:
- Lze použít jako předponu parametru trasy pro vazbu na rest identifikátor URI.
- Nazývají se parametry catch-all. Příklad:
blog/{**slug}
- Odpovídá libovolnému identifikátoru
/blog
URI, který začíná a má za ním libovolnou hodnotu. - Následující hodnota
/blog
je přiřazena ke slug směrovací hodnotě.
- Odpovídá libovolnému identifikátoru
Upozorňující
Parametr catch-all může nesprávně odpovídat trasám kvůli chybě při směrování. Aplikace ovlivněné touto chybou mají následující charakteristiky:
- Například trasa pro zachytávání– vše
{**slug}"
- Trasa catch-all neodpovídá požadavkům, které by se měly shodovat.
- Odebráním jiných tras začne fungovat zachytávání všech tras.
Podívejte se na chyby GitHubu 18677 a 16579 , například případy, které tuto chybu narazily.
Oprava výslovného souhlasu s touto chybou je obsažená v sadě .NET Core 3.1.301 SDK a novějších verzích. Následující kód nastaví interní přepínač, který tuto chybu opraví:
public static void Main(string[] args)
{
AppContext.SetSwitch("Microsoft.AspNetCore.Routing.UseCorrectCatchAllBehavior",
true);
CreateHostBuilder(args).Build().Run();
}
// Remaining code removed for brevity.
Parametry catch-all mohou také odpovídat prázdnému řetězci.
Parametr catch-all umisťuje příslušné znaky při použití trasy k vygenerování adresy URL, včetně znaků oddělovače /
cest. Například trasa foo/{*path}
s hodnotami { path = "my/path" }
trasy generuje foo/my%2Fpath
. Všimněte si řídicího lomítka. Pokud chcete znaky oddělovače cest odezvy použít předponu parametru **
trasy. Trasa foo/{**path}
s { path = "my/path" }
vygenerovanými .foo/my/path
Vzory adres URL, které se pokoušejí zachytit název souboru s volitelnou příponou souboru, mají další důležité informace. Představte si například šablonu files/{filename}.{ext?}
. Když hodnoty obou filename
hodnot existují ext
, naplní se obě hodnoty. Pokud v adrese URL existuje jenom hodnota filename
, trasa se shoduje, protože koncové hodnoty .
jsou volitelné. Následující adresy URL odpovídají této trase:
/files/myFile.txt
/files/myFile
Parametry trasy můžou mít výchozí hodnoty určené zadáním výchozí hodnoty za názvem parametru odděleným symbolem rovná se (=
). Například {controller=Home}
definuje Home
jako výchozí hodnotu pro controller
. Výchozí hodnota se použije, pokud v adrese URL parametru není žádná hodnota. Parametry trasy jsou volitelné připojením otazníku (?
) na konec názvu parametru. Například id?
. Rozdíl mezi volitelnými hodnotami a výchozími parametry trasy je:
- Parametr trasy s výchozí hodnotou vždy vytvoří hodnotu.
- Volitelný parametr má hodnotu pouze v případě, že je hodnota poskytována adresou URL požadavku.
Parametry trasy můžou mít omezení, která musí odpovídat hodnotě trasy vázané z adresy URL. Přidání :
a omezení názvu za názvem parametru trasy určuje vložené omezení parametru trasy. Pokud omezení vyžaduje argumenty, jsou za názvem omezení uzavřeny v závorkách (...)
. Více vložených omezení lze zadat připojením jiného :
názvu a názvu omezení.
Název omezení a argumenty se předávají službě IInlineConstraintResolver , aby se vytvořila instance IRouteConstraint , která se má použít při zpracování adresy URL. Například šablona blog/{article:minlength(10)}
trasy určuje minlength
omezení s argumentem 10
. Další informace o omezeních tras a seznamu omezení poskytovaných architekturou najdete v části Odkaz na omezení trasy.
Parametry trasy mohou mít také transformátory parametrů. Transformátory parametrů transformují hodnotu parametru při generování odkazů a odpovídajících akcí a stránek na adresy URL. Stejně jako omezení lze transformátory parametrů přidat do parametru trasy přidáním :
názvu a transformátoru za název parametru trasy. Například šablona blog/{article:slugify}
trasy určuje slugify
transformátor. Další informace o transformátorech parametrů naleznete v části Odkaz transformátoru parametrů.
Následující tabulka ukazuje ukázkové šablony tras a jejich chování:
Šablona trasy | Příklad odpovídajícího identifikátoru URI | Identifikátor URI požadavku... |
---|---|---|
hello |
/hello |
Odpovídá pouze jedné cestě /hello . |
{Page=Home} |
/ |
Odpovídá a nastaví Page na Home . |
{Page=Home} |
/Contact |
Odpovídá a nastaví Page na Contact . |
{controller}/{action}/{id?} |
/Products/List |
Mapuje se na Products kontroler a List akci. |
{controller}/{action}/{id?} |
/Products/Details/123 |
Mapuje se Products na kontroler a Details akci s nastavenouid na hodnotu 123. |
{controller=Home}/{action=Index}/{id?} |
/ |
Mapuje se na kontroler a Index metoduHome . Vlastnost id je ignorována. |
{controller=Home}/{action=Index}/{id?} |
/Products |
Mapuje se na kontroler a Index metoduProducts . Vlastnost id je ignorována. |
Použití šablony je obecně nejjednodušším přístupem ke směrování. Omezení a výchozí hodnoty lze zadat také mimo šablonu trasy.
Komplexní segmenty
Komplexní segmenty se zpracovávají pomocí odpovídajících oddělovačů literálů zprava doleva způsobem, který není greedy . Jedná se například [Route("/a{b}c{d}")]
o složitý segment.
Složité segmenty fungují určitým způsobem, který je potřeba pochopit, aby je bylo možné úspěšně použít. Příklad v této části ukazuje, proč složité segmenty skutečně fungují dobře, když se text oddělovače nezobrazí uvnitř hodnot parametrů. Použití regulárního výrazu a ruční extrahování hodnot je potřeba pro složitější případy.
Upozorňující
Při zpracování System.Text.RegularExpressions nedůvěryhodného vstupu předejte vypršení časového limitu. Uživatel se zlými úmysly může poskytnout vstup, který RegularExpressions
způsobí útok na dostupnost služby. ASP.NET rozhraní API architektury Core, která používají RegularExpressions
vypršení časového limitu.
Toto je souhrn kroků, které směrování provádí pomocí šablony /a{b}c{d}
a cesty /abcd
URL . Slouží |
k vizualizaci fungování algoritmu:
- První literál, zprava doleva, je
c
. Hledá se tedy/abcd
zprava a najde/ab|c|d
. - Vše napravo (
d
) se teď shoduje s parametrem{d}
trasy . - Další literál, zprava doleva, je
a
. Takže/ab|c|d
je prohledáno od místa, kde jsme skončili, paka
je nalezen/|a|b|c|d
. - Hodnota vpravo (
b
) se teď shoduje s parametrem{b}
trasy . - Neexistuje žádný zbývající text a žádná zbývající šablona trasy, takže se jedná o shodu.
Tady je příklad záporného případu, který používá stejnou šablonu /a{b}c{d}
a cestu /aabcd
URL . Slouží |
k vizualizaci fungování algoritmu. Tento případ není shoda, která je vysvětlená stejným algoritmem:
- První literál, zprava doleva, je
c
. Hledá se tedy/aabcd
zprava a najde/aab|c|d
. - Vše napravo (
d
) se teď shoduje s parametrem{d}
trasy . - Další literál, zprava doleva, je
a
. Takže/aab|c|d
je prohledáno od místa, kde jsme skončili, paka
je nalezen/a|a|b|c|d
. - Hodnota vpravo (
b
) se teď shoduje s parametrem{b}
trasy . - V tomto okamžiku existuje zbývající text
a
, ale algoritmus vyčeráhl šablonu trasy, aby parsovala, takže se nejedná o shodu.
Vzhledem k tomu, že odpovídající algoritmus není greedy:
- Odpovídá nejmenšímu množství textu, který je možné v každém kroku.
- Případ, kdy se hodnota oddělovače zobrazí uvnitř hodnot parametrů, způsobí, že se neshoduje.
Regulární výrazy poskytují mnohem větší kontrolu nad jejich odpovídajícím chováním.
Párování Greedy, označované také jako opožděné párování, odpovídá největšímu možnému řetězci. Greedy odpovídá nejmenšímu možnému řetězci.
Referenční informace o omezení trasy
Omezení směrování se provádějí, když došlo ke shodě s příchozí adresou URL a cesta url se tokenizuje do hodnot tras. Omezení tras obecně kontrolují hodnotu trasy přidruženou prostřednictvím šablony trasy a ověřte, jestli je hodnota přijatelná, nebo nepravdivá. Některá omezení trasy používají data mimo hodnotu trasy a zvažují, jestli je možné požadavek směrovat. Například HttpMethodRouteConstraint může přijmout nebo odmítnout požadavek na základě jeho příkazu HTTP. Omezení se používají v požadavcích směrování a generování propojení.
Upozorňující
Nepoužívejte omezení pro ověřování vstupu. Pokud se pro ověření vstupu používají omezení, výsledkem neplatného 404
vstupu je odpověď Nenalezena. Neplatný vstup by měl vytvořit chybný 400
požadavek s příslušnou chybovou zprávou. Omezení tras se používají k nejednoznačnosti podobných tras, nikoli k ověření vstupů pro konkrétní trasu.
Následující tabulka ukazuje ukázková omezení směrování a jejich očekávané chování:
omezení | Příklad | Příklady shod | Notes |
---|---|---|---|
int |
{id:int} |
123456789 , -123456789 |
Odpovídá libovolnému celočíselnému číslu. |
bool |
{active:bool} |
true , FALSE |
Shody true nebo false . Nerozlišují se malá a velká písmena |
datetime |
{dob:datetime} |
2016-12-31 , 2016-12-31 7:32pm |
Odpovídá platné DateTime hodnotě v invariantní jazykové verzi. Viz předchozí upozornění. |
decimal |
{price:decimal} |
49.99 , -1,000.01 |
Odpovídá platné decimal hodnotě v invariantní jazykové verzi. Viz předchozí upozornění. |
double |
{weight:double} |
1.234 , -1,001.01e8 |
Odpovídá platné double hodnotě v invariantní jazykové verzi. Viz předchozí upozornění. |
float |
{weight:float} |
1.234 , -1,001.01e8 |
Odpovídá platné float hodnotě v invariantní jazykové verzi. Viz předchozí upozornění. |
guid |
{id:guid} |
CD2C1638-1638-72D5-1638-DEADBEEF1638 |
Odpovídá platné Guid hodnotě. |
long |
{ticks:long} |
123456789 , -123456789 |
Odpovídá platné long hodnotě. |
minlength(value) |
{username:minlength(4)} |
Rick |
Řetězec musí mít alespoň 4 znaky. |
maxlength(value) |
{filename:maxlength(8)} |
MyFile |
Řetězec nesmí být delší než 8 znaků. |
length(length) |
{filename:length(12)} |
somefile.txt |
Řetězec musí mít přesně 12 znaků. |
length(min,max) |
{filename:length(8,16)} |
somefile.txt |
Řetězec musí mít maximálně 8 znaků a nesmí být delší než 16 znaků. |
min(value) |
{age:min(18)} |
19 |
Celočíselná hodnota musí být alespoň 18. |
max(value) |
{age:max(120)} |
91 |
Celočíselná hodnota nesmí být větší než 120. |
range(min,max) |
{age:range(18,120)} |
91 |
Celočíselná hodnota musí být alespoň 18, ale nesmí být větší než 120. |
alpha |
{name:alpha} |
Rick |
Řetězec musí obsahovat jeden nebo více abecedních znaků a -z a nerozlišuje velká a malá písmena. |
regex(expression) |
{ssn:regex(^\\d{{3}}-\\d{{2}}-\\d{{4}}$)} |
123-45-6789 |
Řetězec musí odpovídat regulárnímu výrazu. Podívejte se na tipy k definování regulárního výrazu. |
required |
{name:required} |
Rick |
Používá se k vynucení toho, aby během generování adresy URL byla přítomna hodnota, která není parametrem. |
Upozorňující
Při zpracování System.Text.RegularExpressions nedůvěryhodného vstupu předejte vypršení časového limitu. Uživatel se zlými úmysly může poskytnout vstup, který RegularExpressions
způsobí útok na dostupnost služby. ASP.NET rozhraní API architektury Core, která používají RegularExpressions
vypršení časového limitu.
Pro jeden parametr lze použít více omezení oddělených dvojtečkami. Například následující omezení omezuje parametr na celočíselnou hodnotu 1 nebo vyšší:
[Route("users/{id:int:min(1)}")]
public User GetUserById(int id) { }
Upozorňující
Omezení směrování, která ověřují adresu URL a jsou převedeny na typ CLR, vždy používají neutrální jazykovou verzi. Například převod na typ int
CLR nebo DateTime
. Tato omezení předpokládají, že adresa URL není lokalizovatelná. Omezení tras poskytovaná architekturou nemění hodnoty uložené v hodnotách tras. Všechny hodnoty směrování parsované z adresy URL se ukládají jako řetězce. Omezení se například pokusí převést hodnotu trasy na hodnotu float, ale převedená hodnota se použije pouze k ověření, float
že se dá převést na plovoucí hodnotu.
Regulární výrazy v omezeních
Upozorňující
Při zpracování System.Text.RegularExpressions nedůvěryhodného vstupu předejte vypršení časového limitu. Uživatel se zlými úmysly může poskytnout vstup, který RegularExpressions
způsobí útok na dostupnost služby. ASP.NET rozhraní API architektury Core, která používají RegularExpressions
vypršení časového limitu.
Regulární výrazy lze zadat jako vložená omezení pomocí regex(...)
omezení trasy. Metody v rodině MapControllerRoute také přijímají literál objektu omezení. Pokud se tento formulář použije, řetězcové hodnoty se interpretují jako regulární výrazy.
Následující kód používá omezení vložených regulárních výrazů:
app.UseEndpoints(endpoints =>
{
endpoints.MapGet("{message:regex(^\\d{{3}}-\\d{{2}}-\\d{{4}}$)}",
context =>
{
return context.Response.WriteAsync("inline-constraint match");
});
});
Následující kód používá literál objektu k určení omezení regulárního výrazu:
app.UseEndpoints(endpoints =>
{
endpoints.MapControllerRoute(
name: "people",
pattern: "People/{ssn}",
constraints: new { ssn = "^\\d{3}-\\d{2}-\\d{4}$", },
defaults: new { controller = "People", action = "List", });
});
Architektura ASP.NET Core přidává RegexOptions.IgnoreCase | RegexOptions.Compiled | RegexOptions.CultureInvariant
do konstruktoru regulárních výrazů. Podívejte RegexOptions se na popis těchto členů.
Regulární výrazy používají oddělovače a tokeny podobné těm používaným směrováním a jazykem C#. Tokeny regulárních výrazů musí být uchycené. Chcete-li použít regulární výraz ^\d{3}-\d{2}-\d{4}$
v vložené omezení, použijte jednu z následujících možností:
- Nahraďte
\
znaky zadané v řetězci jako\\
znaky ve zdrojovém souboru jazyka C#, aby bylo možné řídicí znak řetězce utéct\
. - Doslovné řetězcové literály.
Chcete-li uvozovat znaky {
oddělovače parametrů směrování , [
}
]
zdvojnásobit znaky ve výrazu, {{
například , }}
, , . ]]
[[
Následující tabulka ukazuje regulární výraz a jeho řídicí verzi:
Regulární výraz | Řídicí regulární výraz |
---|---|
^\d{3}-\d{2}-\d{4}$ |
^\\d{{3}}-\\d{{2}}-\\d{{4}}$ |
^[a-z]{2}$ |
^[[a-z]]{{2}}$ |
Regulární výrazy používané při směrování často začínají znakem ^
a odpovídají počáteční pozici řetězce. Výrazy často končí znakem $
a odpovídají konci řetězce. Znaky ^
a $
zajistěte, aby regulární výraz odpovídal celé hodnotě parametru trasy. ^
Bez znaků a $
znaků regulární výraz odpovídá jakémukoli podřetězci v řetězci, což je často nežádoucí. Následující tabulka obsahuje příklady a vysvětluje, proč se shodují nebo se neshodují:
Výraz | String | Párování | Komentář |
---|---|---|---|
[a-z]{2} |
dobrý den | Ano | Shoda podřetěžce |
[a-z]{2} |
123abc456 | Ano | Shoda podřetěžce |
[a-z]{2} |
mz | Ano | Odpovídá výrazu |
[a-z]{2} |
MZ | Ano | Nerozlišuje se malá a velká písmena. |
^[a-z]{2}$ |
dobrý den | No | Viz ^ a $ výše |
^[a-z]{2}$ |
123abc456 | No | Viz ^ a $ výše |
Další informace o syntaxi regulárních výrazů naleznete v tématu Regulární výrazy rozhraní .NET Framework.
Chcete-li omezit parametr na známou sadu možných hodnot, použijte regulární výraz. Například {action:regex(^(list|get|create)$)}
odpovídá pouze hodnotě action
trasy do list
, get
nebo create
. Pokud je řetězec předán do slovníku omezení, je řetězec ^(list|get|create)$
ekvivalentní. Omezení, která se předávají ve slovníku omezení, která neodpovídají některému ze známých omezení, se také považují za regulární výrazy. Omezení předaná v šabloně, která neodpovídají některému ze známých omezení, se považují za regulární výrazy.
Vlastní omezení trasy
Vlastní omezení trasy je možné vytvořit implementací IRouteConstraint rozhraní. Rozhraní IRouteConstraint
obsahuje Match, který vrátí true
, pokud je omezení splněno a false
jinak.
Vlastní omezení trasy jsou zřídka nutná. Před implementací vlastního omezení trasy zvažte alternativy, jako je například vazba modelu.
Složka ASP.NET Core Constraints poskytuje dobré příklady vytváření omezení. Například GuidRouteConstraint.
Pokud chcete použít vlastní IRouteConstraint
typ omezení trasy, musí být zaregistrovaný v kontejneru služby v aplikaci ConstraintMap . A ConstraintMap
je slovník, který mapuje klíče omezení směrování na IRouteConstraint
implementace, které tato omezení ověřují. Aplikaci ConstraintMap
je možné aktualizovat buď jako Startup.ConfigureServices
součást služeb. AddRouting call or by configuring RouteOptions directly with services.Configure<RouteOptions>
. Příklad:
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers();
services.AddRouting(options =>
{
options.ConstraintMap.Add("customName", typeof(MyCustomConstraint));
});
}
Předchozí omezení se použije v následujícím kódu:
[Route("api/[controller]")]
[ApiController]
public class TestController : ControllerBase
{
// GET /api/test/3
[HttpGet("{id:customName}")]
public IActionResult Get(string id)
{
return ControllerContext.MyDisplayRouteInfo(id);
}
// GET /api/test/my/3
[HttpGet("my/{id:customName}")]
public IActionResult Get(int id)
{
return ControllerContext.MyDisplayRouteInfo(id);
}
}
MyDisplayRouteInfo poskytuje balíček NuGet Rick.Docs.Samples.RouteInfo a zobrazí informace o trase.
Implementace MyCustomConstraint
brání 0
použití parametru trasy:
class MyCustomConstraint : IRouteConstraint
{
private Regex _regex;
public MyCustomConstraint()
{
_regex = new Regex(@"^[1-9]*$",
RegexOptions.CultureInvariant | RegexOptions.IgnoreCase,
TimeSpan.FromMilliseconds(100));
}
public bool Match(HttpContext httpContext, IRouter route, string routeKey,
RouteValueDictionary values, RouteDirection routeDirection)
{
if (values.TryGetValue(routeKey, out object value))
{
var parameterValueString = Convert.ToString(value,
CultureInfo.InvariantCulture);
if (parameterValueString == null)
{
return false;
}
return _regex.IsMatch(parameterValueString);
}
return false;
}
}
Upozorňující
Při zpracování System.Text.RegularExpressions nedůvěryhodného vstupu předejte vypršení časového limitu. Uživatel se zlými úmysly může poskytnout vstup, který RegularExpressions
způsobí útok na dostupnost služby. ASP.NET rozhraní API architektury Core, která používají RegularExpressions
vypršení časového limitu.
Předchozí kód:
- Zabraňuje
0
v{id}
segmentu trasy. - Ukazuje se, že poskytuje základní příklad implementace vlastního omezení. Neměla by se používat v produkční aplikaci.
Následující kód je lepším přístupem k tomu, aby se zabránilo zpracování obsahujícího id
0
:
[HttpGet("{id}")]
public IActionResult Get(string id)
{
if (id.Contains('0'))
{
return StatusCode(StatusCodes.Status406NotAcceptable);
}
return ControllerContext.MyDisplayRouteInfo(id);
}
Předchozí kód má oproti přístupu následující výhody MyCustomConstraint
:
- Nevyžaduje vlastní omezení.
- Vrátí popisnější chybu, pokud parametr trasy obsahuje
0
.
Odkaz na transformátor parametrů
Transformátory parametrů:
- Spustí se při generování odkazu pomocí LinkGenerator.
- Implementovat Microsoft.AspNetCore.Routing.IOutboundParameterTransformer.
- Jsou nakonfigurovány pomocí ConstraintMap.
- Převezměte hodnotu trasy parametru a transformujte ji na novou řetězcovou hodnotu.
- Výsledkem je použití transformované hodnoty ve vygenerovaném odkazu.
Například vlastní slugify
transformátor parametru ve vzoru blog\{article:slugify}
trasy s Url.Action(new { article = "MyTestArticle" })
vygenerovanými blog\my-test-article
.
Zvažte následující IOutboundParameterTransformer
implementaci:
public class SlugifyParameterTransformer : IOutboundParameterTransformer
{
public string TransformOutbound(object value)
{
if (value == null) { return null; }
return Regex.Replace(value.ToString(),
"([a-z])([A-Z])",
"$1-$2",
RegexOptions.CultureInvariant,
TimeSpan.FromMilliseconds(100)).ToLowerInvariant();
}
}
Chcete-li použít transformátor parametrů ve vzoru trasy, nakonfigurujte ho pomocí :ConstraintMap Startup.ConfigureServices
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers();
services.AddRouting(options =>
{
options.ConstraintMap["slugify"] = typeof(SlugifyParameterTransformer);
});
}
Architektura ASP.NET Core používá transformátory parametrů k transformaci identifikátoru URI, kde se koncový bod překládá. Například transformátory parametrů transformují směrovací hodnoty použité ke shodě area
, controller
, action
a page
.
routes.MapControllerRoute(
name: "default",
template: "{controller:slugify=Home}/{action:slugify=Index}/{id?}");
U předchozí šablony trasy se akce SubscriptionManagementController.GetAll
shoduje s identifikátorem URI /subscription-management/get-all
. Transformátor parametrů nemění směrovací hodnoty použité k vygenerování propojení. Například Url.Action("GetAll", "SubscriptionManagement")
výstupy /subscription-management/get-all
.
ASP.NET Core poskytuje konvence rozhraní API pro použití transformátorů parametrů se generovanými trasami:
- Konvence Microsoft.AspNetCore.Mvc.ApplicationModels.RouteTokenTransformerConvention MVC aplikuje zadaný transformátor parametrů na všechny trasy atributů v aplikaci. Parametr transformer transformuje tokeny směrování atributů při jejich nahrazení. Další informace naleznete v tématu Použití transformátoru parametrů k přizpůsobení nahrazení tokenu.
- Razor Stránky používají PageRouteTransformerConvention konvenci rozhraní API. Tato konvence aplikuje zadaný transformátor parametrů na všechny automaticky zjištěné Razor stránky. Transformátor parametru transformuje segmenty Razor složek a názvů souborů tras Pages. Další informace naleznete v tématu Použití transformátoru parametrů k přizpůsobení tras stránky.
Referenční informace ke generování adres URL
Tato část obsahuje odkaz na algoritmus implementovaný generováním adres URL. V praxi používají nejsložitější příklady generování adres URL kontrolery nebo Razor stránky. Další informace najdete v tématu Směrování v kontrolerů .
Proces generování adresy URL začíná voláním LinkGenerator.GetPathByAddress nebo podobné metody. Metoda je poskytována s adresou, sadou hodnot tras a volitelně informace o aktuálním požadavku z HttpContext
.
Prvním krokem je použití adresy k vyřešení sady kandidátských koncových bodů pomocí typu IEndpointAddressScheme<TAddress>
adresy.
Jakmile sada kandidátů najde schéma adres, koncové body se objednávají a zpracovávají iterativním způsobem, dokud operace generování adresy URL nebude úspěšná. Generování adresy URL nekontroluje nejednoznačnosti, první vrácený výsledek je konečný výsledek.
Řešení potíží s generováním adres URL pomocí protokolování
Prvním krokem při generování adresy URL při řešení potíží je nastavení úrovně Microsoft.AspNetCore.Routing
protokolování na TRACE
. LinkGenerator
zaznamenává mnoho podrobností o jeho zpracování, které může být užitečné při řešení problémů.
Podrobnosti o generování adres URL najdete v referenčních informacích ke generování adres URL.
Adresy
Adresy jsou konceptem generování adres URL, které slouží k vytvoření vazby volání do generátoru odkazů na sadu kandidátských koncových bodů.
Adresy jsou rozšiřitelný koncept, který ve výchozím nastavení obsahuje dvě implementace:
- Jako adresu použijte název koncového bodu (
string
):- Poskytuje podobné funkce jako název trasy MVC.
- IEndpointNameMetadata Používá typ metadat.
- Vyřeší zadaný řetězec s metadaty všech registrovaných koncových bodů.
- Vyvolá výjimku při spuštění, pokud více koncových bodů používá stejný název.
- Doporučuje se pro obecné použití mimo kontrolery a Razor stránky.
- Použití hodnot směrování (RouteValuesAddress) jako adresy:
- Poskytuje podobné funkce jako kontrolery a Razor starší generace adres URL stránky.
- Velmi složité rozšířit a ladit.
- Poskytuje implementaci, kterou
IUrlHelper
používají pomocné rutiny značek, pomocné rutiny HTML, výsledky akcí atd.
Role schématu adres spočívá v přidružení mezi adresou a odpovídajícími koncovými body podle libovolných kritérií:
- Schéma názvu koncového bodu provádí základní vyhledávání slovníku.
- Schéma hodnot tras má komplexní nejlepší podmnožinu algoritmu sady.
Okolní hodnoty a explicitní hodnoty
Z aktuálního požadavku směrování přistupuje ke směrovacím hodnotám aktuálního požadavku HttpContext.Request.RouteValues
. Hodnoty přidružené k aktuálnímu požadavku se označují jako okolní hodnoty. Pro účely srozumitelnosti se dokumentace týká směrovacích hodnot předávaných metodám jako explicitních hodnot.
Následující příklad ukazuje okolní hodnoty a explicitní hodnoty. Poskytuje okolní hodnoty z aktuálního požadavku a explicitní hodnoty: { id = 17, }
public class WidgetController : Controller
{
private readonly LinkGenerator _linkGenerator;
public WidgetController(LinkGenerator linkGenerator)
{
_linkGenerator = linkGenerator;
}
public IActionResult Index()
{
var url = _linkGenerator.GetPathByAction(HttpContext,
null, null,
new { id = 17, });
return Content(url);
}
Předchozí kód:
- Návraty
/Widget/Index/17
- Získá LinkGenerator přes DI.
Následující kód neposkytuje žádné okolní hodnoty a explicitní hodnoty: { controller = "Home", action = "Subscribe", id = 17, }
public IActionResult Index2()
{
var url = _linkGenerator.GetPathByAction("Subscribe", "Home",
new { id = 17, });
return Content(url);
}
Předchozí metoda vrátí /Home/Subscribe/17
Následující kód ve návratu WidgetController
/Widget/Subscribe/17
:
var url = _linkGenerator.GetPathByAction("Subscribe", null,
new { id = 17, });
Následující kód poskytuje kontroler z okolních hodnot v aktuálním požadavku a explicitní hodnoty: { action = "Edit", id = 17, }
public class GadgetController : Controller
{
public IActionResult Index()
{
var url = Url.Action("Edit", new { id = 17, });
return Content(url);
}
V předchozím kódu:
/Gadget/Edit/17
je vrácena.- UrlIUrlHelperzíská .
- Action vygeneruje adresu URL s absolutní cestou pro metodu akce. Adresa URL obsahuje zadaný
action
název aroute
hodnoty.
Následující kód poskytuje okolní hodnoty z aktuálního požadavku a explicitní hodnoty: { page = "./Edit, id = 17, }
public class IndexModel : PageModel
{
public void OnGet()
{
var url = Url.Page("./Edit", new { id = 17, });
ViewData["URL"] = url;
}
}
Předchozí kód se nastaví url
, když /Edit/17
Edit Razor Page obsahuje následující direktivu stránky:
@page "{id:int}"
Pokud stránka Upravit neobsahuje "{id:int}"
šablonu trasy, url
je /Edit?id=17
.
Chování MVC IUrlHelper přidává kromě zde popsaných pravidel vrstvu složitosti:
IUrlHelper
vždy poskytuje směrovací hodnoty z aktuálního požadavku jako okolní hodnoty.- IUrlHelper.Action vždy zkopíruje aktuální
action
hodnoty acontroller
směrovací hodnoty jako explicitní hodnoty, pokud je nepřepíše vývojář. - IUrlHelper.Page vždy zkopíruje aktuální
page
hodnotu trasy jako explicitní hodnotu, pokud ji nepřepíšete. IUrlHelper.Page
vždy přepíše aktuálníhandler
hodnotunull
trasy jako explicitní hodnoty, pokud ji nepřepíšete.
Uživatelé jsou často překvapeni chováním okolních hodnot, protože MVC zdánlivě nedodržuje vlastní pravidla. Z historických důvodů a z důvodu kompatibility mají určité hodnoty tras, jako action
je , controller
, page
a handler
mají vlastní zvláštní chování.
Ekvivalentní funkce poskytované LinkGenerator.GetPathByAction
a LinkGenerator.GetPathByPage
duplikuje tyto anomálie z důvodu kompatibility IUrlHelper
.
Proces generování adres URL
Jakmile se najde sada kandidátských koncových bodů, algoritmus generování adres URL:
- Zpracovává koncové body iterativním způsobem.
- Vrátí první úspěšný výsledek.
Prvním krokem v tomto procesu je zneplatnění hodnoty trasy. Zneplatnění hodnoty trasy je proces, kterým směrování rozhodne, které hodnoty trasy z okolních hodnot se mají použít a které by se měly ignorovat. Každá okolní hodnota se považuje a buď v kombinaci s explicitními hodnotami, nebo je ignorována.
Nejlepším způsobem, jak přemýšlet o roli okolních hodnot, je, že se snaží uložit vývojáři aplikací psaní, v některých běžných případech. Scénáře, ve kterých jsou okolní hodnoty užitečné, se tradičně vztahují k MVC:
- Při propojení s jinou akcí ve stejném řadiči není nutné zadat název kontroleru.
- Při propojení s jiným řadičem ve stejné oblasti není nutné zadat název oblasti.
- Při propojení se stejnou metodou akce není nutné zadávat hodnoty tras.
- Při propojení s jinou částí aplikace nechcete přenášet hodnoty tras, které nemají v této části aplikace žádný význam.
Volání nebo LinkGenerator
IUrlHelper
vrácení jsou obvykle způsobená tím, že null
nerozumí neplatné hodnotě trasy. Při řešení potíží s neplatnou hodnotou trasy můžete explicitně zadat více hodnot tras, abyste zjistili, jestli se tím problém vyřeší.
Neplatná hodnota trasy funguje na předpokladu, že schéma adresy URL aplikace je hierarchické s hierarchií vytvořenou zleva doprava. Představte si šablonu {controller}/{action}/{id?}
směrování základního kontroleru, abyste získali intuitivní představu o tom, jak to funguje v praxi. Změna hodnoty zneplatní všechny směrovací hodnoty, které se zobrazují vpravo. To odráží předpoklad o hierarchii. Pokud má aplikace okolní hodnotu a id
operace určuje jinou hodnotu pro controller
:
id
nebude znovu použito, protože{controller}
je nalevo od{id?}
.
Několik příkladů demonstrujících tento princip:
- Pokud explicitní hodnoty obsahují hodnotu pro
id
, okolní hodnota jeid
ignorována. Okolní hodnoty acontroller
action
lze je použít. - Pokud explicitní hodnoty obsahují hodnotu pro
action
, je ignorována jakákoli okolní hodnota proaction
. Lze použít okolní hodnotycontroller
. Pokud se explicitní hodnota pro jinou než okolní hodnotaaction
action
pro ,id
hodnota se nepoužije. Pokud je explicitní hodnotaaction
stejná jako okolní hodnota proaction
,id
lze použít hodnotu. - Pokud explicitní hodnoty obsahují hodnotu pro
controller
, je ignorována jakákoli okolní hodnota procontroller
. Pokud se explicitní hodnota pro jinou než okolní hodnotacontroller
controller
pro ,action
hodnoty aid
hodnoty nebudou použity. Pokud je explicitní hodnotacontroller
stejná jako okolní hodnota procontroller
,action
lze použít hodnoty aid
hodnoty.
Tento proces je ještě složitější díky existenci tras atributů a vyhrazených konvenčních tras. Běžné trasy kontroleru, jako {controller}/{action}/{id?}
je například určení hierarchie pomocí parametrů trasy. Pro vyhrazené konvenční trasy a trasy atributů pro kontrolery a Razor stránky:
- Existuje hierarchie hodnot tras.
- Nezobrazují se v šabloně.
V těchto případech generování adresy URL definuje koncept požadovaných hodnot . Koncové body vytvořené kontrolery a Razor stránkami mají zadané požadované hodnoty, které umožňují zneplatnění hodnoty trasy.
Podrobný algoritmus zneplatnění hodnoty trasy:
- Požadované názvy hodnot se kombinují s parametry trasy a pak se zpracovávají zleva doprava.
- Pro každý parametr se porovná okolní hodnota a explicitní hodnota:
- Pokud je okolní hodnota a explicitní hodnota stejné, proces pokračuje.
- Pokud je okolní hodnota přítomná a explicitní hodnota není, použije se při generování adresy URL okolní hodnota.
- Pokud okolní hodnota není přítomná a explicitní hodnota je, zamítněte okolní hodnotu a všechny následné okolní hodnoty.
- Pokud se nachází okolí a explicitní hodnota a obě hodnoty jsou odlišné, zamítněte okolní hodnotu a všechny následné okolní hodnoty.
V tuto chvíli je operace generování adres URL připravená k vyhodnocení omezení trasy. Sada přijatých hodnot se zkombinuje s výchozími hodnotami parametrů, které jsou k dispozici pro omezení. Pokud všechna omezení projdou, operace bude pokračovat.
Dále je možné použít akceptované hodnoty k rozšíření šablony trasy. Šablona trasy se zpracuje:
- Zleva doprava.
- Každý parametr má jeho přijatou hodnotu nahrazenou.
- S následujícími zvláštními případy:
- Pokud přijaté hodnoty chybí hodnota a parametr má výchozí hodnotu, použije se výchozí hodnota.
- Pokud přijaté hodnoty chybí a parametr je nepovinný, zpracování pokračuje.
- Pokud některý parametr trasy napravo od chybějícího volitelného parametru má hodnotu, operace selže.
- Pokud je to možné, sbalí se souvislé parametry s výchozími hodnotami a volitelné parametry.
Hodnoty explicitně za předpokladu, že neodpovídají segmentu trasy, se přidají do řetězce dotazu. Následující tabulka ukazuje výsledek při použití šablony {controller}/{action}/{id?}
trasy .
Okolní hodnoty | Explicitní hodnoty | Výsledek |
---|---|---|
controller = "Home" | action = "O aplikaci" | /Home/About |
controller = "Home" | controller = "Order", action = "About" | /Order/About |
controller = "Home", color = "Red" | action = "O aplikaci" | /Home/About |
controller = "Home" | action = "O produktu", barva = "Červená" | /Home/About?color=Red |
Problémy s neplatnou hodnotou trasy
Od ASP.NET Core 3.0 nefungují některá schémata generování adres URL použitá v dřívějších verzích ASP.NET Core s generováním adres URL dobře. Tým ASP.NET Core plánuje přidat funkce pro řešení těchto potřeb v budoucí verzi. Prozatím je nejlepším řešením použít starší směrování.
Následující kód ukazuje příklad schématu generování adres URL, které není podporováno směrováním.
app.UseEndpoints(endpoints =>
{
endpoints.MapControllerRoute("default",
"{culture}/{controller=Home}/{action=Index}/{id?}");
endpoints.MapControllerRoute("blog", "{culture}/{**slug}",
new { controller = "Blog", action = "ReadPost", });
});
V předchozím kódu culture
se parametr trasy používá pro lokalizaci. Touha má parametr culture
vždy přijmout jako okolní hodnotu. Parametr culture
však není přijat jako okolní hodnota kvůli způsobu, jakým požadované hodnoty fungují:
"default"
V šabloněculture
trasy je parametr trasy vlevo odcontroller
, takže změnycontroller
nebudouculture
neplatné ."blog"
V šabloněculture
trasy se parametr trasy považuje za napravo odcontroller
parametru trasy, který se zobrazí v požadovaných hodnotách.
Konfigurace metadat koncového bodu
Následující odkazy obsahují informace o konfiguraci metadat koncového bodu:
- Povolení Cors se směrováním koncových bodů
- Ukázka IAuthorizationPolicyProvider pomocí vlastního
[MinimumAgeAuthorize]
atributu - Testování ověřování pomocí atributu [Authorize]
- RequireAuthorization
- Výběr schématu s atributem [Authorize]
- Použití zásad pomocí atributu [Authorize]
- Autorizace na základě rolí v ASP.NET Core
Porovnávání hostitelů v trasách pomocí RequireHost
RequireHost použije omezení na trasu, která vyžaduje zadaného hostitele. Parametrem RequireHost
[Host] může být:
- Hostitel:
www.domain.com
, odpovídáwww.domain.com
libovolnému portu. - Hostitel se zástupným znakem:
*.domain.com
, shodywww.domain.com
,subdomain.domain.com
nebowww.subdomain.domain.com
na libovolném portu. - Port:
*:5000
Odpovídá portu 5000 s libovolným hostitelem. - Hostitel a port:
www.domain.com:5000
nebo*.domain.com:5000
odpovídá hostiteli a portu.
Lze zadat více parametrů pomocí RequireHost
nebo [Host]
. Omezení odpovídá hostitelům platným pro některý z parametrů. Například [Host("domain.com", "*.domain.com")]
shody domain.com
, www.domain.com
a subdomain.domain.com
.
Následující kód používá RequireHost
k vyžadování zadaného hostitele na trase:
public void Configure(IApplicationBuilder app)
{
app.UseRouting();
app.UseEndpoints(endpoints =>
{
endpoints.MapGet("/", context => context.Response.WriteAsync("Hi Contoso!"))
.RequireHost("contoso.com");
endpoints.MapGet("/", context => context.Response.WriteAsync("AdventureWorks!"))
.RequireHost("adventure-works.com");
endpoints.MapHealthChecks("/healthz").RequireHost("*:8080");
});
}
Následující kód používá [Host]
atribut na kontroleru k vyžadování některého ze zadaných hostitelů:
[Host("contoso.com", "adventure-works.com")]
public class ProductController : Controller
{
public IActionResult Index()
{
return ControllerContext.MyDisplayRouteInfo();
}
[Host("example.com:8080")]
public IActionResult Privacy()
{
return ControllerContext.MyDisplayRouteInfo();
}
}
[Host]
Když se atribut použije na metodu kontroleru i akce:
- Použije se atribut akce.
- Atribut kontroleru je ignorován.
Doprovodné materiály k výkonu pro směrování
Většina směrování se aktualizovala v ASP.NET Core 3.0, aby se zvýšil výkon.
Pokud má aplikace problémy s výkonem, směrování se často považuje za problém. Důvodem je podezření, že architektury, jako jsou kontrolery a Razor stránky, hlásí dobu strávenou uvnitř rozhraní v protokolovacích zprávách. Pokud je mezi časem hlášeným kontrolery a celkovým časem požadavku významný rozdíl:
- Vývojáři eliminují kód aplikace jako zdroj problému.
- Běžně se předpokládá, že příčinou je směrování.
Směrování je testované výkonem pomocí tisíců koncových bodů. Je nepravděpodobné, že by typická aplikace narazila na problém s výkonem jenom tím, že je příliš velká. Nejčastější hlavní příčinou pomalého směrování je obvykle špatně se chovající vlastní middleware.
Následující ukázka kódu ukazuje základní techniku zúžení zdroje zpoždění:
public void Configure(IApplicationBuilder app, ILogger<Startup> logger)
{
app.Use(next => async context =>
{
var sw = Stopwatch.StartNew();
await next(context);
sw.Stop();
logger.LogInformation("Time 1: {ElapsedMilliseconds}ms", sw.ElapsedMilliseconds);
});
app.UseRouting();
app.Use(next => async context =>
{
var sw = Stopwatch.StartNew();
await next(context);
sw.Stop();
logger.LogInformation("Time 2: {ElapsedMilliseconds}ms", sw.ElapsedMilliseconds);
});
app.UseAuthorization();
app.Use(next => async context =>
{
var sw = Stopwatch.StartNew();
await next(context);
sw.Stop();
logger.LogInformation("Time 3: {ElapsedMilliseconds}ms", sw.ElapsedMilliseconds);
});
app.UseEndpoints(endpoints =>
{
endpoints.MapGet("/", async context =>
{
await context.Response.WriteAsync("Timing test.");
});
});
}
Směrování podle času:
- Prokládání každého middlewaru pomocí kopie middlewaru časování zobrazeného v předchozím kódu.
- Přidejte jedinečný identifikátor pro korelaci dat časování s kódem.
Jedná se o základní způsob, jak zúžit zpoždění, pokud je významné, například více než 10ms
. Odečítá Time 2
se od Time 1
sestav čas strávený v middlewaru UseRouting
.
Následující kód používá kompaktnější přístup k předchozímu kódu časování:
public sealed class MyStopwatch : IDisposable
{
ILogger<Startup> _logger;
string _message;
Stopwatch _sw;
public MyStopwatch(ILogger<Startup> logger, string message)
{
_logger = logger;
_message = message;
_sw = Stopwatch.StartNew();
}
private bool disposed = false;
public void Dispose()
{
if (!disposed)
{
_logger.LogInformation("{Message }: {ElapsedMilliseconds}ms",
_message, _sw.ElapsedMilliseconds);
disposed = true;
}
}
}
public void Configure(IApplicationBuilder app, ILogger<Startup> logger)
{
int count = 0;
app.Use(next => async context =>
{
using (new MyStopwatch(logger, $"Time {++count}"))
{
await next(context);
}
});
app.UseRouting();
app.Use(next => async context =>
{
using (new MyStopwatch(logger, $"Time {++count}"))
{
await next(context);
}
});
app.UseAuthorization();
app.Use(next => async context =>
{
using (new MyStopwatch(logger, $"Time {++count}"))
{
await next(context);
}
});
app.UseEndpoints(endpoints =>
{
endpoints.MapGet("/", async context =>
{
await context.Response.WriteAsync("Timing test.");
});
});
}
Potenciálně nákladné funkce směrování
Následující seznam obsahuje přehled o funkcích směrování, které jsou relativně drahé v porovnání se základními šablonami tras:
- Regulární výrazy: Je možné psát regulární výrazy, které jsou složité nebo mají dlouhou dobu trvání s malým množstvím vstupu.
- Komplexní segmenty (
{x}-{y}-{z}
):- Jsou výrazně dražší než analýza běžného segmentu cesty URL.
- Výsledkem je přidělení mnoha dalších podřetěžců.
- V aktualizaci výkonu směrování core 3.0 ASP.NET se neaktualizovala logika komplexního segmentu.
- Synchronní přístup k datům: Mnoho složitých aplikací má v rámci směrování přístup k databázi. ASP.NET Core 2.2 a starší směrování nemusí poskytovat správné body rozšiřitelnosti pro podporu směrování přístupu k databázi. Například IRouteConstrainta IActionConstraint jsou synchronní. Body rozšiřitelnosti, jako MatcherPolicy jsou a EndpointSelectorContext jsou asynchronní.
Pokyny pro autory knihoven
Tato část obsahuje pokyny pro autory knihoven, kteří vycházejí ze směrování. Cílem těchto podrobností je zajistit, aby vývojáři aplikací měli dobré zkušenosti s používáním knihoven a architektur, které rozšiřují směrování.
Definování koncových bodů
Pokud chcete vytvořit architekturu, která používá směrování pro porovnávání adres URL, začněte definováním uživatelského prostředí, které je postavené na UseEndpoints.
DO staví na vrcholu IEndpointRouteBuilder. To umožňuje uživatelům vytvářet architekturu s jinými funkcemi ASP.NET Core bez nejasností. Každá šablona ASP.NET Core zahrnuje směrování. Předpokládejme, že směrování je pro uživatele k dispozici a známé.
app.UseEndpoints(endpoints =>
{
// Your framework
endpoints.MapMyFramework(...);
endpoints.MapHealthChecks("/healthz");
});
DO vrátit zapečetěný beton typ z volání MapMyFramework(...)
, které implementuje IEndpointConventionBuilder. Většina metod architektury Map...
tento vzor dodržuje. Rozhraní IEndpointConventionBuilder
:
- Umožňuje kompozičnost metadat.
- Cílí na různé rozšiřující metody.
Deklarování vlastního typu umožňuje do tvůrce přidat vlastní funkce specifické pro architekturu. Je v pořádku zabalit tvůrce deklarovaného architekturou a předat do něj volání.
app.UseEndpoints(endpoints =>
{
// Your framework
endpoints.MapMyFramework(...).RequireAuthorization()
.WithMyFrameworkFeature(awesome: true);
endpoints.MapHealthChecks("/healthz");
});
ZVAŽTE psaní vlastního EndpointDataSource. EndpointDataSource
je primitivní úroveň nízké úrovně pro deklarování a aktualizaci kolekce koncových bodů. EndpointDataSource
je výkonné rozhraní API používané kontrolery a Razor stránkami.
Testy směrování mají základní příklad neaktualizuje zdroje dat.
VE výchozím nastavení se nepokoušejte EndpointDataSource
o registraci. Vyžadovat, aby uživatelé zaregistrovali vaši architekturu v UseEndpoints. Filozofie směrování spočívá v tom, že ve výchozím nastavení se nic nezahrnuje a je to UseEndpoints
místo pro registraci koncových bodů.
Vytvoření middlewaru integrovaného se směrováním
ZVAŽTE definování typů metadat jako rozhraní.
Umožňuje použít typy metadat jako atribut tříd a metod.
public interface ICoolMetadata
{
bool IsCool { get; }
}
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
public class CoolMetadataAttribute : Attribute, ICoolMetadata
{
public bool IsCool => true;
}
Architektury, jako jsou kontrolery a Razor stránky, podporují použití atributů metadat na typy a metody. Pokud deklarujete typy metadat:
- Zpřístupní je jako atributy.
- Většina uživatelů má zkušenosti s používáním atributů.
Deklarace typu metadat jako rozhraní přidává další vrstvu flexibility:
- Rozhraní jsou kompozibilní.
- Vývojáři můžou deklarovat své vlastní typy, které kombinují více zásad.
Umožňuje přepsat metadata, jak je znázorněno v následujícím příkladu:
public interface ICoolMetadata
{
bool IsCool { get; }
}
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
public class CoolMetadataAttribute : Attribute, ICoolMetadata
{
public bool IsCool => true;
}
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
public class SuppressCoolMetadataAttribute : Attribute, ICoolMetadata
{
public bool IsCool => false;
}
[CoolMetadata]
public class MyController : Controller
{
public void MyCool() { }
[SuppressCoolMetadata]
public void Uncool() { }
}
Nejlepší způsob, jak postupovat podle těchto pokynů, je vyhnout se definování metadat značek:
- Nehledáte jenom přítomnost typu metadat.
- Definujte vlastnost metadat a zkontrolujte vlastnost.
Kolekce metadat je seřazená a podporuje přepsání podle priority. V případě kontrolerů jsou metadata pro metodu akce nejvýraznější.
Do make middleware useful with and without routing.
app.UseRouting();
app.UseAuthorization(new AuthorizationPolicy() { ... });
app.UseEndpoints(endpoints =>
{
// Your framework
endpoints.MapMyFramework(...).RequireAuthorization();
});
Jako příklad tohoto návodu UseAuthorization
zvažte middleware. Middleware pro autorizaci umožňuje předávat záložní zásady. Záložní zásada, pokud je zadaná, platí pro obě:
- Koncové body bez zadané zásady
- Požadavky, které neodpovídají koncovému bodu.
Díky tomu je middleware autorizace užitečný mimo kontext směrování. Autorizační middleware lze použít pro tradiční programování middlewaru.
Ladění diagnostiky
Podrobný výstup diagnostiky směrování nastavíte Logging:LogLevel:Microsoft
na Debug
hodnotu . Ve vývojovém prostředí nastavte úroveň protokolu v appsettings.Development.json
:
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Debug",
"Microsoft.Hosting.Lifetime": "Information"
}
}
}