Směrování v ASP.NET Core
Od Ryana Nowaka, Vychytáka Užkinaa Ricka Andersona.
Směrování zodpovídá za párová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 pro zpracování požadavků aplikace. Koncové body se definují v aplikaci a konfiguruje při spuštění aplikace. Proces párování koncových bodů může extrahovat hodnoty z adresy URL požadavku a zadat tyto hodnoty pro zpracování požadavků. Pomocí informací o koncových bodech z aplikace může směrování také generovat adresy URL, které se mapují na koncové body.
Aplikace mohou konfigurovat směrování pomocí:
- Kontrolery
- Razor Stránky
- SignalR
- Služby gRPC
- Middleware s povoleným koncovým bodem, například kontroly stavu.
- Delegáty a výrazy lambda zaregistrované se směrováním.
Tento dokument popisuje podrobné informace o směrování ASP.NET Core úrovni. Informace o konfiguraci směrování:
- Informace o kontrolerů najdete v tématu Směrování na akce kontroleru v ASP.NET Core .
- Konvence Razor pages najdete v tématu RazorSměrování stránek 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ší. Pokud chcete získat informace o předchozím systému směrování založeném na , vyberte IRouter verzi ASP.NET Core 2.1 pomocí jednoho z následujících přístupů:
- Selektor verzí pro předchozí verzi.
- Vyberte ASP.NET Core směrování 2.1.
Zobrazení nebo stažení ukázkového kódu (stažení)
Ukázky ke stažení pro tento dokument jsou povolené konkrétní Startup třídou. Pokud chcete spustit konkrétní ukázku, upravte soubor Program.cs tak, aby volal požadovanou Startup třídu.
Základy směrování
Všechny ASP.NET Core zahrnují směrování ve vygenerovaného kódu. Směrování je zaregistrované v middlewaru kanálu 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 v a UseRouting UseEndpoints :
UseRoutingpřidá do middlewarového kanálu párování tras. Tento middleware se podívá na sadu koncových bodů definovaných v aplikaci a vybere nejlepší shodu na základě požadavku.UseEndpointspřidá spuštění koncového bodu do middlewarového kanálu. 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
GETna kořenovou adresu URL/:- Zobrazený delegát požadavku se provede.
Hello World!se zapisovat do odpovědi HTTP. Ve výchozím nastavení je kořenová adresa URL/https://localhost:5001/.
- Pokud metoda požadavku není nebo kořenová adresa URL není , žádná trasa se shoduje a vrátí se
GET/chyba 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.
- Spuštěno spuštěním delegáta.
Koncové body, které může aplikace spárovat a spustit, jsou nakonfigurované v UseEndpoints . Například , a podobné metody MapGet MapPost připojují delegáty požadavků ke směrovacímu systému.
Další metody lze použít k připojení ASP.NET Core architektury ke směrovacímu systému:
- Stránky Razor mapy pro Razor stránky
- MapControllery pro kontrolery
- MapHub <THub> pro SignalR
- MapGrpcService <TService> pro gRPC
Následující příklad ukazuje směrování s důmyslně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 je /hello/{name:alpha} šablona trasy. Slouží ke konfiguraci shody koncového bodu. V tomto případě šablona odpovídá:
- Adresa URL, například
/hello/Ryan - Libovolná cesta URL, která začíná na
/hello/následovanou posloupností abecedních znaků.:alphapoužije omezení trasy, které odpovídá pouze abecedním znakům. Omezení tras jsou vysvětlena dále v tomto dokumentu.
Druhý segment cesty {name:alpha} URL:
- Je svázán s
nameparametrem . - Je zachycen a uložen v HttpRequest.RouteValues.
Systém směrování koncových bodů popsaný v tomto dokumentu je od verze ASP.NET Core 3.0 nový. Všechny verze šablon ale ASP.NET Core 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ž angličtiny, dejte nám vědět v tomto problému diskuze na GitHubu.
Předchozí příklad ukazuje, jak:
- Autorizační middleware je možné použít se směrováním.
- Koncové body je možné použít ke konfiguraci chování autorizace.
Volání MapHealthChecks přidá koncový bod kontroly stavu. RequireAuthorizationZřetězování s tímto voláním připojí ke koncovému bodu zásady autorizace.
Zavolá UseAuthentication a přidá ověřovací a UseAuthorization autorizační middleware. Mezi a se umístí UseRouting UseEndpoints middleware, aby mohl:
- Podívejte se, který koncový bod vybral
UseRouting. - Před odesláním do UseEndpoints koncového bodu použijte zásady autorizace.
Metadata koncového bodu
V předchozím příkladu jsou dva koncové body, ale připojené jsou jenom koncové body kontroly stavu. Pokud požadavek odpovídá koncovému bodu kontroly stavu /healthz , provede se kontrola autorizace. To ukazuje, že ke koncovým bodům mohou být připojena další data. Tato další data se nazývají metadata koncového bodu:
- Metadata je možné zpracovat middlewarem se směrováním.
- Metadata mohou být libovolného typu .NET.
Koncepty směrování
Systém směrování vychází z middlewarového kanálu přidáním výkonného konceptu koncového bodu. Koncové body představují jednotky funkcí aplikace, které se navzájem liší z hlediska směrování, autorizace a libovolného ASP.NET Core systémů aplikace.
ASP.NET Core definice koncového bodu
Koncový ASP.NET Core je:
- Spustitelný soubor: Má RequestDelegate .
- Extensible: Obsahuje kolekci metadat.
- Volitelné: Volitelně obsahuje informace o směrování.
- Vyčíslitelné: Kolekci koncových bodů lze zobrazit načtením objektu EndpointDataSource z injekcí.
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!");
});
});
}
Pokud vyberete koncový bod, můžete ho načíst z HttpContext . Jeho vlastnosti je možné zkontrolovat. Objekty koncových bodů jsou neměnné a po vytvoření je nelze změnit. Nejběžnějším typem koncového bodu je RouteEndpoint . RouteEndpoint obsahuje informace, které umožňují, aby ji systém směrování vybral.
V předchozím kódu je to aplikace. Pomocí se nakonfiguruje middlewarev řádku .
Následující kód ukazuje, že v závislosti na tom, kde se v kanálu app.Use volá, nemusí být 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. Pro přehlednost ukázka přiřadí zobrazovaný název zadanému koncovému / bodu.
Spuštěním tohoto kódu s adresou URL / se zobrazí:
1. Endpoint: (null)
2. Endpoint: Hello
3. Endpoint: Hello
Při spuštění tohoto kódu s libovolnou jinou adresou URL se zobrazí:
1. Endpoint: (null)
2. Endpoint: (null)
4. Endpoint: (null)
Tento výstup ukazuje, že:
- Koncový bod má před voláním
UseRoutingvždy hodnotu null. - Pokud je nalezena shoda, koncový bod mezi a není
UseRoutingUseEndpoints null. - Middleware
UseEndpointsje terminál, když je nalezena shoda. Terminálový middleware je definován dále v tomto dokumentu. - Middleware po spuštění
UseEndpointspouze v případě, že není 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 vlastní logikou a stále využívat výhody UseRouting používání koncových bodů. Koncové body jsou primitivní prvky nízké úrovně, jako je middleware, a nejsou souovány s implementací směrování. Většina aplikací nemusí nahrazovat UseRouting vlastní logikou.
Middleware UseEndpoints je navržený tak, aby se používal společně s UseRouting middlewarem. Základní logika spuštění koncového bodu není složitá. Pomocí GetEndpoint načtete koncový bod a potom vyvoláte jeho RequestDelegate vlastnost.
Následující kód ukazuje, jak může middleware ovlivnit směrování nebo na toto směrování reagovat:
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 může běžet před
UseRoutingzměnou dat, se kterou směrování pracuje.- Middleware, který se zobrazí před směrováním, obvykle upravuje některé vlastnosti požadavku, například UseRewriter UseHttpMethodOverride , nebo UsePathBase .
- Middleware může běžet mezi a a zpracovávat výsledky směrování před spuštěním
UseRoutingUseEndpoints koncového bodu.- Middleware, který běží mezi
UseRoutingaUseEndpoints:- Obvykle se metadata prověří, aby porozuměly koncovým bodům.
- Často se rozhoduje o zabezpečení, jak to dělá a
UseAuthorizationUseCors.
- Kombinace middlewaru a metadat umožňuje konfigurovat zásady pro každý koncový bod.
- Middleware, který běží mezi
Předchozí kód ukazuje příklad vlastního middlewaru, který podporuje zásady pro koncové body. Middleware zapíše do konzoly protokol auditu přístupu k citlivým datům. Middleware je možné nakonfigurovat tak, aby auditoval koncový bod s AuditPolicyAttribute metadaty. Tato ukázka ukazuje vzor výslovného souhlasu, kdy se auditují pouze koncové body označené jako citlivé. Tuto logiku je možné definovat obráceně, například auditování všeho, co není označené jako bezpečné. Systém metadat koncového bodu je flexibilní. Tuto logiku je možné navrhovat způsobem, který tomuto případu použití vyhovuje.
Předchozí ukázkový kód slouží k předvedení základních konceptů koncových bodů. Ukázka není určená k použití v produkčním prostředí. Úplnější verze middlewaru protokolu auditu by:
- Přihlaste se k souboru nebo databázi.
- Sem patří podrobnosti, jako je uživatel, IP adresa, název citlivého koncového bodu a další.
Metadata zásad auditu se definují jako pro snadnější použití s rozhraními založenými na AuditPolicyAttribute Attribute třídách, jako jsou kontrolery a SignalR . Při použití trasy ke kódu:
- Metadata se připojí pomocí rozhraní API pro tvůrce.
- Architektury založené na třídách zahrnují při vytváření koncových bodů všechny atributy odpovídající metody a třídy.
Osvědčenými postupy pro typy metadat je definovat je buď jako rozhraní, nebo atributy. Rozhraní a atributy umožňují opakované použití kódu. Systém metadat je flexibilní a nemá žádná omezení.
Porovnání middlewaru a směrování terminálu
Následující ukázka kódu kontrastuje mezi middlewarem a 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 pomocí Approach 1: je terminální middleware. Nazývá se terminálový middleware, protože se jedná o odpovídající operaci:
- Operace párování v předchozí ukázce je pro middleware a
Path == "/"Path == "/Movie"pro směrování. - Když je shoda úspěšná, provede některé funkce a vrátí se, a nesvořil
nextmiddleware.
Říká se mu terminálový middleware, protože ukončí hledání, spustí některé funkce a pak se vrátí.
Porovnání middlewaru terminálu a směrování:
- Oba přístupy umožňují ukončení kanálu zpracování:
- Middleware ukončí kanál vrácením namísto vyvolání
next. - Koncové body jsou vždy terminál.
- Middleware ukončí kanál vrácením namísto vyvolání
- Terminálový middleware umožňuje umístit middleware na libovolné místo v kanálu:
- Koncové body se spouští na pozici UseEndpoints .
- Terminálový middleware umožňuje libovolnému kódu určit, kdy se middleware shoduje:
- Vlastní kód pro párování tras může být podrobný a obtížně se píše 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
UseAuthorizationje aUseCors.- Použití terminálového middlewaru s nebo vyžaduje ruční propojení
UseAuthorizationUseCorss autorizačním systémem.
- Použití terminálového middlewaru s nebo vyžaduje ruční propojení
Koncový bod definuje:
- Delegát pro zpracování požadavků.
- Kolekce libovolných metadat. Metadata se používají k implementaci průřezových problémů na základě zásad a konfigurace připojených ke každému koncovému bodu.
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.
Zvažte integraci se směrováním před napsáním koncového middlewaru.
Existující terminálový middleware, který se integruje s mapou nebo se obvykle může MapWhen přetápnout na koncový bod podporující směrování. MapHealthChecks ukazuje vzor pro směrovač:
- Napište rozšiřující metodu na IEndpointRouteBuilder .
- Vytvořte vnořený middlewarový kanál pomocí CreateApplicationBuilder .
- Připojte middleware k novému kanálu. V tomto případě UseHealthChecks .
- Build middlewarový kanál do RequestDelegate .
- Zavolejte
Mapa zadejte nový middlewarový kanál. - Vrátí objekt tvůrce poskytovaný metodou
Maprozšíř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 aplikace nakonfigurovat zásady, jako je autorizace koncového bodu. V tomto příkladu middleware pro kontroly stavu nemá přímou integraci s autorizačním systémem.
Systém metadat byl vytvořen v reakci na problémy, ke kterým autoři rozšiřitelnosti narazili pomocí koncového middlewaru. U každého middlewaru je problematické implementovat vlastní integraci s autorizačním systémem.
Párování adres URL
- Je proces, kterým směrování odpovídá příchozímu požadavku na koncový bod?
- Vychází z dat v cestě adresy URL a hlavičkách.
- Lze ji rozšířit tak, aby v požadavku zvážila jakákoli data.
Když se middleware směrování spustí, nastaví hodnoty a na funkci požadavku na z Endpoint aktuálního HttpContext požadavku:
- Volání HttpContext.GetEndpoint získá koncový bod.
HttpRequest.RouteValueszíská kolekci hodnot tras.
Middleware běžící po middlewaru směrování může zkontrolovat koncový bod a provést akci. Například autorizační middleware se může dotazovat na shromažďování metadat koncového bodu kvůli zásadám 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ých bodů zodpovídá za všechna rozhodnutí o dispečinku. Vzhledem k tomu, že middleware používá zásady na základě vybraného koncového bodu, je důležité, aby:
- Každé rozhodnutí, které může mít vliv na odesílání nebo použití zásad zabezpečení, se provádí v systému směrování.
Upozornění
Pro zpětnou kompatibilitu, když Razor je spuštěný delegát koncového bodu kontroleru nebo stránek, jsou vlastnosti RouteContext. parametr RouteData nastaveny na odpovídající hodnoty na základě dosud provedeného zpracování požadavků.
RouteContextTyp bude v budoucí verzi označen jako zastaralý:
- Migrujte
RouteData.ValuesnaHttpRequest.RouteValues. - Migrujte
RouteData.DataTokenspro načtení IDataTokensMetadata z metadat koncového bodu.
Shoda adresy URL funguje v konfigurovatelné sadě fází. V každé fázi je výstupem sada shod. Množinu shody lze v další fázi zúžit. Implementace směrování nezaručuje pořadí zpracování pro porovnání koncových bodů. Všechny možné shody jsou zpracovávány současně. V následujícím pořadí se shodují tyto fáze adresy URL. ASP.NET Core:
- Zpracuje cestu URL proti sadě koncových bodů a jejich šablonám směrování a shromažďují všechny shody.
- Převezme předchozí seznam a odstraní shody, které selžou s použitými omezeními směrování.
- Převezme předchozí seznam a odstraní shody, které selžou sadu instancí MatcherPolicy .
- Použije EndpointSelector k nastavení konečného rozhodnutí z předchozího seznamu.
Seznam koncových bodů se stanovuje podle priorit:
Všechny vyhovující koncové body jsou zpracovávány v každé fázi až do chvíle, kdy EndpointSelector je dosaženo. EndpointSelectorJe finální fází. Zvolí koncový bod nejvyšší priority z odpovídajících shod jako nejlepší shody. Pokud existují jiné shody se stejnou prioritou, jako je nejlepší shoda, je vyvolána výjimka nejednoznačná shoda.
Priorita trasy je vypočítána na základě konkrétnější šablony trasy, která má vyšší prioritu. Zvažte například šablony /hello a /{message} :
- Obě adresy odpovídají cestě URL
/hello. /helloje konkrétnější a proto má vyšší prioritu.
Obecně platí, že priorita trasy má dobrou úlohu při výběru nejlepší shody pro typy schémat adres URL používaných v praxi. Použijte Order pouze v případě potřeby, aby nedocházelo k nejednoznačnosti.
V důsledku druhů rozšiřitelnosti poskytovaných směrováním není možné, aby systém směrování vypočítal předem nejednoznačné trasy. Vezměte v úvahu příklad, jako jsou například šablony směrování /{message:alpha} a /{message:int} :
alphaOmezení odpovídá pouze abecedním znakům.intOmezení odpovídá pouze číslům.- Tyto šablony mají stejnou prioritu trasy, ale žádná jediná adresa URL se shodují.
- Pokud systém směrování ohlásil při spuštění chybu nejednoznačnosti, zablokuje tento platný případ použití.
Upozornění
Pořadí operací uvnitř UseEndpoints nemá vliv na chování směrování s jednou výjimkou. MapControllerRoute a MapAreaRoute automaticky přiřazují hodnotu objednávky svým koncovým bodům podle pořadí, ve kterém jsou vyvolány. To simuluje dlouhodobé chování řadičů bez směrovacího systému, který poskytuje stejné záruky jako u starších implementací směrování.
Ve starší implementaci směrování je možné implementovat rozšiřitelnost směrování, která má závislost v pořadí, ve kterém jsou trasy zpracovávány. směrování koncových bodů v ASP.NET Core 3,0 a novějším:
- Nemá koncept tras.
- Neposkytuje záruky řazení. Všechny koncové body jsou zpracovávány současně.
Priorita šablony směrování a pořadí výběru koncového bodu
Priorita šablony směrování je systém, který přiřazuje každou šablonu směrování hodnotu podle toho, jak je specifická. Priorita šablony směrování:
- Vyhněte se nutnosti upravovat pořadí koncových bodů v běžných případech.
- Pokusy o shodu se společnými očekáváními chování směrování.
Zvažte například šablony /Products/List a /Products/{id} . Je vhodné předpokládat, že /Products/List se jedná o lepší shodu, než /Products/{id} pro cestu URL /Products/List . To funguje, protože literální segment /List je považován za lepší prioritu než segment parametru /{id} .
Podrobnosti o tom, jak priorita funguje, je spojena s tím, jak jsou definovány šablony směrování:
- Šablony s více segmenty jsou považovány za konkrétnější.
- Segment s textovým literálem je považován za konkrétnější než segment parametru.
- Segment parametru s omezením je považován za konkrétnější než bez.
- Složitý segment je považován za specifický jako segment parametru s omezením.
- Catch – všechny parametry jsou nejméně specifické. Důležité informace o catch – všechny trasy najdete v referenčních informacích k šabloně trasy v tématu catch-All .
odkaz na přesné hodnoty najdete ve zdrojovém kódu GitHub .
Koncepty generování adresy URL
Generování adresy URL:
- Je proces, podle kterého směrování může vytvořit cestu adresy URL na základě sady hodnot tras.
- Umožňuje logické oddělení mezi koncovými body a adresami URL, které k nim mají přístup.
Směrování koncového bodu zahrnuje LinkGenerator rozhraní API. LinkGenerator je služba typu Singleton dostupná z di. LinkGeneratorRozhraní API lze použít mimo kontext vykonávajícího požadavku. MVC. IUrlHelper a scénáře, které spoléhají na, jako jsou například IUrlHelper pomocníky značek, HTML helps a výsledky akcí, používají LinkGenerator rozhraní API interně k poskytování možností vytváření odkazů.
Generátor propojení se zálohuje konceptem adres a schémat adres. Schéma adres je způsob, jak určit koncové body, které by měly být považovány za vytváření odkazů. Například název trasy a hodnoty tras jsou obeznámeny s tím, že se řadiče a Razor stránky implementují jako schéma adres.
Generátor propojení se může připojit k řadičům a Razor stránkám prostřednictvím následujících rozšiřujících metod:
Přetížení těchto metod přijímají argumenty, které obsahují HttpContext . Tyto metody jsou funkčně ekvivalentní k adrese URL. Action a URL.Page, ale nabízejí další flexibilitu a možnosti.
GetPath*Metody jsou nejvíce podobné Url.Action a Url.Page , v tom, že generují identifikátor URI obsahující absolutní cestu. GetUri*Metody vždy generují absolutní identifikátor URI obsahující schéma a hostitele. Metody, které přijímají HttpContext identifikátor URI v kontextu zpracovávaného požadavku. Použijí se hodnoty tras, základní cesta, schéma a hostitel z zpracovávaného požadavku, pokud nejsou přepsány.
LinkGenerator je volána s adresou. K vygenerování identifikátoru URI dochází ve dvou krocích:
- Adresa je svázána se seznamem koncových bodů, které odpovídají dané adrese.
- Každý koncový bod RoutePattern je vyhodnocen, dokud se nenajde vzor směrování, který odpovídá zadaným hodnotám. Výsledný výstup je v kombinaci s ostatními částmi identifikátoru URI dodanými generátorem odkazů a vrácenými.
Metody poskytované LinkGenerator funkcí support standard pro vytváření odkazů pro jakýkoli typ adresy. Nejpohodlnější způsob použití generátoru odkazů je prostřednictvím metod rozšíření, které provádějí operace pro konkrétní typ adresy:
| Metoda rozšíření | Description |
|---|---|
| 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. |
Upozornění
Věnujte pozornost následujícím důsledkům volání LinkGenerator metod:
Používejte
GetUri*rozšiřující metody s opatrností v konfiguraci aplikace, která neověřujeHosthlavičku příchozích požadavků. PokudHostzáhlaví příchozích požadavků není ověřeno, může být nedůvěryhodný vstup žádosti odeslán zpět klientovi v identifikátorech URI v zobrazení nebo na stránce. Doporučujeme, aby všechny produkční aplikace nakonfigurovali server, aby ověřiliHosthlavičku se známými platnými hodnotami.Používejte LinkGenerator s opatrností v middleware v kombinaci s
MapneboMapWhen.Map*změní základní cestu spouštěné žádosti, která má vliv na výstup vytváření odkazů. Všechna LinkGenerator rozhraní API umožňují zadat základní cestu. Zadejte prázdnou základní cestu pro vráceníMap*vlivu na generování odkazů.
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 produkty 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.");
}
}
Odkaz na šablonu směrování
Tokeny v rámci {} definice parametrů trasy, které jsou vázány, pokud je trasa shodná. V segmentu trasy lze definovat více než jeden parametr trasy, ale parametry trasy musí být oddělené hodnotou literálu. Například není platná trasa, protože mezi a neexistuje žádná {controller=Home}{action=Index} {controller} literálová {action} hodnota. Parametry trasy musí mít název a mohou mít zadané další atributy.
Literálový text jiný než parametry trasy (například ) a oddělovač cesty se musí shodovat {id} / s textem v adrese URL. Porovnávání textu rozlišuje malá a velká písmena a vychází z dekódované reprezentace cesty adresy URL. Pokud chcete použít oddělovač parametrů trasy literálu nebo , uvozte 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 zbytek identifikátoru URI.
- Nazývají se zachytávané všechny parametry. Například
blog/{**slug}:- Odpovídá libovolnému identifikátoru URI, který začíná na a
/blogmá za ním libovolnou hodnotu. - Následující hodnota
/blogse přiřadí k hodnotě trasy slug.
- Odpovídá libovolnému identifikátoru URI, který začíná na a
Upozornění
Parametr catch-All může nesprávně odpovídat trasy z důvodu chyby v směrování. Aplikace ovlivněné touto chybou mají následující vlastnosti:
- Například trasa typu catch-ALL.
{**slug}" - Trasa catch-All nesplňuje požadavky, které by se měla shodovat.
- Při odebrání jiných tras bude vše začít pracovat.
Příklady přístupů k této chybě najdete v tématu chyby GitHubu 18677 a 16579 .
Oprava pro tuto chybu je obsažená v sadě .NET Core 3.1.301 SDK a novější. Následující kód nastaví interní přepínač, který vyřeší tuto chybu:
public static void Main(string[] args)
{
AppContext.SetSwitch("Microsoft.AspNetCore.Routing.UseCorrectCatchAllBehavior",
true);
CreateHostBuilder(args).Build().Run();
}
// Remaining code removed for brevity.
Zachycovat všechny parametry se také mohou shodovat s prázdným řetězcem.
Parametr catch-all uchytí příslušné znaky, pokud se trasa použije k vygenerování adresy URL, včetně znaků / oddělovače cesty. Například trasa s hodnotami foo/{*path} trasy generuje { path = "my/path" } foo/my%2Fpath . Všimněte si lomítka s uvoze znaky. Pokud chcete znaky oddělovače cesty round-trip, použijte ** předponu parametru trasy. Trasa s foo/{**path} { path = "my/path" } vygeneruje foo/my/path .
Vzory adres URL, které se pokoušejí zachytit název souboru s volitelnou příponou souboru, mají další aspekty. Zvažte například šablonu files/{filename}.{ext?} . Pokud existují hodnoty filename pro i , naplní se obě ext hodnoty. Pokud v adrese URL existuje pouze hodnota pro , trasa filename se shoduje, protože koncový znak . je volitelný. Následující adresy URL odpovídají této trase:
/files/myFile.txt/files/myFile
Parametry trasy mohou mít výchozí hodnoty určené zadáním výchozí hodnoty za názvem parametru odděleným znaménkem rovná se ( = ). Například definuje {controller=Home} jako výchozí hodnotu pro Home controller . Výchozí hodnota se použije, pokud adresa URL parametru nemá žádnou hodnotu. Parametry trasy jsou volitelné připojením otazník ( ) na ? konec názvu parametru. Například, id?. Rozdíl mezi volitelnými hodnotami a výchozími parametry trasy je následující:
- Parametr trasy s výchozí hodnotou vždy vytvoří hodnotu.
- Volitelný parametr má hodnotu pouze v případě, že je hodnota poskytnuta adresou URL požadavku.
Parametry trasy mohou mít omezení, která musí odpovídat hodnotě trasy svázané s adresou URL. Přidání a název omezení za název parametru trasy určuje vložené : omezení parametru trasy. Pokud omezení vyžaduje argumenty, jsou uzavřeny v závorkách (...) za názvem omezení. Více v řádku omezení lze zadat připojením jiného názvu a názvu : omezení.
Název omezení a argumenty se předá službě, aby se vytvořila instance , IInlineConstraintResolver která se použije při zpracování adresy IRouteConstraint URL. Šablona trasy například určuje blog/{article:minlength(10)} omezení minlength s argumentem 10 . Další informace o omezeních tras a seznam omezení poskytovaných architekturou najdete v části Referenční informace o omezeních tras.
Parametry trasy mohou mít také transformátory parametrů. Transformace parametrů transformují hodnotu parametru při generování odkazů a odpovídajících akcí a stránek na adresy URL. Podobně jako omezení je možné transformační parametry přidat do parametru trasy vložením názvu a : transformeru za název parametru trasy. Šablona trasy například určuje blog/{article:slugify} slugify transformer. Další informace o transformátorech parametrů najdete v referenční části o parameter transformeru.
Následující tabulka ukazuje příklady šablon 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 nastavuje Page na Home . |
{Page=Home} |
/Contact |
Odpovídá a nastavuje Page na Contact . |
{controller}/{action}/{id?} |
/Products/List |
Mapy ke Products kontroleru a List akci. |
{controller}/{action}/{id?} |
/Products/Details/123 |
Mapy ke Products kontroleru Details a akci s id nastavenou na 123. |
{controller=Home}/{action=Index}/{id?} |
/ |
Mapy ke Home kontroleru a Index metodě. id se ignoruje. |
{controller=Home}/{action=Index}/{id?} |
/Products |
Mapy ke Products kontroleru a Index metodě. id se ignoruje. |
Použití šablony je obecně nejjednodušším přístupem ke směrování. Omezení a výchozí hodnoty je také možné zadat mimo šablonu trasy.
Složité segmenty
Složité segmenty se zpracovávají porovnáním literálových oddělovačů zprava doleva jinak než greedy. Například je [Route("/a{b}c{d}")] komplexní segment.
Složité segmenty fungují konkrétním způsobem, který je třeba pochopit, aby je bylo možné úspěšně používat. Příklad v této části ukazuje, proč složité segmenty ve skutečnosti fungují dobře jenom v případě, že se text oddělovače nezobrazuje 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.
Upozornění
Při použití System.Text.RegularExpressions ke zpracování nedůvěryhodného vstupu předejte časový limit. Uživatel se zlými úmysly může poskytnout vstup pro RegularExpressions útok DoS (Denial-of-Service). Rozhraní API rozhraní ASP.NET Core Framework, která používají RegularExpressions předávat časový limit.
Toto je souhrn kroků, které směrování provádí se šablonou a /a{b}c{d} cestou URL /abcd . Slouží | k vizualizaci toho, jak algoritmus funguje:
- První literál zprava doleva je
c. Proto/abcdse prohledá zprava a najde/ab|c|d. - Všechno napravo (
d) se teď shoduje s parametrem trasy{d}. - Další literál zprava doleva je
a. Prohledá/ab|c|dse tedy od místa, kde jsme opustili , a pak jsme našlia/|a|b|c|d. - Hodnota vpravo (
b) se teď shoduje s parametrem trasy{b}. - Neexistuje žádný zbývající text a žádná zbývající šablona trasy, takže se jedná o shodu.
Tady je příklad negativního případu s použitím stejné šablony a /a{b}c{d} cesty URL /aabcd . Slouží | k vizualizaci toho, jak algoritmus funguje. Tento případ neodpovídá, což je vysvětleno stejným algoritmem:
- První literál zprava doleva je
c. Proto/aabcdse prohledá zprava a najde/aab|c|d. - Všechno napravo (
d) se teď shoduje s parametrem trasy{d}. - Další literál zprava doleva je
a. Prohledá/aab|c|dse tedy od místa, kde jsme opustili , a pak jsme našlia/a|a|b|c|d. - Hodnota vpravo (
b) se teď shoduje s parametrem trasy{b}. - V tomto okamžiku zbývá text , ale algoritmus došla šablona trasy k analýze, takže
ase neshoduje.
Vzhledem k tomu, že algoritmus porovnávání není greedy:
- Odpovídá co nejmenšímu množství textu v každém kroku.
- Všechny případy, kdy se hodnota oddělovače zobrazí uvnitř hodnot parametrů, nebudou se shodovat.
Regulární výrazy poskytují mnohem větší kontrolu nad jejich chováním při porovnávání.
Shoda s greedy, která se také ví jako opožděná shoda, odpovídá největšímu možnému řetězci. Non-greedy odpovídá nejmenšímu možnému řetězci.
Referenční informace k omezením tras
Omezení tras se spustí, když dojde 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 při rozhodování o tom, jestli je hodnota přijatelná, je pravdivé nebo nepravdivé. Některá omezení tras používají data mimo hodnotu trasy ke zvážení, jestli je možné požadavek směrovat. Může například přijmout HttpMethodRouteConstraint nebo odmítnout požadavek na základě svého slovesa HTTP. Omezení se používají při směrování požadavků a generování propojení.
Upozornění
Nepoužívejte omezení pro ověřování vstupu. Pokud se pro ověřování vstupu používají omezení, výsledkem neplatného vstupu je odpověď 404 Nenašl se. Neplatný vstup by měl vytvořit 400 chybný požadavek s příslušnou chybovou zprávou. Omezení tras slouží k jednoznačnosti podobných tras, ne k ověřování vstupů pro konkrétní trasu.
Následující tabulka ukazuje příklad omezení tras a jejich očekávané chování:
| omezení | Příklad | Příklady shod | Poznámky |
|---|---|---|---|
int |
{id:int} |
123456789, -123456789 |
Odpovídá libovolnému celému číslu. |
bool |
{active:bool} |
true, FALSE |
Odpovídá true nebo false . Case-insensitive |
datetime |
{dob:datetime} |
2016-12-31, 2016-12-31 7:32pm |
Odpovídá platné hodnotě DateTime v invariantní jazykové verzi. Viz předchozí upozornění. |
decimal |
{price:decimal} |
49.99, -1,000.01 |
Odpovídá platné hodnotě decimal v invariantní jazykové verzi. Viz předchozí upozornění. |
double |
{weight:double} |
1.234, -1,001.01e8 |
Odpovídá platné hodnotě double v invariantní jazykové verzi. Viz předchozí upozornění. |
float |
{weight:float} |
1.234, -1,001.01e8 |
Odpovídá platné hodnotě float 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 nesmí být delší než 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 se musí skládat z jednoho nebo více abecedních znaků a bez rozlišení a - z velkých a malých písmen. |
regex(expression) |
{ssn:regex(^\\d{{3}}-\\d{{2}}-\\d{{4}}$)} |
123-45-6789 |
Řetězec musí odpovídat regulárnímu výrazu. Viz tipy pro definování regulárního výrazu. |
required |
{name:required} |
Rick |
Slouží k vynucení, aby při generování adresy URL byla přítomna hodnota bez parametru. |
Upozornění
Při použití System.Text.RegularExpressions ke zpracování nedůvěryhodného vstupu předejte časový limit. Uživatel se zlými úmysly může poskytnout vstup pro RegularExpressions útok DoS (Denial-of-Service). Rozhraní API rozhraní ASP.NET Core Framework, která používají RegularExpressions předávat časový limit.
Omezení s více dvojtečkami s oddělovači lze použít na jeden parametr. 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) { }
Upozornění
Omezení tras, která ověřují adresu URL a jsou převedena na typ CLR, vždy používají neutrální jazykovou verzi. Například převod na typ CLR int nebo DateTime . Tato omezení předpokládají, že adresu URL nelze lokalizovat. Omezení tras poskytovaná architekturou neupraví hodnoty uložené v hodnotách tras. Všechny hodnoty tras 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í, že je možné ji převést float na float.
Regulární výrazy v omezeních
Upozornění
Při použití System.Text.RegularExpressions ke zpracování nedůvěryhodného vstupu předejte časový limit. Uživatel se zlými úmysly může poskytnout vstup pro RegularExpressions útok DoS (Denial-of-Service). Rozhraní API rozhraní ASP.NET Core Framework, která používají RegularExpressions předávat časový limit.
Regulární výrazy lze zadat jako vložené omezení pomocí regex(...) omezení trasy. Metody v MapControllerRoute rodině také přijímají objektový literál omezení. Pokud je tento formulář použit, jsou řetězcové hodnoty interpretovány jako regulární výrazy.
Následující kód používá omezení v řádku 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á objektový literál 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", });
});
Rozhraní ASP.NET Core přidá RegexOptions.IgnoreCase | RegexOptions.Compiled | RegexOptions.CultureInvariant do konstruktoru regulárního výrazu. Popis RegexOptions těchto členů najdete tady: .
Regulární výrazy používají oddělovače a tokeny podobné těm, které používá směrování a jazyk C#. Tokeny regulárního výrazu musí být uvozeny uvozovacími znaky. Pokud chcete použít regulární výraz ^\d{3}-\d{2}-\d{4}$ v vloženém omezení, použijte jednu z následujících možností:
- Nahraďte znaky zadané v řetězci jako znaky ve zdrojovém souboru C#, abyste řídicí znak řetězce
\\\\uniknou. - Doslovné řetězcové literály.
Pokud chcete řídicí znak oddělovače parametrů směrování , , , zdvojnásobte znaky ve výrazu, například { } , , , [ ] {{ }} [[ ]] . Následující tabulka obsahuje regulární výraz a jeho uvozenou verzi:
| Regulární výraz | Regulární výraz s uvozenou znaky |
|---|---|
^\d{3}-\d{2}-\d{4}$ |
^\\d{{3}}-\\d{{2}}-\\d{{4}}$ |
^[a-z]{2}$ |
^[[a-z]]{{2}}$ |
Regulární výrazy použité 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 zajišťují, že regulární výraz odpovídá celé hodnotě parametru trasy. Bez znaků a odpovídá regulární výraz libovolnému 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 selhávají:
| Výraz | Řetězec | Shoda | Komentář |
|---|---|---|---|
[a-z]{2} |
hello | Yes | Shody podřetězce |
[a-z]{2} |
123abc456 | Yes | Shody podřetězce |
[a-z]{2} |
Mz | Yes | Výraz shody |
[a-z]{2} |
MZ | Yes | Rozlišují se malá a velká písmena. |
^[a-z]{2}$ |
hello | No | Viz ^ a $ výše. |
^[a-z]{2}$ |
123abc456 | No | Viz ^ a $ výše. |
Další informace o syntaxi regulárních výrazů najdete v .NET Framework regulárních výrazů.
Pokud chcete parametr omezit na známou sadu možných hodnot, použijte regulární výraz. Například odpovídá {action:regex(^(list|get|create)$)} pouze hodnotě trasy , nebo action list get create . Pokud je předán do slovníku omezení, je ^(list|get|create)$ řetězec ekvivalentní. Omezení předaná ve slovníku omezení, která neodpovídají jednomu ze známých omezení, jsou také považována za regulární výrazy. Omezení předaná v rámci šablony, která neodpovídají jednomu ze známých omezení, nejsou považována za regulární výrazy.
Vlastní omezení tras
Vlastní omezení tras lze vytvořit implementací IRouteConstraint rozhraní . Rozhraní IRouteConstraint obsahuje , který vrátí hodnotu , pokud je omezení Match true splněno, a false v opačném případě .
Vlastní omezení tras jsou zřídka potřebná. Před implementací omezení vlastních tras zvažte alternativy, jako je například vazba modelu.
Dobrá ASP.NET Core omezení najdete ve složce Omezení. Například GuidRouteConstraint.
Pokud chcete použít vlastní , musí být typ omezení trasy zaregistrovaný u aplikace IRouteConstraint ConstraintMap v kontejneru služby. Je ConstraintMap slovník, který mapuje směrovací klíče omezení na IRouteConstraint implementace, které tato omezení ověřují. Aplikace je možné ConstraintMap aktualizovat v Startup.ConfigureServices obou službách. Volání AddRouting nebo konfigurací RouteOptions přímo pomocí services.Configure<RouteOptions> . Napří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 zobrazuje informace o trasách.
Implementace metody MyCustomConstraint brání použití na parametr 0 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;
}
}
Upozornění
Při použití System.Text.RegularExpressions ke zpracování nedůvěryhodného vstupu předejte časový limit. Uživatel se zlými úmysly může poskytnout vstup pro RegularExpressions útok DoS (Denial-of-Service). Rozhraní API rozhraní ASP.NET Core Framework, která používají RegularExpressions předávat časový limit.
Předchozí kód:
- Zabrání
0v{id}segmentu trasy. - Zobrazuje se základní příklad implementace vlastního omezení. Neměl by se používat v produkční aplikaci.
Následující kód je lepším přístupem k zabránění id zpracování 0 obsahujícího :
[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í MyCustomConstraint výhody:
- Nevyžaduje vlastní omezení.
- Pokud parametr trasy obsahuje , vrátí popisnější
0chybu.
Referenční informace k parameter transformeru
Parameter transformers (Transformátory parametrů):
- Spustí se při generování odkazu pomocí LinkGenerator .
- Implementujte Microsoft.AspNetCore.Routing.IOutboundParameterTransformer .
- Konfiguruje se 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é odkazu.
Například vlastní transformátor parametrů ve vzoru trasy s slugify blog\{article:slugify} vygeneruje Url.Action(new { article = "MyTestArticle" }) 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();
}
}
Pokud chcete použít transformátor parametrů ve vzoru trasy, nakonfigurujte ho pomocí v ConstraintMap Startup.ConfigureServices souboru :
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers();
services.AddRouting(options =>
{
options.ConstraintMap["slugify"] = typeof(SlugifyParameterTransformer);
});
}
Rozhraní ASP.NET Core používá transformace parametrů k transformaci identifikátoru URI, kde se překládá koncový bod. Například transformace parametrů transformují hodnoty tras, které se používají ke shodě area s , , a controller action page .
routes.MapControllerRoute(
name: "default",
template: "{controller:slugify=Home}/{action:slugify=Index}/{id?}");
S předchozí šablonou trasy se akce porovná SubscriptionManagementController.GetAll s identifikátorem URI /subscription-management/get-all . Transformátor parametrů nemění hodnoty tras 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žívání transformátorů parametrů s generovanými trasami:
- Konvence Microsoft.AspNetCore.Mvc.ApplicationModels.RouteTokenTransformerConvention MVC aplikuje zadaný parameter transformer na všechny trasy atributů v aplikaci. Transformace parametrů transformuje tokeny směrování atributů při jejich nahrazování. Další informace najdete v tématu Přizpůsobení nahrazení tokenů pomocí parameter transformeru.
- Razor Pages používá PageRouteTransformerConvention konvenci rozhraní API. Tato konvence aplikuje zadaný transformátor parametrů na všechny automaticky zjištěné Razor stránky. Transformace parametrů transformuje segmenty názvů složek a souborů tras Razor Pages. Další informace najdete v tématu Přizpůsobení tras stránek pomocí parameter transformeru.
Referenční informace ke generování adres URL
Tato část obsahuje odkaz na algoritmu implementované generováním adresy URL. V praxi nejsložitější příklady generování adres URL používají 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 metody LinkGenerator.GetPathByAddress nebo podobné metody. Metoda má adresu, sadu hodnot tras a volitelně informace o aktuálním požadavku z HttpContext .
Prvním krokem je použití adresy k překladu sady kandidátských koncových bodů pomocí objektu , který odpovídá IEndpointAddressScheme<TAddress> typu adresy.
Jakmile schéma adres nasvědčí sadě kandidátů, koncové body se seřazeny a zpracovávají iterativně, dokud operace generování adresy URL neprovede úspěch. Generování adresy URL neschová nejednoznačnosti, první vrácený výsledek je konečný výsledek.
Řešení potíží s generováním adres URL s protokolováním
Prvním krokem při řešení potíží s generováním adres URL je nastavení úrovně protokolování Microsoft.AspNetCore.Routing na TRACE . LinkGenerator protokoluje mnoho podrobností o jeho zpracování, což 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 o generování adres URL.
Adresy
Adresy jsou koncept generování adres URL, který se používá k navázání volání do generátoru odkazů na sadu kandidátských koncových bodů.
Adresy jsou rozšiřitelný koncept, který se standardně dodá se dvěma implementacemi:
- Použití názvu koncového bodu (
string) jako adresy:- Poskytuje podobné funkce jako název trasy MVC.
- Používá IEndpointNameMetadata typ metadat.
- Překládá zadaný řetězec na metadata všech registrovaných koncových bodů.
- Vyvolá při spuštění výjimku, pokud více koncových bodů používá stejný název.
- Doporučuje se pro obecné účely mimo kontrolery a Razor stránky.
- Použití hodnot tras ( ) jako RouteValuesAddress adresy:
- Poskytuje podobné funkce jako kontrolery a Razor generování starších adres URL stránek.
- Rozšíření a ladění je velmi složité.
- Poskytuje implementaci, kterou používají
IUrlHelper, pomocníci značek, pomocníci HTML, výsledky akcí atd.
Rolí schématu adres je přidružení mezi adresou a odpovídajícími koncovými body na základě libovolných kritérií:
- Schéma názvu koncového bodu provádí základní slovníkové vyhledávání.
- Schéma hodnot tras má složitou nejlepší podmnožinu nastaveného algoritmu.
Ambientní hodnoty a explicitní hodnoty
Z aktuálního požadavku směrování přistupuje k hodnotám tras aktuálního požadavku HttpContext.Request.RouteValues . Hodnoty přidružené k aktuálnímu požadavku se označují jako ambientní hodnoty. Z důvodu přehlednosti dokumentace odkazuje na hodnoty tras předané metodám jako na explicitní hodnoty.
Následující příklad ukazuje okolní hodnoty a explicitní hodnoty. Poskytuje ambientní 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:
- Vrátí
/Widget/Index/17 - Získá LinkGenerator prostřednictvím di .
Následující kód poskytuje žádné ambientní 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 v vrátí 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/17se vrátí .- Url získá IUrlHelper .
- Action
vygeneruje adresu URL s absolutní cestou pro metodu akce. Adresa URL obsahuje zadanýactionnázev aroutehodnoty.
Následující kód poskytuje ambientní 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 nastaví na url , když stránka pro /Edit/17 Razor úpravy obsahuje následující direktivu page:
@page "{id:int}"
Pokud stránka Upravit šablonu trasy "{id:int}" neobsahuje, je url /Edit?id=17 .
Chování MVC přidává kromě zde popsaných pravidel také vrstvu IUrlHelper složitosti:
IUrlHelpervždy poskytuje hodnoty tras z aktuálního požadavku jako ambientní hodnoty.- IUrlHelper.Action vždy zkopíruje aktuální a směrovací hodnoty jako explicitní hodnoty, pokud
actioncontrollerje nepopíše vývojář. - IUrlHelper.Page vždy zkopíruje aktuální hodnotu trasy jako explicitní hodnotu, pokud
pagenení přepsána. IUrlHelper.Pagevždy přepíše aktuálníhandlerhodnotu trasy jako explicitnínullhodnoty, pokud není přepsána.
Uživatelé jsou často překvapení kvůli podrobnostem o chování okolních hodnot, protože MVC zřejmě nesleduje vlastní pravidla. Z historických důvodů a z důvodů kompatibility mají určité hodnoty tras, například , , a vlastní chování action controller při page handler zvláštních případech.
Ekvivalentní funkce poskytované funkcí a LinkGenerator.GetPathByAction LinkGenerator.GetPathByPage duplikují tyto anomálie z IUrlHelper důvodu kompatibility.
Proces generování adres URL
Jakmile najdete sadu kandidátských koncových bodů, algoritmus generování adres URL:
- Iterativně zpracovává koncové body.
- Vrátí první úspěšný výsledek.
První krok v tomto procesu se nazývá zneplatnění hodnoty trasy. Zneplatnění hodnoty trasy je proces, podle kterého směrování rozhoduje, které hodnoty tras z okolních hodnot se mají použít a které by se měly ignorovat. Každá ambientní hodnota je považována za a buď zkombinována s explicitními hodnotami, nebo ignorována.
Nejlepší způsob, jak zamyslet se nad rolí okolních hodnot, je v některých běžných případech pokusit se uložit psaní vývojáři aplikací. Scénáře, ve kterých jsou užitečné okolní hodnoty, tradičně souvisejí s MVC:
- Při propojování s jinou akcí ve stejném kontroleru nemusí být název kontroleru zadán.
- Při propojování s jiným kontroleru ve stejné oblasti není potřeba zazadat název oblasti.
- Při propojování se stejnou metodou akce není nutné zazadat hodnoty tras.
- Při propojování s jinou částí aplikace nechcete přenést hodnoty tras, které v této části aplikace nemají žádný význam.
Volání metody LinkGenerator nebo , která vrací , jsou obvykle IUrlHelper null způsobena tím, že neporozumíte zneplatnění hodnoty trasy. Vyřešte potíže s zneplatněním hodnoty trasy explicitním zadáním dalších hodnot tras a podívejte se, jestli se tím problém nevyřeší.
Zneplatnění hodnoty trasy funguje za předpokladu, že schéma adresy URL aplikace je hierarchické a hierarchie je vytvořená zleva doprava. Zvažte základní šablonu trasy kontroleru, {controller}/{action}/{id?} abyste získali intuitivní přehled o tom, jak to funguje v praxi. Změna hodnoty zneplatní všechny hodnoty trasy, které se zobrazují vpravo. To odráží předpoklad o hierarchii. Pokud má aplikace ambientní hodnotu pro a operace určuje id jinou hodnotu pro controller :
idse nebude znovu používat,{controller}protože je nalevo od{id?}.
Několik příkladů demonstrujících tento princip:
- Pokud explicitní hodnoty obsahují hodnotu
idpro , okolí hodnota pro jeidignorována. Je možné použítcontrolleractionambientní hodnoty pro a . - Pokud explicitní hodnoty obsahují hodnotu
actionpro , bude ignorována jakákoliactionambientní hodnota pro . Je možné použítcontrollerambientní hodnoty pro . Pokud se explicitní hodnota pro liší od ambientní hodnoty pro , hodnotaactionse nebudeactionidpoužívat. Pokud je explicitní hodnotaactionpro stejná jako ambientní hodnota pro ,actionlze hodnotuidpoužít. - Pokud explicitní hodnoty obsahují hodnotu
controllerpro , bude ignorována jakákolicontrollerambientní hodnota pro . Pokud se explicitní hodnota pro liší od ambientní hodnoty pro , hodnoty acontrollercontrollerse nebudouactionidpoužívat. Pokud je explicitní hodnota pro stejná jako ambientní hodnota pro , lzecontrollerpoužít hodnoty acontrolleractionid.
Tento proces je ještě složitější díky existenci tras atributů a vyhrazených konvenčních tras. Konvenční trasy kontroleru, jako {controller}/{action}/{id?} je například určení hierarchie pomocí parametrů trasy. U vyhrazených konvenčních tras a tras atributů na kontrolery a Razor stránky:
- Existuje hierarchie hodnot tras.
- V šabloně se nezobrazí.
V těchto případech definuje generování adresy URL koncept požadovaných hodnot. Koncové body vytvořené kontrolery a stránkami mají zadané požadované hodnoty, které umožňují, aby Razor hodnota trasy zneplatněná fungovala.
Algoritmus zneplatnění hodnoty trasy podrobně:
- Názvy požadovaných hodnot se zkombinují s parametry trasy a pak se zpracují zleva doprava.
- Pro každý parametr je porovnána ambientní hodnota a explicitní hodnota:
- Pokud je hodnota okolí a explicitní hodnota stejné, proces pokračuje.
- Pokud je k dispozici hodnota okolí a explicitní hodnota není, použije se při generování adresy URL hodnota okolí.
- Pokud okolí hodnota není k dispozici a explicitní hodnota je, odmítne okolí hodnotu a všechny následné okolí hodnoty.
- Pokud jsou k dispozici ambientní hodnota a explicitní hodnota a tyto dvě hodnoty se liší, odmítnou okolní hodnotu a všechny následné okolní hodnoty.
V tuto chvíli je operace generování adresy URL připravená vyhodnotit omezení tras. Sada přijatých hodnot se kombinuje s výchozími hodnotami parametrů, které se poskytují omezením. Pokud všechna omezení projdou, operace bude pokračovat.
Dále je možné pomocí akceptované hodnoty rozbalit šablonu trasy. Šablona trasy se zpracuje:
- Zleva doprava.
- Každý parametr má svou přijatou hodnotu nahrazenou.
- S následujícími zvláštními případy:
- Pokud v akceptovaných hodnotách chybí hodnota a parametr má výchozí hodnotu, použije se výchozí hodnota.
- Pokud v akceptovaných hodnotách chybí hodnota a parametr je volitelný, zpracování pokračuje.
- Pokud nějaký parametr trasy napravo od chybějícího volitelného parametru obsahuje hodnotu, operace selže.
- Souvislé parametry s výchozí hodnotou a volitelné parametry jsou tam, kde je to možné, sbalené.
Hodnoty explicitně zadané, které neodpovídají segmentu trasy, se přidávají do řetězce dotazu. Následující tabulka ukazuje výsledek při použití šablony trasy {controller}/{action}/{id?} .
| Ambientní hodnoty | Explicitní hodnoty | Výsledek |
|---|---|---|
| controller = " Home " " | action = "About" | /Home/About |
| controller = " Home " " | controller = "Order", action = "About" | /Order/About |
| controller = " Home ", color = "Red" | action = "About" | /Home/About |
| controller = " Home " " | action = "About", color = "Red" | /Home/About?color=Red |
Problémy s zneplatněním hodnoty trasy
Od verze ASP.NET Core 3.0 některá schémata generování adres URL používaná v dřívějších verzích ASP.NET Core s generováním adres URL nefungují dobře. Tým ASP.NET Core plánuje přidat funkce, které budou tyto potřeby řešit v budoucí verzi. Pro tuto dobu je nejlepším řešením použít starší verzi směrování.
Následující kód ukazuje příklad schématu generování adres URL, které směrování nepodporuje.
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 se parametr culture trasy používá pro lokalizaci. Touhou je mít culture parametr vždy přijatý jako ambientní hodnotu. Parametr však není přijat jako ambientní hodnota kvůli culture způsobu, jakým požadované hodnoty fungují:
- V šabloně trasy je parametr trasy nalevo od , takže změny na nezoplatní
"default"culturecontrollercontrollerculture. - V šabloně trasy se parametr trasy považuje za napravo od , který se zobrazuje
"blog"culturevcontrollerpožadovaných hodnotách.
Konfigurace metadat koncového bodu
Na následujících odkazech najdete informace o konfiguraci metadat koncového bodu:
- Povolení Cors se směrováním koncového bodu
- Ukázka IAuthorizationPolicyProvider s použitím vlastního
[MinimumAgeAuthorize]atributu - Testování ověřování s atributem [Authorize]
- RequireAuthorization
- Výběr schématu s atributem [Authorize]
- Použití zásad pomocí atributu [Authorize]
- Ověřování na základě rolí v ASP.NET Core
Párování hostitelů v trasách pomocí RequireHost
RequireHost aplikuje na trasu omezení, které vyžaduje zadaného hostitele. Parametr RequireHost nebo [Host] může být:
- Hostitel:
www.domain.comodpovídáwww.domain.comlibovolnému portu. - Hostitel se zástupným znakem:
*.domain.com, odpovídá , nebo nawww.domain.comsubdomain.domain.comwww.subdomain.domain.comlibovolném portu. - Port:
*:5000– odpovídá portu 5000 libovolnému hostiteli. - Hostitel a port: nebo – odpovídá hostiteli a
www.domain.com:5000*.domain.com:5000portu.
Pomocí nebo je možné zadat RequireHost více [Host] parametrů. Toto omezení odpovídá hostitelům platným pro kterýkoli z parametrů. Například odpovídá [Host("domain.com", "*.domain.com")] , domain.com a www.domain.com 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á atribut [Host] na kontroleru k vyžadování libovolné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();
}
}
Při [Host] použití atributu na metodu kontroleru i akci:
- Použije se atribut akce.
- Atribut kontroleru se ignoruje.
Pokyny k výkonu pro směrování
Většina směrování se aktualizovala ve verzi ASP.NET Core 3.0, aby se zvýšil výkon.
Pokud má aplikace problémy s výkonem, je často podezření na směrování jako problém. Důvodem, proč je směrování podezřelé, je, že architektury, jako jsou kontrolery a Stránky, hlásí množství času stráveného v rámci architektury Razor ve svých protokolovacích zprávách. Pokud je mezi časem hlášenou kontrolery a celkovou časem požadavku velký 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í se testuje na výkonu pomocí tisíců koncových bodů. Je nepravděpodobné, že by typická aplikace narazila na problém s výkonem jen tím, že je příliš velká. Nejběžnější hlavní příčinou pomalého výkonu směrování je obvykle špatně se chovající vlastní middleware.
Následující ukázka kódu ukazuje základní techniku pro 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:
- Promyšlete každý middleware kopií middlewaru časování, která je zobrazena v předchozím kódu.
- Přidejte jedinečný identifikátor pro korelaci dat časování s kódem.
Toto je základní způsob, jak zúžit zpoždění, pokud je významné, například více než 10ms . Odečtení Time 2 od sestav čas Time 1 strávený uvnitř UseRouting middlewaru.
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 funkcí směrování, které jsou v porovnání se základními šablonami tras poměrně nákladné:
Regulární výrazy: Je možné psát regulární výrazy, které jsou složité nebo mají dlouhou dobu běhu s malým množstvím vstupů.
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ězců.
- Logika komplexního segmentu se v aktualizaci výkonu směrování ASP.NET Core 3.0 ne aktuální.
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ší nemusí poskytovat správné body rozšiřitelnosti pro podporu směrování přístupu k databázi. Například , IRouteConstraint a IActionConstraint jsou synchronní. Body rozšiřitelnosti, jako MatcherPolicy jsou a , jsou EndpointSelectorContext asynchronní.
Pokyny pro velké směrovací tabulky
Ve výchozím ASP.NET Core používá algoritmus směrování, který vymění paměť za čas procesoru. To má dobrý účinek, že čas párování tras závisí pouze na délce cesty, která se má shodovat, a ne na počtu tras. Tento přístup však může být v některých případech problematický, pokud má aplikace velký počet tras (v tisících) a v trasách je velké množství proměnných předpon. Pokud například trasy mají parametry v počátečních segmentech trasy, například {parameter}/some/literal .
Je nepravděpodobné, že by aplikace našla do situace, kdy se jedná o problém, pokud:
- V aplikaci existuje vysoký počet tras, které tento model používají.
- V aplikaci je velký počet tras.
Jak zjistit, jestli u aplikace dochází k problému s velkou směrovací tabulkou
- Existují dva symthomy, které můžete hledat:
- Spuštění aplikace při prvním požadavku je pomalé.
- Všimněte si, že je to povinné, ale nestačí. Existuje mnoho dalších problémů, které nejsou směrované, než může způsobit pomalé spouštění aplikace. Zkontrolujte následující podmínku, abyste přesně určili, že aplikace v této situaci běží.
- Aplikace spotřebovává hodně paměti během spouštění a výpis paměti zobrazuje velký
Microsoft.AspNetCore.Routing.Matching.DfaNodepočet instancí.
- Spuštění aplikace při prvním požadavku je pomalé.
Jak tento problém vyřešit
Existuje několik technik a optimalizací pro trasy, které tento scénář do značné míry zlepší:
- Pokud je to možné, použijte na parametry omezení tras, 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žití paměti.
- Ve většině případů to bude stačit k tomu, 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ídaly 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í a
MapDynamicControllerRouteMapDynamicPageRoute.
- Toho lze dosáhnout pomocí a
Pokyny pro autory knihoven
Tato část obsahuje pokyny pro autory knihoven, kteří staví na směrování. Účelem 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 rozhraní, 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 nad . UseEndpoints
Proveďte sestavení nad IEndpointRouteBuilder . To umožňuje uživatelům vytvářet vaše rozhraní 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 přítomné a známé.
app.UseEndpoints(endpoints =>
{
// Your framework
endpoints.MapMyFramework(...);
endpoints.MapHealthChecks("/healthz");
});
Vraťte zapečetěný konkrétní typ z volání MapMyFramework(...) , které implementuje IEndpointConventionBuilder . Tento model Map... dodržuje většina metod architektury. IEndpointConventionBuilderRozhraní:
- Umožňuje kompozibilitu metadat.
- Cílí na různé rozšiřující metody.
Deklarování vlastního typu umožňuje přidat do tvůrce vlastní funkce specifické pro rozhraní. 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ích EndpointDataSource . EndpointDataSource je primitiv nízké úrovně pro deklaraci 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 ne aktualizací zdroje dat.
NEPOKOUŠEJTE se zaregistrovat EndpointDataSource ve výchozím nastavení. Vyžadovat, aby si uživatelé zaregistroval vaši rozhraní v UseEndpoints . Filozofií směrování je, že ve výchozím nastavení není nic zahrnuto a je to místo pro UseEndpoints registraci koncových bodů.
Vytvoření middlewaru integrovaného se směrováním
ZVAŽTE definování typů metadat jako rozhraní.
U tříd a metod je možné používat typy metadat jako atribut.
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 stránky, podporují použití atributů metadat na typy a Razor metody. Pokud deklarujete typy metadat:
- Zajistěte, aby byly přístupné jako atributy.
- Většina uživatelů zná použití atributů.
Deklarování typu metadat jako rozhraní přidává další vrstvu flexibility:
- Rozhraní jsou smyšitelná.
- Vývojáři mohou deklarovat své vlastní typy, které kombinují více zásad.
Proveďte, aby bylo možné 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ším způsobem, jak postupovat podle těchto pokynů, je vyhnout se definování metadat značek:
- Ne hledejte jen přítomnost typu metadat.
- Definujte vlastnost metadat a zkontrolujte vlastnost .
Kolekce metadat je seřazená a podporuje přepisování podle priority. V případě kontrolerů jsou metadata metody akce nej specifická.
Zajistěte, aby byl middleware užitečný se směrováním a bez něj.
app.UseRouting();
app.UseAuthorization(new AuthorizationPolicy() { ... });
app.UseEndpoints(endpoints =>
{
// Your framework
endpoints.MapMyFramework(...).RequireAuthorization();
});
Jako příklad tohoto návodu zvažte UseAuthorization middleware. Autorizační middleware umožňuje předat záložní zásady. Pokud jsou zadané záložní zásady, platí pro oba typy:
- Koncové body bez zadané zásady.
- Požadavky, které neodpovídají koncovému bodu.
Díky tomu je autorizační middleware užitečný mimo kontext směrování. Autorizační middleware je možné použít pro tradiční programování middlewaru.
Diagnostika ladění
Pro podrobný výstup diagnostiky směrování nastavte Logging:LogLevel:Microsoft na Debug . Ve vývojovém prostředí nastavte úroveň protokolu v appsettings.Development.jsna:
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Debug",
"Microsoft.Hosting.Lifetime": "Information"
}
}
}
Směrování zodpovídá za párová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 pro zpracování požadavků aplikace. Koncové body se definují v aplikaci a konfiguruje při spuštění aplikace. Proces párování koncových bodů může extrahovat hodnoty z adresy URL požadavku a zadat tyto hodnoty pro zpracování požadavků. Pomocí informací o koncových bodech z aplikace může směrování také generovat adresy URL, které se mapují na koncové body.
Aplikace mohou konfigurovat směrování pomocí:
- Kontrolery
- Razor Stránky
- SignalR
- Služby gRPC
- Middleware s povoleným koncovým bodem, například kontroly stavu.
- Delegáty a výrazy lambda zaregistrované se směrováním.
Tento dokument popisuje podrobné informace o směrování ASP.NET Core úrovni. Informace o konfiguraci směrování:
- Informace o kontrolerů najdete v tématu Směrování na akce kontroleru v ASP.NET Core .
- Konvence Razor pages najdete v tématu RazorSměrování stránek 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ší. Pokud chcete získat informace o předchozím systému směrování založeném na , vyberte IRouter verzi ASP.NET Core 2.1 pomocí jednoho z následujících přístupů:
- Selektor verzí pro předchozí verzi.
- Vyberte ASP.NET Core směrování 2.1.
Zobrazení nebo stažení ukázkového kódu (stažení)
Ukázky ke stažení pro tento dokument jsou povolené konkrétní Startup třídou. Pokud chcete spustit konkrétní ukázku, upravte soubor Program.cs tak, aby volal požadovanou Startup třídu.
Základy směrování
Všechny ASP.NET Core zahrnují směrování ve vygenerovaného kódu. Směrování je zaregistrované v middlewaru kanálu 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 v a UseRouting UseEndpoints :
UseRoutingpřidá do middlewarového kanálu párování tras. Tento middleware se podívá na sadu koncových bodů definovaných v aplikaci a vybere nejlepší shodu na základě požadavku.UseEndpointspřidá spuštění koncového bodu do middlewarového kanálu. 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
GETna kořenovou adresu URL/:- Zobrazený delegát požadavku se provede.
Hello World!se zapisovat do odpovědi HTTP. Ve výchozím nastavení je kořenová adresa URL/https://localhost:5001/.
- Pokud metoda požadavku není nebo kořenová adresa URL není , žádná trasa se shoduje a vrátí se
GET/chyba 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.
- Spuštěno spuštěním delegáta.
Koncové body, které může aplikace spárovat a spustit, se konfigurují v UseEndpoints . Například , a podobné metody MapGet MapPost připojují delegáty požadavků ke směrovacímu systému.
Další metody lze použít k připojení ASP.NET Core architektury ke směrovacímu systému:
- Stránky Razor mapy pro Razor stránky
- MapControllery pro kontrolery
- MapHub <THub> pro SignalR
- MapGrpcService <TService> pro gRPC
Následující příklad ukazuje směrování s důmyslně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 je /hello/{name:alpha} šablona trasy. Slouží ke konfiguraci shody koncového bodu. V tomto případě šablona odpovídá:
- Adresa URL, například
/hello/Ryan - Libovolná cesta URL, která začíná na
/hello/následovanou posloupností abecedních znaků.:alphapoužije omezení trasy, které odpovídá pouze abecedním znakům. Omezení tras jsou vysvětlena dále v tomto dokumentu.
Druhý segment cesty {name:alpha} URL:
- Je svázán s
nameparametrem . - Je zachycen a uložen v HttpRequest.RouteValues.
Systém směrování koncových bodů popsaný v tomto dokumentu je od verze ASP.NET Core 3.0 nový. Všechny verze šablon ale ASP.NET Core 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ž angličtiny, dejte nám vědět v tomto problému diskuze na GitHubu.
Předchozí příklad ukazuje, jak:
- Autorizační middleware je možné použít se směrováním.
- Koncové body je možné použít ke konfiguraci chování autorizace.
Volání MapHealthChecks přidá koncový bod kontroly stavu. RequireAuthorizationZřetězování s tímto voláním připojí ke koncovému bodu zásady autorizace.
Zavolá UseAuthentication a přidá ověřovací a UseAuthorization autorizační middleware. Mezi a se umístí UseRouting UseEndpoints middleware, aby mohl:
- Podívejte se, který koncový bod vybral
UseRouting. - Před odesláním do UseEndpoints koncového bodu použijte zásady autorizace.
Metadata koncového bodu
V předchozím příkladu jsou dva koncové body, ale připojené jsou jenom koncové body kontroly stavu. Pokud požadavek odpovídá koncovému bodu kontroly stavu , provede /healthz se kontrola autorizace. To ukazuje, že ke koncovým bodům mohou být připojena další data. Tato další data se nazývají metadata koncového bodu:
- Metadata je možné zpracovat middlewarem se směrováním.
- Metadata mohou být libovolného typu .NET.
Koncepty směrování
Systém směrování vychází z middlewarového kanálu přidáním výkonného konceptu koncového bodu. Koncové body představují jednotky funkcí aplikace, které se navzájem liší z hlediska směrování, autorizace a libovolného ASP.NET Core systémů aplikace.
ASP.NET Core definice koncového bodu
Koncový ASP.NET Core je:
- Spustitelný soubor: Má RequestDelegate .
- Extensible: Obsahuje kolekci metadat.
- Volitelné: Volitelně obsahuje informace o směrování.
- Vyčíslitelné: Kolekci koncových bodů lze zobrazit načtením objektu EndpointDataSource z injekcí.
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!");
});
});
}
Pokud vyberete koncový bod, můžete ho načíst z HttpContext . Jeho vlastnosti je možné zkontrolovat. Objekty koncových bodů jsou neměnné a po vytvoření je nelze změnit. Nejběžnějším typem koncového bodu je RouteEndpoint . RouteEndpoint obsahuje informace, které umožňují, aby ji systém směrování vybral.
V předchozím kódu je to aplikace. Pomocí se nakonfiguruje middlewarev řádku .
Následující kód ukazuje, že v závislosti na tom, kde se v kanálu app.Use volá, nemusí být 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. Pro přehlednost ukázka přiřadí zobrazovaný název zadanému koncovému / bodu.
Spuštěním tohoto kódu s adresou URL / se zobrazí:
1. Endpoint: (null)
2. Endpoint: Hello
3. Endpoint: Hello
Při spuštění tohoto kódu s libovolnou jinou adresou URL se zobrazí:
1. Endpoint: (null)
2. Endpoint: (null)
4. Endpoint: (null)
Tento výstup ukazuje, že:
- Koncový bod má před voláním
UseRoutingvždy hodnotu null. - Pokud je nalezena shoda, koncový bod mezi a není
UseRoutingUseEndpoints null. - Middleware
UseEndpointsje terminál, když je nalezena shoda. Middleware terminálu je definován dále v tomto dokumentu. - Middleware po spuštění
UseEndpointspouze v případě, že není 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 vlastní logikou a stále využívat výhody UseRouting používání koncových bodů. Koncové body jsou primitivní prvky nízké úrovně, jako je middleware, a nejsou souovány s implementací směrování. Většina aplikací nemusí nahrazovat UseRouting vlastní logikou.
UseEndpointsMiddleware je navržená tak, aby se mohla používat společně s UseRouting middlewarem. Základní logika pro spuštění koncového bodu není složitá. Použijte GetEndpoint k načtení koncového bodu a poté jeho vlastnost vyvolejte RequestDelegate .
Následující kód ukazuje, jak middleware může ovlivnit směrování nebo reagovat na něj:
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 může běžet před
UseRoutingzměnou dat, na kterých funguje směrování.- Middleware, které se zobrazují před směrováním, mění určitou vlastnost žádosti, jako UseRewriter je například, UseHttpMethodOverride nebo UsePathBase .
- Middleware může běžet mezi
UseRoutinga UseEndpoints ke zpracování výsledků směrování před provedením koncového bodu.- Middleware spouštěné mezi
UseRoutingaUseEndpoints:- Obvykle kontroluje metadata pro pochopení koncových bodů.
- Často provádí rozhodnutí o zabezpečení, jak to dělá
UseAuthorizationaUseCors.
- Kombinace middlewaru a metadat umožňuje konfigurovat zásady na koncový bod.
- Middleware spouštěné mezi
Předchozí kód ukazuje příklad vlastního middlewaru, který podporuje zásady pro jednotlivé koncové body. Middleware zapisuje protokol auditu přístupu k citlivým datům do konzoly. Middleware je možné nakonfigurovat pro audit koncového bodu s AuditPolicyAttribute metadaty. Tato ukázka předvádí vzor výslovných přihlášení, kde jsou auditovány pouze koncové body označené jako citlivé. Tuto logiku je možné definovat obráceně a auditovat vše, co není označeno 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ý odpovídá 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čena pro použití v produkčním prostředí. Ucelená verze middlewaru protokolu auditu by mohla:
- 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 AuditPolicyAttribute jsou definována jako Attribute pro snazší použití s architekturami založenými na třídách, jako jsou například řadiče a SignalR . Při použití směrování na kód:
- K rozhraní API tvůrce se připojují metadata.
- Rozhraní založená na třídě zahrnují všechny atributy odpovídající metody a třídy při vytváření koncových bodů.
Osvědčené postupy pro typy metadat jsou jejich definování buď jako rozhraní, nebo jako atributy. Rozhraní a atributy umožňují opakované použití kódu. Systém metadat je flexibilní a nezavádí žádná omezení.
Porovnání middlewaru a směrování terminálu
Následující ukázka kódu kontrastuje pomocí middlewaru s použitím směrování:
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 middleware zobrazený v nástroji Approach 1: je middleware terminálu. Nazývá middleware terminálu, protože se jedná o shodnou operaci:
- Operace porovnání v předchozím příkladu je určena
Path == "/"pro middleware aPath == "/Movie"pro směrování. - Po úspěšné shodě se spustí některé funkce a vrátí místo vyvolání
nextmiddlewaru.
Nazývá middleware terminálu, protože ukončí hledání, spustí některé funkce a pak vrátí.
Porovnání middlewaru a směrování terminálu:
- Oba přístupy umožňují ukončení kanálu zpracování:
- Middleware ukončí kanál vrácením místo vyvolání
next. - Koncové body jsou vždycky Terminálové.
- Middleware ukončí kanál vrácením místo vyvolání
- Middleware terminálu umožňuje umístění middlewaru na libovolné místo v kanálu:
- Koncové body jsou spouštěny v pozici UseEndpoints .
- Middleware terminálu umožňuje libovolnému kódu určit, kdy se middleware shoduje:
- Kód pro přizpůsobení vlastní trasy může být podrobný a obtížně zapisovat.
- Směrování poskytuje jednoduchá řešení pro běžné aplikace. Většina aplikací nevyžaduje kód pro přizpůsobení vlastní trasy.
- Rozhraní koncových bodů s middlewarem, jako je
UseAuthorizationaUseCors.- Použití middleware terminálu pro
UseAuthorizationneboUseCorsvyžaduje ruční propojení s autorizačním systémem.
- Použití middleware terminálu pro
Koncový bod definuje:
- Delegát pro zpracování požadavků.
- Kolekce libovolných metadat Metadata se používají k implementaci průřezových obav na základě zásad a konfigurace připojených ke každému koncovému bodu.
Middleware terminálu může být účinný nástroj, ale může vyžadovat:
- Významné množství kódu a testování.
- Ruční integrace s jinými systémy pro dosažení požadované úrovně flexibility.
Před zápisem middleware terminálu zvažte integraci se směrováním.
Existující middleware terminálu, který se integruje s mapou , nebo MapWhen se obvykle může přepínat na koncový bod podporující směrování. MapHealthChecks ukazuje vzor pro router:
- Zápis metody rozšíření na IEndpointRouteBuilder .
- Vytvořte vnořený kanál middlewaru pomocí CreateApplicationBuilder .
- Připojte middleware k novému kanálu. V tomto případě UseHealthChecks .
- Build kanál middlewaru do RequestDelegate .
- Zavolejte
Mapa poskytněte nový kanál middlewaru. - Vrátí objekt tvůrce poskytnutý
Mapz metody 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í příklad ukazuje, proč je důležité vracet objekt tvůrce. Vrácení objektu Tvůrce umožňuje vývojářům aplikací nakonfigurovat zásady, jako je například autorizace pro koncový bod. V tomto příkladu middleware pro kontrolu stavu nemá přímou integraci s autorizačním systémem.
Systém metadat byl vytvořen v reakci na problémy zjištěné rozšířením autoři pomocí middlewaru terminálu. U každého middlewaru je problematické implementovat svou vlastní integraci s autorizačním systémem.
Shoda adresy URL
- Je proces, podle kterého směrování odpovídá příchozímu požadavku na koncový bod.
- Je založena na datech v cestě a hlavičkách URL.
- Dá se rozšířit tak, aby v žádosti mohla být považovat všechna data.
Když middleware směrování spustí, nastaví v Endpoint rámci aktuální žádosti hodnoty a směrování na funkci Request HttpContext .
- Volání HttpContext. GetEndPoint získá koncový bod.
HttpRequest.RouteValuesZíská kolekci hodnot tras.
Middleware spuštěný poté, co middleware směrování může zkontrolovat koncový bod a provést akci. Middleware autorizace může například dotazování kolekci metadat koncového bodu pro zásadu autorizace. Po spuštění všech middlewarů v kanálu zpracování požadavků je vyvolán delegát vybraného koncového bodu.
Systém směrování v rámci směrování koncových bodů zodpovídá za všechna 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í.
Upozornění
Pro zpětnou kompatibilitu, když Razor je spuštěný delegát koncového bodu kontroleru nebo stránek, jsou vlastnosti RouteContext. parametr RouteData nastaveny na odpovídající hodnoty na základě dosud provedeného zpracování požadavků.
RouteContextTyp bude v budoucí verzi označen jako zastaralý:
- Migrujte
RouteData.ValuesnaHttpRequest.RouteValues. - Migrujte
RouteData.DataTokenspro načtení IDataTokensMetadata z metadat koncového bodu.
Shoda adresy URL funguje v konfigurovatelné sadě fází. V každé fázi je výstupem sada shod. Množinu shody lze v další fázi zúžit. Implementace směrování nezaručuje pořadí zpracování pro porovnání koncových bodů. Všechny možné shody jsou zpracovávány současně. V následujícím pořadí se shodují tyto fáze adresy URL. ASP.NET Core:
- Zpracuje cestu URL proti sadě koncových bodů a jejich šablonám směrování a shromažďují všechny shody.
- Převezme předchozí seznam a odstraní shody, které selžou s použitými omezeními směrování.
- Převezme předchozí seznam a odstraní shody, které selžou sadu instancí MatcherPolicy .
- Použije EndpointSelector k konečnému rozhodnutí z předchozího seznamu.
Seznam koncových bodů má prioritu podle těchto hodnot:
- RouteEndpoint.Order
- Priorita šablony trasy
Všechny odpovídající koncové body se zpracovávají v každé fázi, dokud se EndpointSelector nedosáhlo hodnoty . EndpointSelectorje poslední fáze. Jako nejlepší shodu zvolí koncový bod s nejvyšší prioritou ze shod. Pokud existují jiné shody se stejnou prioritou jako nejlepší shoda, je vyvolána nejednoznačná výjimka shody.
Priorita trasy se počítá na základě konkrétnější šablony trasy s vyšší prioritou. Zvažte například šablony a /hello /{message} :
- Obě odpovídají cestě URL
/hello. /helloje konkrétnější, a proto má vyšší prioritu.
Obecně platí, že priorita tras je dobrou úlohou při výběru nejlepší shody pro druhy schémat adres URL používaných v praxi. Používejte ho jenom v případě potřeby, abyste se Order vyhnuli nejednoznačnosti.
Vzhledem k druhům rozšiřitelnosti poskytovaným směrováním není možné, aby systém směrování předem spočítal nejednoznačné trasy. Představte si například šablony tras a /{message:alpha} /{message:int} :
- Omezení
alphaodpovídá pouze abecedním znakům. - Omezení
intodpovídá pouze číslům. - Tyto šablony mají stejnou prioritu trasy, ale neexistuje žádná jedna adresa URL, kterou by obě měly.
- Pokud systém směrování nahlásil při spuštění nejednoznačnost, zablokuje by tento platný případ použití.
Upozornění
Pořadí operací uvnitř UseEndpoints nemá vliv na chování směrování s jednou výjimkou. MapControllerRouteMapAreaRoutea automaticky přiřadí hodnotu objednávky koncovým bodům na základě pořadí, ve které jsou vyvolány. Tím se simuluje dlouhodobé chování kontrolerů bez systému směrování, který poskytuje stejné záruky jako starší implementace směrování.
Ve starší verzi implementace směrování je možné implementovat rozšiřitelnost směrování, která je závislá na pořadí, ve kterém se zpracovávají trasy. Směrování koncových bodů v ASP.NET Core 3.0 a novějších verzích:
- Nemá koncept tras.
- Neposkytuje záruky objednávání. Všechny koncové body se zpracovávají najednou.
Priorita šablony směrování a pořadí výběru koncových bodů
Priorita šablony trasy je systém, který každé šabloně trasy přiřadí hodnotu na základě toho, jak specifická je. Priorita šablony trasy:
- V běžných případech není potřeba upravovat pořadí koncových bodů.
- Pokusí se přizpůsobit běžným očekáváním ohledně chování směrování.
Zvažte například šablony a /Products/List /Products/{id} . Bylo by rozumné předpokládat, že /Products/List je lepší shoda než /Products/{id} cesta URL /Products/List . To funguje, protože segment literálů má lepší /List prioritu než segment parametrů /{id} .
Podrobnosti o tom, jak priorita funguje, jsou řazeny podle toho, jak jsou definovány šablony tras:
- Šablony s více segmenty se považují za konkrétnější.
- Segment s textem literálu se považuje za konkrétnější než segment parametrů.
- Segment parametrů s omezením se považuje za konkrétnější než segment bez parametru.
- Komplexní segment se považuje za specifický jako segment parametrů s omezením.
- Parametry catch-all jsou nejméně specifické. Důležité informace o všech trasách najdete v části catch-all v referenčních informacích k šablonám tras.
Referenční informace o přesných GitHub najdete ve zdrojovém kódu na GitHub kódu.
Koncepty generování adres URL
Generování adres URL:
- Je proces, pomocí kterého může směrování 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 rozhraní LinkGenerator API. LinkGenerator je jednosměnná služba dostupná od di. Rozhraní LinkGenerator API je možné použít mimo kontext spuštěného požadavku. Mvc.IUrlHelper a scénáře, které spoléhají na , jako jsou například pomocníci značek, pomocníci HTML a výsledky akcí, interně používají rozhraní API k poskytování možností generování IUrlHelper LinkGenerator odkazů.
Generátor odkazů je podchycený konceptem schémat adres a adres. Schéma adres je způsob určení koncových bodů, které by se měly zvážit při generování propojení. Například scénáře s názvem trasy a hodnotami tras, které mnoho uživatelů zná z kontrolerů, a Stránky jsou implementované Razor 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ímá argumenty, které zahrnují HttpContext . Tyto metody jsou funkčně ekvivalentní metodám Url.Action a Url.Page, ale nabízejí větší flexibilitu a možnosti.
Metody jsou nejvíce podobné a v tom, že GetPath* Url.Action Url.Page generují 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 identifikátor URI, generují identifikátor URI v kontextu prováděného požadavku. Hodnoty okolí trasy, základní cesta URL, schéma a hostitel z prováděného požadavku se používají, pokud nejsou přepsány.
LinkGenerator se volá s adresou. K vygenerování identifikátoru URI dochází ve dvou krocích:
- Adresa je svázaná se seznamem koncových bodů, které odpovídají adrese.
- Hodnoty jednotlivých koncových bodů se vyhodnocují, dokud se nenasátí vzor trasy, který odpovídá RoutePattern zadaným hodnotám. Výsledný výstup se zkombinuje s ostatními částmi identifikátoru URI dodávanými generátoru odkazů a vrátí se.
Metody, které poskytuje LinkGenerator podpora standardních možností generování propojení pro libovolný typ adresy. Nejpohodlnější způsob použití generátoru odkazů je prostřednictvím rozšiřujících metod, které provádějí operace pro konkrétní typ adresy:
| Extension – metoda | Description |
|---|---|
| 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. |
Upozornění
Věnujte pozornost následujícím důsledkům volání LinkGenerator metod:
V konfiguraci aplikace, která neověřuje hlavičku příchozích požadavků, používejte metody
GetUri*Hostrozšíření obezřetně. Pokud se hlavička příchozích požadavků neověřuje, může se vstup nedůvěryhodné žádosti odeslat zpět klientovi v identifikátorech URI v zobrazeníHostnebo na stránce. Doporučujeme všem produkčním aplikacím nakonfigurovat server tak, aby ověřilHosthlavičku na známé platné hodnoty.Při LinkGenerator použití middlewaru v kombinaci s nebo
Mappoužívejte obezřetně.MapWhenMap*změní základní cestu prováděného požadavku, což má vliv na výstup generování propojení. Všechna rozhraní LinkGenerator API umožňují zadat základní cestu. Zadejte prázdnou základní cestu, která vrátíMap*zpět vliv na generování propojení.
Příklad middlewaru
V následujícím příkladu middleware používá rozhraní API k vytvoření odkazu na metodu akce, která LinkGenerator obsahuje seznam položek pro ukládání produktů. Použití generátoru odkazů jeho vložením do třídy a volání je k dispozici pro GenerateLink 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ě směrování
Tokeny v {} rámci definují parametry trasy, které jsou vázané, pokud se trasa shoduje. V segmentu trasy lze definovat více než jeden parametr trasy, ale parametry trasy musí být oddělené hodnotou literálu. Například není platná trasa, protože mezi a neexistuje žádná {controller=Home}{action=Index} {controller} literálová {action} hodnota. Parametry trasy musí mít název a mohou mít zadané další atributy.
Literálový text jiný než parametry trasy (například ) a oddělovač cesty se musí shodovat {id} / s textem v adrese URL. Porovnávání textu rozlišuje malá a velká písmena a vychází z dekódované reprezentace cesty adresy URL. Pokud chcete použít oddělovač parametrů trasy literálu nebo , uvozte 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 zbytek identifikátoru URI.
- Nazývají se zachytávané všechny parametry. Například
blog/{**slug}:- Odpovídá libovolnému identifikátoru URI, který začíná na a
/blogmá za ním libovolnou hodnotu. - Následující hodnota
/blogse přiřadí k hodnotě trasy slug.
- Odpovídá libovolnému identifikátoru URI, který začíná na a
Upozornění
Parametr catch-All může nesprávně odpovídat trasy z důvodu chyby v směrování. Aplikace ovlivněné touto chybou mají následující vlastnosti:
- Například trasa typu catch-ALL.
{**slug}" - Trasa catch-All nesplňuje požadavky, které by se měla shodovat.
- Při odebrání jiných tras bude vše začít pracovat.
Příklady přístupů k této chybě najdete v tématu chyby GitHubu 18677 a 16579 .
Oprava pro tuto chybu je obsažená v sadě .NET Core 3.1.301 SDK a novější. Následující kód nastaví interní přepínač, který vyřeší tuto chybu:
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 se také mohou shodovat s prázdným řetězcem.
Parametr catch-all uchytí příslušné znaky, pokud se trasa použije k vygenerování adresy URL, včetně znaků / oddělovače cesty. Například trasa s hodnotami foo/{*path} trasy generuje { path = "my/path" } foo/my%2Fpath . Všimněte si lomítka s uvoze znaky. Pokud chcete znaky oddělovače cesty round-trip použít ** předponu parametru trasy. Trasa s foo/{**path} { path = "my/path" } vygeneruje foo/my/path .
Vzory adres URL, které se pokoušejí zachytit název souboru s volitelnou příponou souboru, mají další aspekty. Zvažte například šablonu files/{filename}.{ext?} . Pokud existují hodnoty filename pro i , naplní se obě ext hodnoty. Pokud v adrese URL existuje pouze hodnota pro , trasa filename se shoduje, protože koncový znak . je volitelný. Následující adresy URL odpovídají této trase:
/files/myFile.txt/files/myFile
Parametry trasy mohou mít výchozí hodnoty určené zadáním výchozí hodnoty za názvem parametru odděleným znaménkem rovná se ( = ). Například definuje {controller=Home} jako výchozí hodnotu pro Home controller . Výchozí hodnota se použije, pokud adresa URL parametru nemá žádnou hodnotu. Parametry trasy jsou volitelné připojením otazník ( ) na ? konec názvu parametru. Například, id?. Rozdíl mezi volitelnými hodnotami a výchozími parametry trasy je následující:
- Parametr trasy s výchozí hodnotou vždy vytvoří hodnotu.
- Volitelný parametr má hodnotu pouze v případě, že je hodnota poskytnuta adresou URL požadavku.
Parametry trasy mohou mít omezení, která musí odpovídat hodnotě trasy svázané s adresou URL. Přidání a název omezení za název parametru trasy určuje vložené : omezení parametru trasy. Pokud omezení vyžaduje argumenty, jsou uzavřeny v závorkách (...) za názvem omezení. Více v řádku omezení lze zadat připojením jiného názvu a názvu : omezení.
Název omezení a argumenty se předá službě, aby se vytvořila instance , IInlineConstraintResolver která se má použít při zpracování adresy IRouteConstraint URL. Šablona trasy například určuje blog/{article:minlength(10)} omezení minlength s argumentem 10 . Další informace o omezeních tras a seznam omezení poskytovaných architekturou najdete v části Referenční informace o omezeních tras.
Parametry trasy mohou mít také transformátory parametrů. Transformace parametrů transformují hodnotu parametru při generování odkazů a odpovídajících akcí a stránek na adresy URL. Podobně jako omezení je možné transformační parametry přidat do parametru trasy vložením názvu a : transformeru za název parametru trasy. Například šablona trasy určuje blog/{article:slugify} slugify transformer. Další informace o transformátorech parametrů najdete v referenční části Parameter Transformer.
Následující tabulka ukazuje příklady šablon 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 nastavuje Page na Home . |
{Page=Home} |
/Contact |
Odpovídá a nastavuje Page na Contact . |
{controller}/{action}/{id?} |
/Products/List |
Mapy ke Products kontroleru a List akci. |
{controller}/{action}/{id?} |
/Products/Details/123 |
Mapy kontroleru Products a Details akci s id nastavenou na 123. |
{controller=Home}/{action=Index}/{id?} |
/ |
Mapy ke Home kontroleru a Index metodě. id se ignoruje. |
{controller=Home}/{action=Index}/{id?} |
/Products |
Mapy ke Products kontroleru a Index metodě. id se ignoruje. |
Použití šablony je obecně nejjednodušším přístupem ke směrování. Omezení a výchozí hodnoty je také možné zadat mimo šablonu trasy.
Složité segmenty
Složité segmenty se zpracovávají porovnáním literálových oddělovačů zprava doleva jinak než greedy. Například je [Route("/a{b}c{d}")] komplexní segment.
Složité segmenty fungují konkrétním způsobem, který je třeba pochopit, aby je bylo možné úspěšně používat. Příklad v této části ukazuje, proč složité segmenty ve skutečnosti fungují dobře jenom v případě, že se text oddělovače nezobrazuje 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.
Upozornění
Při použití System.Text.RegularExpressions ke zpracování nedůvěryhodného vstupu předejte časový limit. Uživatel se zlými úmysly může poskytnout vstup pro RegularExpressions útok DoS (Denial-of-Service). Rozhraní API rozhraní ASP.NET Core Framework, která používají RegularExpressions předávat časový limit.
Toto je souhrn kroků, které směrování provádí se šablonou a /a{b}c{d} cestou URL /abcd . Slouží | k vizualizaci toho, jak algoritmus funguje:
- První literál zprava doleva je
c. Proto/abcdse prohledá zprava a najde/ab|c|d. - Všechno napravo (
d) se teď shoduje s parametrem trasy{d}. - Další literál zprava doleva je
a. Prohledá/ab|c|dse tedy od místa, kde jsme opustili , a pak jsme našlia/|a|b|c|d. - Hodnota vpravo (
b) se teď shoduje s parametrem trasy{b}. - Neexistuje žádný zbývající text a žádná zbývající šablona trasy, takže se jedná o shodu.
Tady je příklad negativního případu s použitím stejné šablony a /a{b}c{d} cesty adresy URL /aabcd . Slouží | k vizualizaci toho, jak algoritmus funguje. Tento případ neodpovídá, což je vysvětleno stejným algoritmem:
- První literál zprava doleva je
c. Proto/aabcdse prohledá zprava a najde/aab|c|d. - Všechno napravo (
d) se teď shoduje s parametrem trasy{d}. - Další literál zprava doleva je
a. Prohledá/aab|c|dse tedy od místa, kde jsme opustili , a pak jsme našlia/a|a|b|c|d. - Hodnota vpravo (
b) se teď shoduje s parametrem trasy{b}. - V tomto okamžiku zbývá text , ale algoritmus došla šablona trasy k analýze, takže
ase neshoduje.
Vzhledem k tomu, že algoritmus porovnávání není greedy:
- Odpovídá co nejmenšímu množství textu v každém kroku.
- Všechny případy, kdy se hodnota oddělovače zobrazí uvnitř hodnot parametrů, nebudou se shodovat.
Regulární výrazy poskytují mnohem větší kontrolu nad jejich chováním při porovnávání.
Shoda s greedy, která se také ví jako opožděná shoda, odpovídá největšímu možnému řetězci. Non-greedy odpovídá nejmenšímu možnému řetězci.
Referenční informace k omezení tras
Omezení tras se spustí, když dojde 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 správně nebo nepravdivá rozhodnutí o tom, jestli je hodnota přijatelná. Některá omezení tras používají data mimo hodnotu trasy ke zvážení, jestli je možné požadavek směrovat. Může například přijmout HttpMethodRouteConstraint nebo odmítnout požadavek na základě svého slovesa HTTP. Omezení se používají při směrování požadavků a generování propojení.
Upozornění
Nepoužívejte omezení pro ověřování vstupu. Pokud se pro ověřování vstupu používají omezení, výsledkem neplatného vstupu je odpověď 404 Nenašl se. Neplatný vstup by měl vytvořit 400 chybný požadavek s příslušnou chybovou zprávou. Omezení tras slouží k jednoznačnosti podobných tras, ne k ověřování vstupů pro konkrétní trasu.
Následující tabulka ukazuje příklad omezení tras a jejich očekávané chování:
| omezení | Příklad | Příklady shod | Poznámky |
|---|---|---|---|
int |
{id:int} |
123456789, -123456789 |
Odpovídá libovolnému celému číslu. |
bool |
{active:bool} |
true, FALSE |
Odpovídá true nebo false . Case-insensitive |
datetime |
{dob:datetime} |
2016-12-31, 2016-12-31 7:32pm |
Odpovídá platné hodnotě DateTime v invariantní jazykové verzi. Viz předchozí upozornění. |
decimal |
{price:decimal} |
49.99, -1,000.01 |
Odpovídá platné hodnotě decimal v invariantní jazykové verzi. Viz předchozí upozornění. |
double |
{weight:double} |
1.234, -1,001.01e8 |
Odpovídá platné hodnotě double v invariantní jazykové verzi. Viz předchozí upozornění. |
float |
{weight:float} |
1.234, -1,001.01e8 |
Odpovídá platné hodnotě float 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 nesmí být delší než 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 se musí skládat z jednoho nebo více abecedních znaků a bez rozlišení a - z velkých a malých písmen. |
regex(expression) |
{ssn:regex(^\\d{{3}}-\\d{{2}}-\\d{{4}}$)} |
123-45-6789 |
Řetězec musí odpovídat regulárnímu výrazu. Viz tipy pro definování regulárního výrazu. |
required |
{name:required} |
Rick |
Slouží k vynucení, aby při generování adresy URL byla přítomna hodnota bez parametru. |
Upozornění
Při použití System.Text.RegularExpressions ke zpracování nedůvěryhodného vstupu předejte časový limit. Uživatel se zlými úmysly může poskytnout vstup pro RegularExpressions útok DoS (Denial-of-Service). Rozhraní API rozhraní ASP.NET Core Framework, která používají RegularExpressions předávat časový limit.
Omezení s více dvojtečkami s oddělovači lze použít na jeden parametr. 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) { }
Upozornění
Omezení tras, která ověřují adresu URL a jsou převedena na typ CLR, vždy používají neutrální jazykovou verzi. Například převod na typ CLR int nebo DateTime . Tato omezení předpokládají, že adresu URL nelze lokalizovat. Omezení tras poskytovaná architekturou neupraví hodnoty uložené v hodnotách tras. Všechny hodnoty tras 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í, že je možné ji převést float na float.
Regulární výrazy v omezeních
Upozornění
Při použití System.Text.RegularExpressions ke zpracování nedůvěryhodného vstupu předejte časový limit. Uživatel se zlými úmysly může poskytnout vstup pro RegularExpressions útok DoS (Denial-of-Service). Rozhraní API rozhraní ASP.NET Core Framework, která používají RegularExpressions předávat časový limit.
Regulární výrazy lze zadat jako vložené omezení pomocí regex(...) omezení trasy. Metody v MapControllerRoute rodině také přijímají objektový literál omezení. Pokud je tento formulář použit, jsou řetězcové hodnoty interpretovány jako regulární výrazy.
Následující kód používá omezení v řádku 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á objektový literál 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", });
});
Rozhraní ASP.NET Core přidá RegexOptions.IgnoreCase | RegexOptions.Compiled | RegexOptions.CultureInvariant do konstruktoru regulárního výrazu. Popis RegexOptions těchto členů najdete tady: .
Regulární výrazy používají oddělovače a tokeny podobné těm, které používá směrování a jazyk C#. Tokeny regulárního výrazu musí být uvozeny uvozovacími znaky. Pokud chcete použít regulární výraz ^\d{3}-\d{2}-\d{4}$ v vloženém omezení, použijte jednu z následujících možností:
- Nahraďte znaky zadané v řetězci jako znaky ve zdrojovém souboru C#, abyste řídicí znak řetězce
\\\\uniknou. - Doslovné řetězcové literály.
Pokud chcete řídicí znak oddělovače parametrů směrování , , , zdvojnásobte znaky ve výrazu, například { } , , , [ ] {{ }} [[ ]] . Následující tabulka obsahuje regulární výraz a jeho uvozenou verzi:
| Regulární výraz | Regulární výraz s uvozenou znaky |
|---|---|
^\d{3}-\d{2}-\d{4}$ |
^\\d{{3}}-\\d{{2}}-\\d{{4}}$ |
^[a-z]{2}$ |
^[[a-z]]{{2}}$ |
Regulární výrazy použité 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 zajišťují, že regulární výraz odpovídá celé hodnotě parametru trasy. Bez znaků a odpovídá regulární výraz libovolnému 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 selhávají:
| Výraz | Řetězec | Shoda | Komentář |
|---|---|---|---|
[a-z]{2} |
hello | Yes | Shody podřetězce |
[a-z]{2} |
123abc456 | Yes | Shody podřetězce |
[a-z]{2} |
Mz | Yes | Výraz shody |
[a-z]{2} |
MZ | Yes | Rozlišují se malá a velká písmena. |
^[a-z]{2}$ |
hello | No | Viz ^ a $ výše. |
^[a-z]{2}$ |
123abc456 | No | Viz ^ a $ výše. |
Další informace o syntaxi regulárních výrazů najdete v .NET Framework regulárních výrazů.
Pokud chcete parametr omezit na známou sadu možných hodnot, použijte regulární výraz. Například odpovídá {action:regex(^(list|get|create)$)} pouze hodnotě trasy , nebo action list get create . Pokud je předán do slovníku omezení, je ^(list|get|create)$ řetězec ekvivalentní. Omezení předaná ve slovníku omezení, která neodpovídají jednomu ze známých omezení, jsou také považována za regulární výrazy. Omezení předaná v rámci šablony, která neodpovídají jednomu ze známých omezení, nejsou považována za regulární výrazy.
Vlastní omezení tras
Vlastní omezení tras lze vytvořit implementací IRouteConstraint rozhraní . Rozhraní IRouteConstraint obsahuje , který vrátí hodnotu , pokud je omezení Match true splněno, a false v opačném případě .
Vlastní omezení tras jsou zřídka potřebná. Před implementací omezení vlastních tras zvažte alternativy, jako je například vazba modelu.
Dobrá ASP.NET Core omezení najdete ve složce Omezení. Například GuidRouteConstraint.
Pokud chcete použít vlastní , musí být typ omezení trasy zaregistrovaný u aplikace IRouteConstraint ConstraintMap v kontejneru služby. Je ConstraintMap slovník, který mapuje směrovací klíče omezení na IRouteConstraint implementace, které tato omezení ověřují. Aplikace je možné ConstraintMap aktualizovat v Startup.ConfigureServices obou službách. Volání AddRouting nebo konfigurací RouteOptions přímo pomocí services.Configure<RouteOptions> . Napří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 zobrazuje informace o trasách.
Implementace metody MyCustomConstraint brání použití na parametr 0 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;
}
}
Upozornění
Při použití System.Text.RegularExpressions ke zpracování nedůvěryhodného vstupu předejte časový limit. Uživatel se zlými úmysly může poskytnout vstup pro RegularExpressions útok DoS (Denial-of-Service). Rozhraní API rozhraní ASP.NET Core Framework, která používají RegularExpressions předávat časový limit.
Předchozí kód:
- Zabrání
0v{id}segmentu trasy. - Zobrazuje se základní příklad implementace vlastního omezení. Neměl by se používat v produkční aplikaci.
Následující kód je lepším způsobem, jak zabránit zpracování id 0 obsahujícího :
[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í MyCustomConstraint výhody:
- Nevyžaduje vlastní omezení.
- Pokud parametr trasy obsahuje , vrátí popisnější
0chybu.
Referenční informace k parameter transformeru
Parameter transformers (Transformátory parametrů):
- Spustí se při generování odkazu pomocí LinkGenerator .
- Implementujte Microsoft.AspNetCore.Routing.IOutboundParameterTransformer .
- Konfiguruje se 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é odkazu.
Například vlastní transformátor parametrů ve vzoru trasy s slugify blog\{article:slugify} vygeneruje Url.Action(new { article = "MyTestArticle" }) 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();
}
}
Pokud chcete použít transformátor parametrů ve vzoru trasy, nakonfigurujte ho pomocí v ConstraintMap Startup.ConfigureServices souboru :
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers();
services.AddRouting(options =>
{
options.ConstraintMap["slugify"] = typeof(SlugifyParameterTransformer);
});
}
Rozhraní ASP.NET Core používá transformace parametrů k transformaci identifikátoru URI, kde se překládá koncový bod. Například transformace parametrů transformují hodnoty tras, které se používají ke shodě area s , , a controller action page .
routes.MapControllerRoute(
name: "default",
template: "{controller:slugify=Home}/{action:slugify=Index}/{id?}");
S předchozí šablonou trasy se akce porovná SubscriptionManagementController.GetAll s identifikátorem URI /subscription-management/get-all . Parameter Transformer nemění hodnoty tras 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žívání transformátorů parametrů s generovanými trasami:
- Konvence Microsoft.AspNetCore.Mvc.ApplicationModels.RouteTokenTransformerConvention MVC aplikuje zadaný parameter transformer na všechny trasy atributů v aplikaci. Transformace parametrů transformuje tokeny směrování atributů při jejich nahrazování. Další informace najdete v tématu Přizpůsobení nahrazení tokenů pomocí parameter transformeru.
- Razor Stránky používají PageRouteTransformerConvention konvenci rozhraní API. Tato konvence aplikuje zadaný parametr transformer na všechny automaticky zjištěné Razor stránky. Transformace parametrů transformuje segmenty složek a názvů souborů tras Razor Pages. Další informace najdete v tématu Přizpůsobení tras stránek pomocí parameter transformeru.
Referenční informace ke generování adres URL
Tato část obsahuje odkaz na algoritmu implementované generováním adresy URL. V praxi nejsložitější příklady generování adres URL používají 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 metody LinkGenerator.GetPathByAddress nebo podobné metody. Metoda má adresu, sadu hodnot tras a volitelně informace o aktuálním požadavku z HttpContext .
Prvním krokem je použití adresy k překladu sady kandidátských koncových bodů pomocí typu adresy IEndpointAddressScheme<TAddress> .
Jakmile schéma adres nasvědčí sadě kandidátů, jsou koncové body seřazeny a zpracovány iterativně, dokud operace generování adresy URL nebude úspěšná. Generování adresy URL neschová nejednoznačnosti, první vrácený výsledek je konečný výsledek.
Řešení potíží s generováním adres URL s protokolováním
Prvním krokem při řešení potíží s generováním adres URL je nastavení úrovně protokolování Microsoft.AspNetCore.Routing na TRACE . LinkGenerator protokoluje mnoho podrobností o jeho zpracování, což 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 o generování adres URL.
Adresy
Adresy jsou koncept generování adres URL, který se používá k navázání volání do generátoru odkazů na sadu kandidátských koncových bodů.
Adresy jsou rozšiřitelný koncept, který se standardně dodá se dvěma implementacemi:
- Použití názvu koncového bodu (
string) jako adresy:- Poskytuje podobné funkce jako název trasy MVC.
- Používá IEndpointNameMetadata typ metadat.
- Překládá zadaný řetězec na metadata všech registrovaných koncových bodů.
- Vyvolá při spuštění výjimku, pokud více koncových bodů používá stejný název.
- Doporučuje se pro obecné účely mimo kontrolery a Razor stránky.
- Použití hodnot tras ( ) jako RouteValuesAddress adresy:
- Poskytuje podobné funkce jako kontrolery a Razor generování starších adres URL stránek.
- Rozšíření a ladění je velmi složité.
- Poskytuje implementaci, kterou používají
IUrlHelper, pomocníci značek, pomocníci HTML, výsledky akcí atd.
Rolí schématu adres je přidružení mezi adresou a odpovídajícími koncovými body na základě libovolných kritérií:
- Schéma názvu koncového bodu provádí základní slovníkové vyhledávání.
- Schéma hodnot tras má složitou nejlepší podmnožinu nastaveného algoritmu.
Ambientní hodnoty a explicitní hodnoty
Z aktuálního požadavku směrování přistupuje k hodnotám tras aktuálního požadavku HttpContext.Request.RouteValues . Hodnoty přidružené k aktuálnímu požadavku se označují jako ambientní hodnoty. Z důvodu přehlednosti dokumentace odkazuje na hodnoty tras předané metodám jako na explicitní hodnoty.
Následující příklad ukazuje okolní hodnoty a explicitní hodnoty. Poskytuje ambientní 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:
- Vrátí
/Widget/Index/17 - Získá LinkGenerator prostřednictvím di .
Následující kód poskytuje žádné ambientní 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 v vrátí 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/17se vrátí .- Url získá IUrlHelper .
- Action
vygeneruje adresu URL s absolutní cestou pro metodu akce. Adresa URL obsahuje zadanýactionnázev aroutehodnoty.
Následující kód poskytuje ambientní 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 nastaví na url , když stránka pro /Edit/17 Razor úpravy obsahuje následující direktivu page:
@page "{id:int}"
Pokud stránka Upravit šablonu trasy "{id:int}" neobsahuje, je url /Edit?id=17 .
Chování MVC přidává kromě zde popsaných pravidel také vrstvu IUrlHelper složitosti:
IUrlHelpervždy poskytuje hodnoty tras z aktuálního požadavku jako ambientní hodnoty.- IUrlHelper.Action vždy zkopíruje aktuální a směrovací hodnoty jako explicitní hodnoty, pokud
actioncontrollerje nepopíše vývojář. - IUrlHelper.Page vždy zkopíruje aktuální hodnotu trasy jako explicitní hodnotu, pokud
pagenení přepsána. IUrlHelper.Pagevždy přepíše aktuálníhandlerhodnotu trasy jako explicitnínullhodnoty, pokud není přepsána.
Uživatelé jsou často překvapení kvůli podrobnostem o chování okolních hodnot, protože MVC zřejmě nesleduje vlastní pravidla. Z historických důvodů a z důvodů kompatibility mají určité hodnoty tras, například , , a vlastní chování action controller při page handler zvláštních případech.
Ekvivalentní funkce poskytované funkcí a LinkGenerator.GetPathByAction LinkGenerator.GetPathByPage duplikují tyto anomálie z IUrlHelper důvodu kompatibility.
Proces generování adres URL
Jakmile najdete sadu kandidátských koncových bodů, algoritmus generování adres URL:
- Iterativně zpracovává koncové body.
- Vrátí první úspěšný výsledek.
První krok v tomto procesu se nazývá zneplatnění hodnoty trasy. Zneplatnění hodnoty trasy je proces, podle kterého směrování rozhoduje, které hodnoty tras z okolních hodnot se mají použít a které by se měly ignorovat. Každá ambientní hodnota je považována za a buď zkombinována s explicitními hodnotami, nebo ignorována.
Nejlepší způsob, jak zamyslet se nad rolí okolních hodnot, je v některých běžných případech pokusit se uložit psaní vývojáři aplikací. Scénáře, ve kterých jsou užitečné okolní hodnoty, tradičně souvisejí s MVC:
- Při propojování s jinou akcí ve stejném kontroleru nemusí být název kontroleru zadán.
- Při propojování s jiným kontroleru ve stejné oblasti není potřeba zazadat název oblasti.
- Při propojování se stejnou metodou akce není nutné zazadat hodnoty tras.
- Při propojování s jinou částí aplikace nechcete přenést hodnoty tras, které v této části aplikace nemají žádný význam.
Volání metody LinkGenerator nebo , která vrací , jsou obvykle IUrlHelper null způsobena tím, že neporozumíte zneplatnění hodnoty trasy. Vyřešte potíže s zneplatněním hodnoty trasy explicitním zadáním dalších hodnot tras a podívejte se, jestli se tím problém nevyřeší.
Zneplatnění hodnoty trasy funguje za předpokladu, že schéma adresy URL aplikace je hierarchické a hierarchie je vytvořená zleva doprava. Zvažte základní šablonu trasy kontroleru, {controller}/{action}/{id?} abyste získali intuitivní přehled o tom, jak to funguje v praxi. Změna hodnoty zneplatní všechny hodnoty trasy, které se zobrazují vpravo. To odráží předpoklad o hierarchii. Pokud má aplikace ambientní hodnotu pro a operace určuje id jinou hodnotu pro controller :
idse nebude znovu používat,{controller}protože je nalevo od{id?}.
Několik příkladů demonstrujících tento princip:
- Pokud explicitní hodnoty obsahují hodnotu
idpro , okolí hodnota pro jeidignorována. Je možné použítcontrolleractionambientní hodnoty pro a . - Pokud explicitní hodnoty obsahují hodnotu
actionpro , bude ignorována jakákoliactionambientní hodnota pro . Okolní hodnoty procontrollerlze použít. Pokud je explicitní hodnota proactionodlišná od okolní hodnoty proaction, hodnota seidnepoužije. Pokud je explicitní hodnota proactionshodná s hodnotou okolí proaction,idlze použít hodnotu. - Pokud explicitní hodnoty obsahují hodnotu pro
controller, všechny okolí hodnoty procontrollerje ignorováno. Pokud je explicitní hodnota procontrollerodlišná od hodnoty okolí procontroller,actionidhodnoty a nebudou použity. Pokud je explicitní hodnota procontrollershodná s hodnotou okolí procontroller,actionidlze použít hodnoty a.
Tento proces je dále komplikovaný existence tras atributů a vyhrazených konvenčních tras. Řadiče konvenčních cest, jako je například {controller}/{action}/{id?} určení hierarchie pomocí parametrů směrování. Pro vyhrazené konvenční trasy a Směrování atributů na řadiče a Razor stránky:
- Existuje hierarchie hodnot směrování.
- Nezobrazují se v šabloně.
V těchto případech generování adresy URL definuje koncept požadovaných hodnot . U koncových bodů vytvořených řadiči a Razor stránkami jsou zadané požadované hodnoty, které umožňují fungování neplatnosti hodnoty směrování.
Podrobnosti o algoritmu neplatnosti hodnoty směrování:
- Požadované názvy hodnot jsou kombinovány s parametry směrování a následně zpracovány z 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 hodnota okolí přítomná a explicitní hodnota není, použije se při generování adresy URL okolní hodnota.
- Pokud okolní hodnota není přítomna a explicitní hodnota je, zamítnout okolní hodnotu a všechny následné okolní hodnoty.
- Pokud je přítomna okolní hodnota a explicitní hodnota a dvě hodnoty se liší, zamítnout okolní hodnotu a všechny následné hodnoty okolí.
V tomto okamžiku je operace generování adresy URL připravena k vyhodnocení omezení trasy. Sada přijatých hodnot je kombinována s výchozími hodnotami parametrů, které jsou k dispozici v omezeních. Pokud jsou omezení splněna, operace pokračuje.
V dalším kroku lze přijmout hodnoty , které slouží k rozbalení šablony trasy. Zpracovává se šablona trasy:
- Zleva doprava.
- U každého parametru je nahrazena jeho přijatá hodnota.
- Následující zvláštní případy:
- Pokud v poli přijatelné hodnoty chybí hodnota a parametr má výchozí hodnotu, použije se výchozí hodnota.
- Pokud v poli přijatelné hodnoty chybí hodnota a parametr je nepovinný, zpracování pokračuje.
- Pokud libovolný parametr trasy napravo od chybějícího volitelného parametru má hodnotu, operace se nezdařila.
- Sousedící parametry výchozí hodnoty a volitelné parametry jsou sbaleny tam, kde je to možné.
Hodnoty zadané explicitně, které neodpovídají segmentu trasy, se přidají do řetězce dotazu. V následující tabulce je uveden výsledek při použití šablony směrování {controller}/{action}/{id?} .
| Okolní hodnoty | Explicitní hodnoty | Výsledek |
|---|---|---|
| Controller = " Home " | Action = "o" | /Home/About |
| Controller = " Home " | Controller = "objednávka"; Action = "o" | /Order/About |
| Controller = " Home "; Color = "Red" | Action = "o" | /Home/About |
| Controller = " Home " | Action = "o", Color = "Red" | /Home/About?color=Red |
Problémy s neplatností hodnoty trasy
od verze ASP.NET Core 3,0 nemusí některá schémata generování adres url používaná v dřívějších ASP.NET Core verzích dobře spolupracovat s generováním adresy url. tým ASP.NET Core plánuje přidat funkce, které tyto potřeby řeší v budoucí verzi. V současné době je nejvhodnějším řešením použití starší verze směrování.
Následující kód ukazuje příklad schématu generování adresy 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 je parametr Route použit k lokalizaci. Je potřeba, aby parametr byl culture vždycky přijatý jako ambientní hodnota. cultureParametr ale není přijatý jako ambientní hodnota z důvodu způsobu, jakým požadované hodnoty fungují:
- V
"default"šabloně trasycultureje parametr trasy nalevo odcontroller, takže změny secontrollernebudou odhodnocovatculture. - V
"blog"šabloně trasycultureje parametr Route považován za napravo odcontroller, což se zobrazuje 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 s směrováním koncových bodů
- Ukázka IAuthorizationPolicyProvider s použitím vlastního
[MinimumAgeAuthorize]atributu - Test ověřování pomocí atributu [autorizovat]
- RequireAuthorization
- Výběr schématu pomocí atributu [autorizovat]
- Použití zásad pomocí atributu [autorizační]
- Ověřování na základě rolí v ASP.NET Core
Přiřazení hostitelů v cestách pomocí RequireHost
RequireHost použije omezení na trasu, která vyžaduje zadaného hostitele. RequireHostParametr nebo [Host] může být:
- Hostitel:
www.domain.com, odpovídáwww.domain.comjakémukoli portu. - Hostitel se zástupnými znaky:
*.domain.com, odpovídáwww.domain.com,subdomain.domain.comnebowww.subdomain.domain.comna jakémkoli portu. - Port:
*:5000, odpovídá portu 5000 všem hostitelům. - Hostitel a port:
www.domain.com:5000nebo*.domain.com:5000se shoduje s hostitelem a portem.
Více parametrů lze zadat pomocí RequireHost nebo [Host] . Omezení odpovídá počtu hostitelů platných pro libovolný parametr. Například odpovídá, [Host("domain.com", "*.domain.com")] domain.com www.domain.com a subdomain.domain.com .
Následující kód používá RequireHost pro vyžadování zadaného hostitele v 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 řadiči pro vyžadování některého z určený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();
}
}
Když [Host] je atribut použit pro metodu Controller a Action:
- Atribut akce je použit.
- Atribut kontroleru se ignoruje.
Průvodce výkonem pro směrování
většina směrování se v ASP.NET Core 3,0 aktualizovala, aby se zvýšil výkon.
Pokud dojde k problémům s výkonem aplikace, směrování je často podezřelé jako problém. Podezření na směrování je, že architektury, jako jsou řadiče a Razor stránky, nahlásí množství času stráveného v rámci rozhraní ve zprávách protokolování. V případě významného rozdílu mezi časem hlášeným řadiči a celkovou dobou trvání žádosti:
- Vývojáři odstraňují svůj kód aplikace jako zdroj problému.
- Je běžné předpokládat, že směrování je příčinou.
Směrování je Testováno pomocí tisíců koncových bodů. Je pravděpodobné, že Typická aplikace zaznamená problém s výkonem, který je právě velký. Nejběžnější hlavní příčinou pomalého výkonu směrování je obvykle nesprávně se často fungujícím vlastním middlewarem.
Následující příklad kódu ukazuje základní techniku pro 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.");
});
});
}
Čas do směrování:
- Proložení každého middlewaru pomocí kopie middlewaru časování zobrazeného v předchozím kódu.
- Přidejte jedinečný identifikátor, který bude korelovat data časování s kódem.
Jedná se o základní způsob zúžení zpoždění, pokud je důležité, například více než 10ms . Odečte Time 2 se od Time 1 sestav čas strávený uvnitř UseRouting middlewaru.
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 funkcí směrování, které jsou v porovnání se základními šablonami směrování poměrně nákladné:
Regulární výrazy: je možné napsat regulární výrazy, které jsou složité, nebo mají dlouhou dobu běhu s malým množstvím vstupu.
Komplexní segmenty (
{x}-{y}-{z}):- Jsou podstatně dražší než analýza běžného segmentu cesty URL.
- Výsledkem je přidělení mnoha dalších podřetězců.
- Logika komplexního segmentu se v aktualizaci výkonu směrování ASP.NET Core 3.0 ne aktualizovala.
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ší nemusí poskytovat správné body rozšiřitelnosti pro podporu směrování přístupu k databázi. Například , IRouteConstraint a IActionConstraint jsou synchronní. Body rozšiřitelnosti, jako MatcherPolicy jsou a , jsou EndpointSelectorContext asynchronní.
Pokyny pro autory knihoven
Tato část obsahuje pokyny pro autory knihoven, kteří staví na směrování. Účelem 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 rozhraní, 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 nad . UseEndpoints
Proveďte sestavení nad IEndpointRouteBuilder . To umožňuje uživatelům vytvářet vaše rozhraní s další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 přítomné a známé.
app.UseEndpoints(endpoints =>
{
// Your framework
endpoints.MapMyFramework(...);
endpoints.MapHealthChecks("/healthz");
});
Vraťte zapečetěný konkrétní typ z volání MapMyFramework(...) , které implementuje IEndpointConventionBuilder . Většina metod Map... architektury dodržuje tento model. IEndpointConventionBuilderRozhraní:
- Umožňuje kompozibilitu metadat.
- Cílí na různé rozšiřující metody.
Deklarování vlastního typu umožňuje přidat do tvůrce vlastní funkce specifické pro rozhraní. 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ích EndpointDataSource . EndpointDataSource je primitivum nízké úrovně pro deklaraci 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 ne aktualizací zdroje dat.
NEPOKOUŠEJTE se zaregistrovat EndpointDataSource ve výchozím nastavení. Vyžadovat, aby si uživatelé zaregistroval vaši rozhraní v UseEndpoints . Filozofií směrování je, že ve výchozím nastavení není nic zahrnuto, a to je místo pro UseEndpoints registraci koncových bodů.
Vytvoření middlewaru integrovaného se směrováním
ZVAŽTE definování typů metadat jako rozhraní.
U tříd a metod je možné používat typy metadat jako atribut.
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 stránky, podporují použití atributů metadat na typy a Razor metody. Pokud deklarujete typy metadat:
- Zajistěte, aby byly přístupné jako atributy.
- Většina uživatelů zná použití atributů.
Deklarování typu metadat jako rozhraní přidává další vrstvu flexibility:
- Rozhraní jsou smyšitelná.
- Vývojáři mohou deklarovat své vlastní typy, které kombinují více zásad.
Proveďte, aby bylo možné 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ším způsobem, jak postupovat podle těchto pokynů, je vyhnout se definování metadat značek:
- Ne hledejte jen přítomnost typu metadat.
- Definujte vlastnost metadat a zkontrolujte vlastnost .
Kolekce metadat je seřazená a podporuje přepisování podle priority. V případě kontrolerů jsou metadata metody akce nej specifická.
Zajistěte, aby byl middleware užitečný se směrováním a bez něj.
app.UseRouting();
app.UseAuthorization(new AuthorizationPolicy() { ... });
app.UseEndpoints(endpoints =>
{
// Your framework
endpoints.MapMyFramework(...).RequireAuthorization();
});
Jako příklad tohoto návodu zvažte UseAuthorization middleware. Autorizační middleware umožňuje předat záložní zásady. Pokud jsou zadané záložní zásady, platí pro oba typy:
- Koncové body bez zadané zásady.
- Požadavky, které neodpovídají koncovému bodu.
Díky tomu je autorizační middleware užitečný mimo kontext směrování. Autorizační middleware lze použít pro tradiční programování middlewaru.
Diagnostika ladění
Pro podrobný výstup diagnostiky směrování nastavte Logging:LogLevel:Microsoft na Debug . Ve vývojovém prostředí nastavte úroveň protokolu v appsettings.Development.jsna:
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Debug",
"Microsoft.Hosting.Lifetime": "Information"
}
}
}