Anteckning
Åtkomst till den här sidan kräver auktorisering. Du kan prova att logga in eller ändra kataloger.
Åtkomst till den här sidan kräver auktorisering. Du kan prova att ändra kataloger.
Av Ryan Nowak, Kirk Larkin och Rick Anderson
Warning
Den här versionen av ASP.NET Core stöds inte längre. Mer information finns i supportpolicyn för .NET och .NET Core. För den nuvarande utgåvan, se .NET 9-versionen av den här artikeln .
Important
Den här informationen gäller en förhandsversionsprodukt som kan ändras avsevärt innan den släpps kommersiellt. Microsoft lämnar inga garantier, uttryckliga eller underförstådda, med avseende på den information som tillhandahålls här.
För den nuvarande utgåvan, se .NET 9-versionen av den här artikeln .
Routning ansvarar för att matcha inkommande HTTP-begäranden och skicka dessa begäranden till appens körbara slutpunkter. Slutpunkter är appens enheter för körbar kod för hantering av begäranden. Slutpunkter definieras i appen och konfigureras när appen startas. Slutpunktsmatchningsprocessen kan extrahera värden från begärans URL och ange dessa värden för bearbetning av begäranden. Med hjälp av slutpunktsinformation från appen kan routning också generera URL:er som mappar till slutpunkter.
Appar kan konfigurera routning med hjälp av:
- Controllers
- Razor sidor
- SignalR
- gRPC-tjänster
- Slutpunktsaktiverat mellanprogram , till exempel hälsokontroller.
- Delegater och lambdas som registrerats med routning.
Den här artikeln beskriver information på låg nivå om ASP.NET Core-routning. Information om hur du konfigurerar routning:
- För kontrollanter, se Routning till kontrollantåtgärder i ASP.NET Core.
- För Razor Sidor-konventioner, se Razor Sidor rout- och appkonventioner i ASP.NET Core.
- Vägledning för Blazor routning, som lägger till eller ersätter vägledningen i den här artikeln, finns i ASP.NET Core-routning Blazor och navigering.
Grunderna för routning
Följande kod visar ett grundläggande exempel på routning:
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
app.MapGet("/", () => "Hello World!");
app.Run();
Föregående exempel innehåller en enskild slutpunkt med hjälp av MapGet metoden:
- När en HTTP-begäran
GETskickas till rot-URL:en/:- Begärandedelegaten utförs.
-
Hello World!skrivs till HTTP-svaret.
- Om begärandemetoden inte är
GETeller om rot-URL:en inte är/, matchar ingen rutt och en HTTP 404 returneras.
Routning använder ett par mellanprogram, registrerade av UseRouting och UseEndpoints:
-
UseRoutinglägger till routningsmatchning till pipelinen för mellanprogram. Det här mellanprogrammet tittar på den uppsättning slutpunkter som definierats i appen och väljer den bästa matchningen baserat på begäran. -
UseEndpointslägger till slutpunktskörning i pipelinen för mellanprogram. Den kör delegeringen som är kopplad till den valda slutpunkten.
Appar behöver vanligtvis inte anropa UseRouting eller UseEndpoints.
WebApplicationBuilder konfigurerar en middleware-pipeline som omsluter den middleware som lagts till i Program.cs med UseRouting och UseEndpoints. Appar kan dock ändra i vilken UseRouting ordning och UseEndpoints körs genom att anropa dessa metoder explicit. Följande kod gör till exempel ett explicit anrop till UseRouting:
app.Use(async (context, next) =>
{
// ...
await next(context);
});
app.UseRouting();
app.MapGet("/", () => "Hello World!");
I koden ovan:
- Anropet till
app.Useregistrerar ett anpassat mellanprogram som körs i början av pipelinen. - Anropet till
UseRoutingkonfigurerar mellanprogrammet för ruttmatchning att köras efter det anpassade mellanprogrammet. - Slutpunkten som registrerats med
MapGetkörs i slutet av pipeline.
Om föregående exempel inte innehöll ett anrop till UseRoutingskulle det anpassade mellanprogrammet köras efter vägen som matchar mellanprogrammet.
Obs! Rutterna som läggs till direkt i WebApplication utförs vid slutet av pipelinen.
Endpoints
Metoden MapGet används för att definiera en slutpunkt. En slutpunkt är något som kan vara:
- Vald genom att matcha URL:en och HTTP-metoden.
- Utförs genom att köra delegeringen.
Ändpunkter som kan matchas och köras av appen konfigureras i UseEndpoints. Till exempel ansluter MapGet, MapPost och liknande metoder förbinder ombud för begäranden till routningssystemet. Ytterligare metoder kan användas för att ansluta ASP.NET Core Framework-funktioner till routningssystemet:
- MapRazorPages för Razor sidor
- MapControllers för styrenheter
- MapHub<THub> för SignalR
- MapGrpcService<TService> för gRPC
I följande exempel visas routning med en mer avancerad vägmall:
app.MapGet("/hello/{name:alpha}", (string name) => $"Hello {name}!");
Strängen /hello/{name:alpha} är en vägmall. En vägmall används för att konfigurera hur slutpunkten matchas. I det här fallet matchar mallen:
- En URL som
/hello/Docs - Alla URL-sökvägar som börjar med
/hello/följt av en sekvens med alfabetiska tecken.:alphatillämpar en vägbegränsning som endast matchar alfabetiska tecken. Routningsbegränsningar beskrivs senare i den här artikeln.
Det andra segmentet i URL-sökvägen: {name:alpha}
- Är bunden till parametern
name. - Samlas in och lagras i HttpRequest.RouteValues.
I följande exempel visas routning med hälsokontroller och auktorisering:
app.UseAuthentication();
app.UseAuthorization();
app.MapHealthChecks("/healthz").RequireAuthorization();
app.MapGet("/", () => "Hello World!");
Föregående exempel visar hur:
- Mellanprogrammet för auktorisering kan användas med routning.
- Slutpunkter kan användas för att konfigurera auktoriseringsbeteende.
Anropet MapHealthChecks lägger till en slutpunkt för hälsokontroll. Länkning RequireAuthorization till det här anropet kopplar en auktoriseringsprincip till slutpunkten.
Anropar UseAuthentication och UseAuthorization lägger till mellanprogrammet för autentisering och auktorisering. Dessa mellanprogram placeras mellan UseRouting och UseEndpoints så att de kan:
- Se vilken slutpunkt som har valts av
UseRouting. - Tillämpa en auktoriseringsprincip innan UseEndpoints skickas till slutpunkten.
Slutpunktsmetadata
I föregående exempel finns det två slutpunkter, men endast slutpunkten för hälsokontroll har en auktoriseringsprincip kopplad. Om begäran matchar slutpunkten /healthzför hälsokontroll utförs en auktoriseringskontroll. Detta visar att slutpunkter kan ha extra data kopplade till sig. Dessa extra data kallas slutpunktsmetadata:
- Metadata kan bearbetas av routningsmedvetna mellanprogram.
- Metadata kan vara av valfri .NET-typ.
Routningsbegrepp
Routningssystemet bygger på pipelinen för mellanprogram genom att lägga till det kraftfulla slutpunktskonceptet . Slutpunkter representerar enheter i appens funktioner som skiljer sig från varandra när det gäller routning, auktorisering och valfritt antal ASP.NET Core-system.
ASP.NET Core-slutpunktsdefinition
En ASP.NET Core-slutpunkt är:
- Körbar: Har en RequestDelegate.
- Utökningsbar: Har en metadatasamling .
- Valbar: Om du vill kan du ha routningsinformation.
- Uppräkningsbar: Samlingen med slutpunkter kan visas genom att EndpointDataSource hämta från DI.
Följande kod visar hur du hämtar och inspekterar slutpunkten som matchar den aktuella begäran:
app.Use(async (context, next) =>
{
var currentEndpoint = context.GetEndpoint();
if (currentEndpoint is null)
{
await next(context);
return;
}
Console.WriteLine($"Endpoint: {currentEndpoint.DisplayName}");
if (currentEndpoint is RouteEndpoint routeEndpoint)
{
Console.WriteLine($" - Route Pattern: {routeEndpoint.RoutePattern}");
}
foreach (var endpointMetadata in currentEndpoint.Metadata)
{
Console.WriteLine($" - Metadata: {endpointMetadata}");
}
await next(context);
});
app.MapGet("/", () => "Inspect Endpoint.");
Slutpunkten, om den är markerad, kan hämtas från HttpContext. Dess egenskaper kan inspekteras. Slutpunktsobjekt är oföränderliga och kan inte ändras när de har skapats. Den vanligaste typen av slutpunkt är en RouteEndpoint.
RouteEndpoint innehåller information som gör att den kan väljas av routningssystemet.
I föregående kod konfigurerar app.Use en inline-mellanprogram.
Följande kod visar att det, beroende på var app.Use som anropas i pipelinen, kanske inte finns någon slutpunkt:
// Location 1: before routing runs, endpoint is always null here.
app.Use(async (context, next) =>
{
Console.WriteLine($"1. Endpoint: {context.GetEndpoint()?.DisplayName ?? "(null)"}");
await next(context);
});
app.UseRouting();
// Location 2: after routing runs, endpoint will be non-null if routing found a match.
app.Use(async (context, next) =>
{
Console.WriteLine($"2. Endpoint: {context.GetEndpoint()?.DisplayName ?? "(null)"}");
await next(context);
});
// Location 3: runs when this endpoint matches
app.MapGet("/", (HttpContext context) =>
{
Console.WriteLine($"3. Endpoint: {context.GetEndpoint()?.DisplayName ?? "(null)"}");
return "Hello World!";
}).WithDisplayName("Hello");
app.UseEndpoints(_ => { });
// Location 4: runs after UseEndpoints - will only run if there was no match.
app.Use(async (context, next) =>
{
Console.WriteLine($"4. Endpoint: {context.GetEndpoint()?.DisplayName ?? "(null)"}");
await next(context);
});
Föregående exempel lägger till Console.WriteLine instruktioner som visar om en slutpunkt har valts eller inte. För tydlighetens skull tilldelar exemplet ett visningsnamn till den angivna / slutpunkten.
Föregående exempel innehåller även anrop till UseRouting och UseEndpoints för att styra exakt när dessa mellanprogram körs i pipelinen.
Kör den här koden med en URL på / visar:
1. Endpoint: (null)
2. Endpoint: Hello
3. Endpoint: Hello
Om du kör den här koden med andra URL:ar visas:
1. Endpoint: (null)
2. Endpoint: (null)
4. Endpoint: (null)
Dessa utdata visar att:
- Slutpunkten är alltid null innan
UseRoutinganropas. - Om en matchning hittas är slutpunkten inte null mellan
UseRoutingoch UseEndpoints. - Mellanprogrammet
UseEndpointsär terminal när en matchning hittas. Terminalmellanprogram definieras senare i den här artikeln. - Mellanprogrammet efter
UseEndpointskörs endast när ingen matchning hittas.
Mellanprogrammet UseRouting använder SetEndpoint metoden för att koppla slutpunkten till den aktuella kontexten. Det går att ersätta UseRouting mellanprogrammet med anpassad logik och ändå få fördelarna med att använda slutpunkter. Ändpunkter är ett grundläggande element på låg nivå som mellanvaror och är inte kopplade till routningens implementering. De flesta appar behöver inte ersättas UseRouting med anpassad logik.
Mellanprogrammet UseEndpoints är utformat för att användas tillsammans med UseRouting mellanprogrammet. Kärnlogiken för att utföra en slutpunkt är inte komplicerad. Använd GetEndpoint för att hämta slutpunkten och anropa sedan dess RequestDelegate egenskap.
Följande kod visar hur mellanprogram kan påverka eller reagera på routning:
app.UseHttpMethodOverride();
app.UseRouting();
app.Use(async (context, next) =>
{
if (context.GetEndpoint()?.Metadata.GetMetadata<RequiresAuditAttribute>() is not null)
{
Console.WriteLine($"ACCESS TO SENSITIVE DATA AT: {DateTime.UtcNow}");
}
await next(context);
});
app.MapGet("/", () => "Audit isn't required.");
app.MapGet("/sensitive", () => "Audit required for sensitive data.")
.WithMetadata(new RequiresAuditAttribute());
public class RequiresAuditAttribute : Attribute { }
Föregående exempel visar två viktiga begrepp:
- Mellanprogram kan köras tidigare
UseRoutingför att ändra de data som routningen körs på.- Vanligtvis ändrar mellanprogram som visas innan routning någon egenskap för begäran, till exempel UseRewriter, UseHttpMethodOverrideeller UsePathBase.
- Mellanprogram kan köras mellan
UseRoutingoch UseEndpoints för att bearbeta resultatet av routingen innan slutpunkten körs.- Mellanprogram som körs mellan
UseRoutingochUseEndpoints:- Inspekterar vanligtvis metadata för att förstå slutpunkterna.
- Fattar ofta säkerhetsbeslut, som görs av
UseAuthorizationochUseCors.
- Kombinationen av mellanprogram och metadata gör det möjligt att konfigurera principer per slutpunkt.
- Mellanprogram som körs mellan
Föregående kod visar ett exempel på ett anpassat mellanprogram som stöder principer per slutpunkt. Mellanprogrammet skriver en revisionslogg av åtkomst av känsliga data till konsolen. Mellanprogrammet kan konfigureras för att granska en slutpunkt med RequiresAuditAttribute metadata. Det här exemplet visar ett opt-in-mönster där endast slutpunkter som är markerade som känsliga granskas. Det är möjligt att definiera den här logiken omvänt och granska allt som inte är markerat som säkert, till exempel. Slutpunktsmetadatasystemet är flexibelt. Den här logiken kan utformas på vilket sätt som helst som passar användningsfallet.
Föregående exempelkod är avsedd att demonstrera de grundläggande begreppen för slutpunkter. Exemplet är inte avsett för produktionsanvändning. En mer fullständig version av ett mellanprogram för granskningsloggar skulle:
- Logga in på en fil eller databas.
- Inkludera information som användaren, IP-adressen, namnet på den känsliga slutpunkten med mera.
Metadata för revisionspolicy RequiresAuditAttribute definieras som en Attribute för att enklare kunna använda klassbaserade ramverk som kontroller och SignalR. När du använder route to code:
- Metadata bifogas med ett builder-API.
- Klassbaserade ramverk innehåller alla attribut på motsvarande metod och klass när du skapar slutpunkter.
Metodtipsen för metadatatyper är att definiera dem antingen som gränssnitt eller attribut. Gränssnitt och attribut tillåter återanvändning av kod. Metadatasystemet är flexibelt och medför inga begränsningar.
Jämför terminalmellanprogram med routning
I följande exempel visas både terminalmellanprogram och routning:
// Approach 1: Terminal Middleware.
app.Use(async (context, next) =>
{
if (context.Request.Path == "/")
{
await context.Response.WriteAsync("Terminal Middleware.");
return;
}
await next(context);
});
app.UseRouting();
// Approach 2: Routing.
app.MapGet("/Routing", () => "Routing.");
Formatet för mellanprogram som visas med Approach 1: är terminalmellanprogram. Det kallas terminalmellanprogram eftersom det utför en matchande åtgärd:
- Matchningsåtgärden i föregående exempel är
Path == "/"för mellanprogrammet ochPath == "/Routing"för routning. - När en matchning lyckas, utför den vissa funktioner och returnerar istället för att anropa
next-mellanprogrammet.
Det kallas terminalmellanprogram eftersom det avslutar sökningen, kör vissa funktioner och sedan returnerar.
I följande lista jämförs terminalmellanprogram med routning:
- Båda metoderna gör det möjligt att avsluta bearbetningspipelinen:
- Mellanprogram avslutar pipelinen genom att returnera i stället för att
nextanropa . - Slutpunkter är alltid terminaler.
- Mellanprogram avslutar pipelinen genom att returnera i stället för att
- Med terminalmellanprogram kan du placera mellanprogrammet på en godtycklig plats i pipelinen:
- Slutpunkter körs på positionen UseEndpoints.
- Med terminalmellanprogram kan godtycklig kod avgöra när mellanprogrammet matchar:
- Anpassad vägmatchningskod kan vara utförlig och svår att skriva korrekt.
- Routning ger enkla lösningar för typiska appar. De flesta appar kräver inte anpassad vägmatchningskod.
- Slutpunktsgränssnitt med mellanprogram som
UseAuthorizationochUseCors.- Användning av ett terminalmellanprogram med
UseAuthorizationellerUseCorskräver manuell koppling med auktoriseringssystemet.
- Användning av ett terminalmellanprogram med
En slutpunkt definierar båda:
- Ett ombud för att bearbeta begäranden.
- En samling godtyckliga metadata. Metadata används för att implementera övergripande problem baserat på principer och konfiguration som är kopplade till varje slutpunkt.
Terminalmellanprogram kan vara ett effektivt verktyg, men kan kräva:
- En betydande mängd kodning och testning.
- Manuell integrering med andra system för att uppnå önskad flexibilitetsnivå.
Överväg att integrera med routning innan du skriver ett terminalmellanprogram.
Befintliga terminalmellanprogram som integreras med Map eller MapWhen kan vanligtvis omvandlas till en routingmedveten slutpunkt. MapHealthChecks visar mönstret för router-ware:
- Skriv en tilläggsmetod på IEndpointRouteBuilder.
- Skapa en pipeline för kapslade mellanprogram med CreateApplicationBuilder.
- Koppla mellanprogrammet till den nya pipelinen. I det här fallet UseHealthChecks.
- Build mellanprogramspipelinen till en RequestDelegate.
- Anropa
Mapoch ange den nya pipelinen för mellanprogram. - Returnera builder-objektet som tillhandahålls av
Mapfrån tilläggsmetoden.
Följande kod visar användning av MapHealthChecks:
app.UseAuthentication();
app.UseAuthorization();
app.MapHealthChecks("/healthz").RequireAuthorization();
Föregående exempel visar varför det är viktigt att returnera builder-objektet. När byggobjektet returneras kan apputvecklaren konfigurera principer som auktorisering för slutpunkten. I det här exemplet har mellanprogrammet för hälsokontroller ingen direkt integrering med auktoriseringssystemet.
Metadatasystemet skapades som svar på de problem som uppstått av utökningsförfattare med hjälp av terminalmellanprogram. Det är problematiskt för varje mellanprogram att implementera sin egen integrering med auktoriseringssystemet.
URL-matchning
- Är den process genom vilken routningen matchar en inkommande begäran till en slutpunkt.
- Baseras på data i URL-sökvägen och rubrikerna.
- Kan utökas för att överväga alla data i begäran.
När ett routningsmellanprogram körs anger det en Endpoint och dirigerar värden till en begäransfunktion på HttpContext från den aktuella begäran:
- Genom att anropa HttpContext.GetEndpoint hämtas slutpunkten.
-
HttpRequest.RouteValueshämtar samlingen av routvärden.
Mellanprogram som körs efter routningsmellanprogrammet kan inspektera slutpunkten och vidta åtgärder. Till exempel kan ett mellanprogramvara för auktorisering granska och utvärdera slutpunktens metadatasamling för en auktoriseringspolicy. När alla mellanprogram i pipelinen för bearbetning av begäranden har körts anropas den valda slutpunktens ombud.
Routningssystemet i slutpunktsroutningen ansvarar för alla leveransbeslut. Eftersom mellanprogrammet tillämpar principer baserat på den valda slutpunkten är det viktigt att:
- Alla beslut som kan påverka sändningen eller tillämpningen av säkerhetsprinciper fattas i routningssystemet.
Warning
För bakåtkompatibilitet, när en Controller eller Razor Pages-slutpunktsdelegat körs, anges egenskaperna till lämpliga värden baserat på den bearbetning som hittills utförts av RouteContext.RouteData-begäran.
Typen RouteContext kommer att markeras som föråldrad i en framtida version:
- Migrera
RouteData.ValuestillHttpRequest.RouteValues. - Migrera
RouteData.DataTokensför att hämta IDataTokensMetadata från slutpunktsmetadata.
URL-matchning fungerar i en konfigurerbar uppsättning faser. I varje fas är utdata en uppsättning matchningar. Mängden matcher kan begränsas ytterligare under nästa fas. Routningsimplementeringen garanterar inte någon bearbetningsordning för matchande slutpunkter. Alla möjliga matchningar bearbetas samtidigt. Url-matchningsfaserna sker i följande ordning. ASP.NET Core:
- Bearbetar URL-sökvägen mot uppsättningen slutpunkter och deras vägmallar och samlar in alla matchningar.
- Tar den föregående listan och tar bort matchningar som inte uppfyller ruttbegränsningar som tillämpas.
- Tar föregående lista och tar bort matchningar som inte uppfyller kraven för MatcherPolicy instanser.
- Använder EndpointSelector för att fatta ett slutgiltigt beslut från föregående lista.
Listan över slutpunkter prioriteras enligt:
- Den RouteEndpoint.Order
- Prioritet för routsmall
Alla matchande ändpunkter bearbetas i varje fas tills den EndpointSelector har nåtts.
EndpointSelector är den sista fasen. Den väljer den högsta prioritetsslutpunkten från matchningarna som den bästa matchningen. Om det finns andra matchningar med samma prioritet som den bästa matchningen, kommer ett tvetydigt matchningsundantag att utlösas.
Routningsprioriteten beräknas baserat på att en mer specifik vägmall får högre prioritet. Tänk till exempel på mallarna /hello och /{message}:
- Båda matchar URL-sökvägen
/hello. -
/helloär mer specifik och därför högre prioritet.
I allmänhet gör routningsprioriteten ett bra jobb med att välja den bästa matchningen för de typer av URL-scheman som används i praktiken. Använd Order endast när det behövs för att undvika tvetydigheter.
På grund av de typer av utökningsbarhet som tillhandahålls av routning är det inte möjligt för routningssystemet att beräkna de tvetydiga vägarna i förväg. Överväg ett exempel som routningsmallarna /{message:alpha} och /{message:int}:
- Villkoret
alphamatchar endast alfabetiska tecken. - Villkoret
intmatchar endast tal. - Dessa mallar har samma vägprioritet, men det finns ingen enskild URL som båda matchar.
- Om routningssystemet rapporterade ett tvetydighetsfel vid starten skulle det blockera det här giltiga användningsfallet.
Warning
Ordningen på åtgärderna i UseEndpoints påverkar inte beteendet för routning, med ett undantag. MapControllerRoute och MapAreaRoute tilldela automatiskt ett ordervärde till sina slutpunkter baserat på den ordning som de anropas. Detta simulerar långvarigt beteende för kontrollanter utan att routningssystemet ger samma garantier som äldre routningsimplementeringar.
Slutpunktsroutning i ASP.NET Core:
- Har inte begreppet rutter.
- Ger inte ordergarantier. Alla slutpunkter bearbetas samtidigt.
Routningsmallens prioritet och slutpunktsmarkeringsordning
Prioritet för routningsmallar är ett system som tilldelar varje vägmall ett värde baserat på hur specifik den är. Prioritet för routningsmall:
- Undviker behovet av att justera ordningen på slutpunkter i vanliga fall.
- Försöker matcha allmänna förväntningar på routingbeteende.
Du kan till exempel överväga mallar /Products/List och /Products/{id}. Det är rimligt att anta att det /Products/List är en bättre matchning än /Products/{id} för URL-sökvägen /Products/List. Detta fungerar eftersom literalsegmentet /List anses ha bättre prioritet än parametersegmentet /{id}.
Information om hur prioritet fungerar är kopplat till hur routningsmallar definieras:
- Mallar med fler segment anses vara mer specifika.
- Ett segment med literaltext anses vara mer specifikt än ett parametersegment.
- Ett parametersegment med en begränsning anses vara mer specifikt än ett utan.
- Ett komplext segment anses vara lika specifikt som ett parametersegment med en begränsning.
- Catch-all-parametrar är de minst specifika. Se catch-all i avsnittet Routningsmallar för viktig information om catch-all-vägar.
Begrepp för URL-generering
URL-generering:
- Är den process genom vilken routning kan skapa en URL-sökväg baserat på en uppsättning vägvärden.
- Tillåter en logisk separation mellan slutpunkter och URL:er som har åtkomst till dem.
Slutpunktsroutning innehåller API:et LinkGenerator .
LinkGenerator är en singleton-tjänst som är tillgänglig från DI. API LinkGenerator kan användas utanför kontexten för en exekverande begäran.
Mvc.IUrlHelper och scenarier som förlitar sig på IUrlHelper, till exempel Tag Helpers, HTML Helpers och Action Results, använder API:et LinkGenerator internt för att tillhandahålla funktioner för länkgenerering.
Länkgeneratorn backas upp av begreppet adress - och adressscheman. Ett adressschema är ett sätt att fastställa de slutpunkter som ska beaktas för länkgenerering. Till exempel implementeras scenarier med routningnamn och routvärden som många användare är bekanta med från kontroller och Razor sidor såsom ett adressschema.
Länkgeneratorn kan länka till styrenheter och Razor sidor via följande tilläggsmetoder:
Överbelastningar av dessa metoder tar emot argument som inkluderar HttpContext. Dessa metoder är funktionellt likvärdiga med Url.Action och Url.Page, men ger ytterligare flexibilitet och alternativ.
Metoderna GetPath* liknar Url.Action mest och Url.Page, eftersom de genererar en URI som innehåller en absolut sökväg. Metoderna GetUri* genererar alltid en absolut URI som innehåller ett schema och en värd. De metoder som accepterar en HttpContext genererar en URI i kontexten för den körande begäran. Värden ambienta för väg, URL-bassökväg, protokoll och värd från den körande begäran används om de inte åsidosätts.
LinkGenerator anropas med en adress. Generera en URI sker i två steg:
- En adress är bunden till en lista över slutpunkter som matchar adressen.
- Varje slutpunkts RoutePattern utvärderas tills ett vägmönster som matchar de angivna värdena hittas. Resultatet kombineras med de andra URI-delarna som levereras till länkgeneratorn och returneras.
Metoderna som tillhandahålls av LinkGenerator stöder standardfunktioner för länkgenerering för alla typer av adresser. Det enklaste sättet att använda länkgeneratorn är genom tilläggsmetoder som utför åtgärder för en viss adresstyp:
| Tilläggsmetod | Description |
|---|---|
| GetPathByAddress | Genererar en URI med en absolut sökväg baserat på de angivna värdena. |
| GetUriByAddress | Genererar en absolut URI baserat på de angivna värdena. |
Warning
Var uppmärksam på följande konsekvenser av att anropa LinkGenerator metoder:
Använd
GetUri*tilläggsmetoder med försiktighet i en appkonfiguration som inte validerar headern för inkommande begäranden.HostOm rubriken för inkommande begäranden inte verifieras kan ej betrodda begärandeindata skickas tillbaka till klienten i URI:er i en vy eller sida. Vi rekommenderar att alla produktionsappar konfigurerar sin server för att kontrolleraHostheadern mot kända giltiga värden.Använd LinkGenerator med försiktighet i mellanprogram i kombination med
MapellerMapWhen.Map*ändrar basvägen för den körande begäran, vilket påverkar utdata från länkgenereringen. LinkGenerator Alla API:er tillåter att du anger en bassökväg. Ange en tom bassökväg för att ta bortMap*effekten på länkgenereringen.
Exempel på mellanprogram
I följande exempel använder ett mellanprogram API:et LinkGenerator för att skapa en länk till en åtgärdsmetod som visar lagerprodukter. Använda länkgeneratorn genom att mata in den i en klass och anrop GenerateLink är tillgängligt för alla klasser i en app:
public class ProductsMiddleware
{
private readonly LinkGenerator _linkGenerator;
public ProductsMiddleware(RequestDelegate next, LinkGenerator linkGenerator) =>
_linkGenerator = linkGenerator;
public async Task InvokeAsync(HttpContext httpContext)
{
httpContext.Response.ContentType = MediaTypeNames.Text.Plain;
var productsPath = _linkGenerator.GetPathByAction("Products", "Store");
await httpContext.Response.WriteAsync(
$"Go to {productsPath} to see our products.");
}
}
Routningsmallar
Token inom {} definierar ruttparametrar som är bundna om rutten matchas. Mer än en vägparameter kan definieras i ett vägsegment, men vägparametrarna måste avgränsas med ett literalvärde. Till exempel:
{controller=Home}{action=Index}
är inte en giltig väg eftersom det inte finns något literalvärde mellan {controller} och {action}. Routningsparametrarna måste ha ett namn och kan ha ytterligare attribut angivna.
Annan literaltext än vägparametrar (till exempel {id}) och sökvägsavgränsaren / måste matcha texten i URL:en. Textmatchning är skiftlägesokänslig och baseras på den avkodade representationen av URL:ens sökväg. Om du vill matcha en literalvägsparameter avgränsare { eller }kan du undvika avgränsare genom att upprepa tecknet. Till exempel {{ eller }}.
Asterisk * eller dubbel asterisk **:
- Kan användas som ett prefix till en vägparameter för att binda till resten av URI:n.
- Kallas för catch-all-parametrar. Till exempel
blog/{**slug}:- Matchar alla URI:er som börjar med
blog/och har ett värde som följer den. - Värdet som följer efter
blog/tilldelas som värde för slug-routen.
- Matchar alla URI:er som börjar med
Warning
En parameter kan matcha vägar felaktigt på grund av en bugg i routning. Appar som påverkas av den här buggen har följande egenskaper:
- En allomfattande rutt, till exempel
{**slug}" - Catch-all-vägen matchar inte begäranden som den ska matcha.
- Om du tar bort andra rutter börjar den allomfattande rutten att fungera.
Se GitHub-buggar 18677 och 16579 till exempel fall som drabbat den här buggen.
En anmälningskorrigering för den här buggen finns i .NET Core 3.1.301 eller senare SDK. Följande kod anger en intern växel som åtgärdar felet:
public static void Main(string[] args)
{
AppContext.SetSwitch("Microsoft.AspNetCore.Routing.UseCorrectCatchAllBehavior",
true);
CreateHostBuilder(args).Build().Run();
}
// Remaining code removed for brevity.
Catch-all-parametrar kan även matcha den tomma strängen.
Parametern catch-all undflyr lämpliga tecken när vägen används för att generera en URL, inklusive sökvägsavgränsningstecken / . Till exempel genererar rutten foo/{*path} med ruttvärden { path = "my/path" }foo/my%2Fpath. Observera det undantagna snedstrecket. Använd routningsparameterprefixet ** för att avgränsa sökvägens avgränsningstecken. Vägen foo/{**path} med { path = "my/path" } genererar foo/my/path.
URL-mönster som försöker avbilda ett filnamn med ett valfritt filnamnstillägg har ytterligare överväganden. Överväg till exempel mallen files/{filename}.{ext?}. När värden för båda filename och ext finns fylls båda värdena i. Om det bara finns ett värde för filename i URL:en matchar vägen eftersom avslutandet . är valfritt. Följande URL:er matchar den här vägen:
/files/myFile.txt/files/myFile
Routningsparametrar kan ha standardvärden som anges genom att ange standardvärdet efter parameternamnet avgränsat med ett likhetstecken (=). Definierar {controller=Home}Home till exempel som standardvärde för controller. Standardvärdet används om inget värde finns i URL:en för parametern. Routningsparametrar görs valfria genom att ett frågetecken (?) läggs till i slutet av parameternamnet. Till exempel id?. Skillnaden mellan valfria värden och standardvägsparametrar är:
- En routningsparameter med ett standardvärde genererar alltid ett värde.
- En valfri parameter har endast ett värde när ett värde tillhandahålls av begärande-URL:en.
Ruttparametrarna kan ha begränsningar som måste matcha ruttvärdet som är bundet från URL:en. Att lägga till : och villkorsnamn efter namnet på routningsparametern anger en infogad begränsning för en routningsparameter. Om villkoret kräver argument omges de av parenteser (...) efter villkorsnamnet. Du kan ange flera inline-begränsningar genom att lägga till en annan : och ett annat begränsningsnamn.
Villkorsnamnet och argumenten IInlineConstraintResolver skickas till tjänsten för att skapa en instans av IRouteConstraint som ska användas i URL-bearbetning. Routningsmallen blog/{article:minlength(10)} anger till exempel en minlength begränsning med argumentet 10. Mer information om routningsbegränsningar och en lista över de begränsningar som tillhandahålls av ramverket finns i avsnittet Routningsbegränsningar .
Routningsparametrar kan också ha parametertransformatorer. Parametertransformatorer transformerar en parameters värde vid generering av länkar och matchande åtgärder och sidor till URL:er. Precis som begränsningar kan parametertransformatorer läggas till direkt i en routparameter genom att lägga till ett : och ett transformeringsnamn efter routparameternamnet. Routningsmallen blog/{article:slugify} anger till exempel en slugify transformerare. Mer information om parametertransformatorer finns i avsnittet Parametertransformatorer .
I följande tabell visas exempel på routningsmallar och deras beteende:
| Routningsmall | Exempel på matchande URI | Förfrågan-URI:n... |
|---|---|---|
hello |
/hello |
Matchar endast den ensamma sökvägen /hello. |
{Page=Home} |
/ |
Matchar och anger Page till Home. |
{Page=Home} |
/Contact |
Matchar och anger Page till Contact. |
{controller}/{action}/{id?} |
/Products/List |
Mappar till kontroller Products och åtgärd List. |
{controller}/{action}/{id?} |
/Products/Details/123 |
Mappar till kontrollanten Products och Details åtgärden medid värdet 123. |
{controller=Home}/{action=Index}/{id?} |
/ |
Mappar till Home-kontrollern och Index-metoden.
id ignoreras. |
{controller=Home}/{action=Index}/{id?} |
/Products |
Mappar till Products-kontrollern och Index-metoden.
id ignoreras. |
Att använda en mall är vanligtvis den enklaste metoden för routning. Begränsningar och standardvärden kan också anges utanför vägmallen.
Komplexa segment
Komplexa segment bearbetas genom matchning av literalavgränsare från höger till vänster på ett icke-girigt sätt. Till exempel [Route("/a{b}c{d}")] är ett komplext segment.
Komplexa segment fungerar på ett visst sätt som måste tolkas för att kunna använda dem. Exemplet i det här avsnittet visar varför komplexa segment bara fungerar bra när avgränsartexten inte visas i parametervärdena. Att använda en regex och sedan extrahera värdena manuellt behövs för mer komplexa fall.
Warning
När du använder System.Text.RegularExpressions för att bearbeta ej betrodda indata skickar du en timeout. En obehörig användare kan ange indata för att RegularExpressions orsaka en Denial-of-Service-attack. ASP.NET Core Frameworks API som använder RegularExpressions har en timeout.
Det här är en sammanfattning av de steg som routningen utför med mallen /a{b}c{d} och URL-sökvägen /abcd.
| Används för att visualisera hur algoritmen fungerar:
- Den första literalen, från höger till vänster, är
c. Så/abcdsöks från höger och hittar/ab|c|d. - Allt till höger (
d) matchas nu med routningsparametern{d}. - Nästa literal, från höger till vänster, är
a. Så/ab|c|dgenomsöks från där vi slutade, sedan hittasa/|a|b|c|d. - Värdet till höger (
b) matchas nu med routningsparametern{b}. - Det finns ingen kvarvarande text och ingen kvarvarande mall för rutt, så det här är en matchning.
Här är ett exempel på ett negativt ärende med samma mall /a{b}c{d} och URL-sökvägen /aabcd.
| Används för att visualisera hur algoritmen fungerar. Det här fallet är inte en matchning, vilket förklaras av samma algoritm:
- Den första literalen, från höger till vänster, är
c. Så/aabcdsöks från höger och hittar/aab|c|d. - Allt till höger (
d) matchas nu med routningsparametern{d}. - Nästa literal, från höger till vänster, är
a. Så/aab|c|dgenomsöks från där vi slutade, sedan hittasa/a|a|b|c|d. - Värdet till höger (
b) matchas nu med routningsparametern{b}. - I det här läget finns det fortfarande text
a, men algoritmen har slut på vägmall för analys, så detta stämmer inte.
Eftersom matchningsalgoritmen inte är girig:
- Den matchar den minsta möjliga mängden text i varje steg.
- Alla fall där avgränsarvärdet visas i parametervärdena resulterar i att det inte matchar.
Reguljära uttryck ger mycket mer kontroll över deras matchande beteende.
Girig matchning, även kallat maximal matchning , försöker hitta den längsta möjliga matchningen i indatatexten som uppfyller regex-mönstret . Icke-grådig matchning, även kallad försiktig matchning, söker den kortaste möjliga matchningen i inmatningstexten som uppfyller regex-uttrycket.
Routning med specialtecken
Routning med specialtecken kan leda till oväntade resultat. Tänk dig till exempel en kontrollant med följande åtgärdsmetod:
[HttpGet("{id?}/name")]
public async Task<ActionResult<string>> GetName(string id)
{
var todoItem = await _context.TodoItems.FindAsync(id);
if (todoItem == null || todoItem.Name == null)
{
return NotFound();
}
return todoItem.Name;
}
När string id innehåller följande kodade värden kan oväntade resultat inträffa:
| ASCII | Encoded |
|---|---|
/ |
%2F |
|
+ |
Routningsparametrar är inte alltid URL-avkodade. Det här problemet kan åtgärdas i framtiden. Mer information finns i det här GitHub-problemet;
Vägbegränsningar
Routningsbegränsningar körs när en matchning har hittats för den inkommande URL:en och URL-sökvägen tokeniseras till ruttvärden. Routningsbegränsningar inspekterar vanligtvis det vägvärde som är associerat via routningsmallen och fattar ett sant eller falskt beslut om huruvida värdet är acceptabelt. Vissa routningsbegränsningar använder data utanför vägvärdet för att överväga om begäran kan dirigeras. Till exempel HttpMethodRouteConstraint kan acceptera eller avvisa en begäran baserat på dess HTTP-verb. Begränsningar används i routningsbegäranden och länkgenerering.
Warning
Använd inte begränsningar för indataverifiering. Om begränsningar används för indataverifiering resulterar ogiltiga indata i ett 404 svar som inte hittades. Ogiltiga indata bör generera en 400 felaktig begäran med ett lämpligt felmeddelande. Routningsbegränsningar används för att särskilja liknande rutter, inte för att verifiera inmatningar för en viss rutt.
I följande tabell visas standardvägsbegränsningarna och deras förväntade beteende:
| constraint | Example | Exempelmatchningar | Notes |
|---|---|---|---|
int |
{id:int} |
123456789, -123456789 |
Matchar alla heltal |
bool |
{active:bool} |
true, FALSE |
Matchar true eller false. Case-insensitive |
datetime |
{dob:datetime} |
2016-12-31, 2016-12-31 7:32pm |
Matchar ett giltigt DateTime värde i den invarianta kulturen. Se föregående varning |
decimal |
{price:decimal} |
49.99, -1,000.01 |
Matchar ett giltigt decimal värde i den invarianta kulturen. Se föregående varning |
double |
{weight:double} |
1.234, -1,001.01e8 |
Matchar ett giltigt double värde i den invarianta kulturen. Se föregående varning |
float |
{weight:float} |
1.234, -1,001.01e8 |
Matchar ett giltigt float värde i den invarianta kulturen. Se föregående varning |
guid |
{id:guid} |
CD2C1638-1638-72D5-1638-DEADBEEF1638 |
Matchar ett giltigt Guid värde |
long |
{ticks:long} |
123456789, -123456789 |
Matchar ett giltigt long värde |
minlength(value) |
{username:minlength(4)} |
Rick |
Strängen måste innehålla minst 4 tecken |
maxlength(value) |
{filename:maxlength(8)} |
MyFile |
Strängen får inte innehålla fler än 8 tecken |
length(length) |
{filename:length(12)} |
somefile.txt |
Strängen måste vara exakt 12 tecken lång |
length(min,max) |
{filename:length(8,16)} |
somefile.txt |
Strängen får vara minst 8 och högst 16 tecken lång |
min(value) |
{age:min(18)} |
19 |
Heltalsvärdet måste vara minst 18 |
max(value) |
{age:max(120)} |
91 |
Heltalsvärdet får inte vara mer än 120 |
range(min,max) |
{age:range(18,120)} |
91 |
Heltalsvärdet måste vara minst 18 men högst 120 |
alpha |
{name:alpha} |
Rick |
Strängen måste bestå av ett eller flera alfabetiska tecken a-z och skiftlägesokänslig |
regex(expression) |
{ssn:regex(^\\d{{3}}-\\d{{2}}-\\d{{4}}$)} |
123-45-6789 |
Strängen måste matcha det reguljära uttrycket. Se tips om hur du definierar ett reguljärt uttryck |
required |
{name:required} |
Rick |
Används för att framtvinga att ett icke-parametervärde finns under URL-generering |
file |
{filename:file} |
myfile.txt |
Strängen kan innehålla sökvägssegment, men dess sista segment måste ha en punkt (.) och följas av ett eller flera tecken som inte är punkttecken |
nonfile |
{page:nonfile} |
PageName |
Strängen får inte ha en punkt i det sista sökvägssegmentet som följs av ett eller flera icke-punktstecken (.) |
Warning
När du använder System.Text.RegularExpressions för att bearbeta ej betrodda indata skickar du en timeout. En obehörig användare kan ange indata för att RegularExpressions orsaka en Denial-of-Service-attack. ASP.NET Core Frameworks API som använder RegularExpressions har en timeout.
Flera, kolonavgränsade begränsningar kan tillämpas på en enskild parameter. Följande villkor begränsar till exempel en parameter till ett heltalsvärde på 1 eller högre:
[Route("users/{id:int:min(1)}")]
public User GetUserById(int id) { }
Warning
Routningsbegränsningar som verifierar URL:en och konverteras till en CLR-typ använder alltid den invarianta kulturen. Till exempel konvertering till CLR-typen int eller DateTime. Dessa begränsningar förutsätter att URL:en inte kan lokaliseras. De ramverksbaserade vägbegränsningarna ändrar inte de värden som lagras i vägvärden. Alla vägvärden som parsas från URL:en lagras som strängar. Villkoret float försöker till exempel konvertera vägvärdet till en flyttal, men det konverterade värdet används bara för att verifiera att det kan konverteras till en flyttal.
Reguljära uttryck i begränsningar
Warning
När du använder System.Text.RegularExpressions för att bearbeta ej betrodda indata skickar du en timeout. En obehörig användare kan ange indata för att RegularExpressions orsaka en Denial-of-Service-attack. ASP.NET Core Frameworks API som använder RegularExpressions har en timeout.
Reguljära uttryck kan anges som infogade begränsningar med hjälp av routningsbegränsningen regex(...) . Metoder i MapControllerRoute familjen accepterar också en objektliteral av begränsningar. Om formuläret används tolkas strängvärden som reguljära uttryck.
Följande kod använder en infogad regex-begränsning:
app.MapGet("{message:regex(^\\d{{3}}-\\d{{2}}-\\d{{4}}$)}",
() => "Inline Regex Constraint Matched");
Följande kod använder en objektliteral för att ange en regex-begränsning:
app.MapControllerRoute(
name: "people",
pattern: "people/{ssn}",
constraints: new { ssn = "^\\d{3}-\\d{2}-\\d{4}$", },
defaults: new { controller = "People", action = "List" });
Ramverket ASP.NET Core lägger RegexOptions.IgnoreCase | RegexOptions.Compiled | RegexOptions.CultureInvariant till konstruktorn för reguljära uttryck. Se RegexOptions en beskrivning av dessa medlemmar.
Reguljära uttryck använder avgränsare och token som liknar dem som används vid routning och C#-språket. Token för reguljära uttryck måste vara undantagna. Om du vill använda reguljära uttryck ^\d{3}-\d{2}-\d{4}$ i en infogad begränsning använder du något av följande:
- Ersätt
\tecken som anges i strängen som\\tecken i C#-källfilen för att undvika strängens\escape-tecken. - Verbatim strängliteraler.
Om du vill undvika dirigeringsparametertecken {, }, [, ], dubblar du tecknen i uttrycket, {{till exempel , }}, [[, . ]] I följande tabell visas ett reguljärt uttryck och dess undantagna version:
| Reguljärt uttryck | Undantagna reguljära uttryck |
|---|---|
^\d{3}-\d{2}-\d{4}$ |
^\\d{{3}}-\\d{{2}}-\\d{{4}}$ |
^[a-z]{2}$ |
^[[a-z]]{{2}}$ |
Reguljära uttryck som används i routning börjar ofta med ^ tecknet och matchar strängens startposition. Uttrycken slutar ofta med $ tecknet och matchar slutet av strängen. Tecknen ^ och $ ser till att det reguljära uttrycket matchar värdet för hela routningsparametern. Utan ^- och $-tecknen matchar det reguljära uttrycket vilken delsträng som helst i strängen, vilket ofta är oönskat. Följande tabell innehåller exempel och förklarar varför de matchar eller inte matchar:
| Expression | String | Match | Comment |
|---|---|---|---|
[a-z]{2} |
hello | Yes | Matchningar för delsträngar |
[a-z]{2} |
123abc456 | Yes | Matchningar för delsträngar |
[a-z]{2} |
mz | Yes | Matchar uttryck |
[a-z]{2} |
MZ | Yes | Inte skiftlägeskänslig |
^[a-z]{2}$ |
hello | No | Se ^ och $ ovan |
^[a-z]{2}$ |
123abc456 | No | Se ^ och $ ovan |
Mer information om syntax för reguljära uttryck finns i Reguljära .NET Framework-uttryck.
Om du vill begränsa en parameter till en känd uppsättning möjliga värden använder du ett reguljärt uttryck. Till exempel {action:regex(^(list|get|create)$)} matchar endast routningsvärdet action till list, geteller create. Om den skickas in i begränsningsordboken, så är strängen ^(list|get|create)$ likvärdig. Begränsningar som skickas i villkorsordlistan som inte matchar någon av de kända begränsningarna behandlas också som reguljära uttryck. Begränsningar som skickas i en mall som inte matchar någon av de kända begränsningarna behandlas inte som reguljära uttryck.
Begränsningar för anpassad rutt
Anpassade routningsbegränsningar kan skapas genom att implementera IRouteConstraint gränssnittet. Gränssnittet IRouteConstraint innehåller Match, som returnerar true om villkoret är uppfyllt och false på annat sätt.
Anpassade routningsbegränsningar behövs sällan. Innan du implementerar en anpassad vägbegränsning bör du överväga alternativ, till exempel modellbindning.
Mappen ASP.NET Core Constraints innehåller bra exempel på hur du skapar begränsningar. Till exempel GuidRouteConstraint.
Om du vill använda en anpassad IRouteConstraintmåste routningsbegränsningstypen registreras med appens ConstraintMap i tjänstcontainern. A ConstraintMap är en ordlista som mappar routningsbegränsningsnycklar till IRouteConstraint implementeringar som validerar dessa begränsningar. En app"s ConstraintMap kan uppdateras i Program.cs antingen som en del av ett AddRouting-anrop eller genom att konfigurera RouteOptions direkt med builder.Services.Configure<RouteOptions>. Till exempel:
builder.Services.AddRouting(options =>
options.ConstraintMap.Add("noZeroes", typeof(NoZeroesRouteConstraint)));
Föregående villkor tillämpas i följande kod:
[ApiController]
[Route("api/[controller]")]
public class NoZeroesController : ControllerBase
{
[HttpGet("{id:noZeroes}")]
public IActionResult Get(string id) =>
Content(id);
}
Implementeringen av NoZeroesRouteConstraint förhindrar 0 att den används i en vägparameter:
public class NoZeroesRouteConstraint : IRouteConstraint
{
private static readonly Regex _regex = new(
@"^[1-9]*$",
RegexOptions.CultureInvariant | RegexOptions.IgnoreCase,
TimeSpan.FromMilliseconds(100));
public bool Match(
HttpContext? httpContext, IRouter? route, string routeKey,
RouteValueDictionary values, RouteDirection routeDirection)
{
if (!values.TryGetValue(routeKey, out var routeValue))
{
return false;
}
var routeValueString = Convert.ToString(routeValue, CultureInfo.InvariantCulture);
if (routeValueString is null)
{
return false;
}
return _regex.IsMatch(routeValueString);
}
}
Warning
När du använder System.Text.RegularExpressions för att bearbeta ej betrodda indata skickar du en timeout. En obehörig användare kan ange indata för att RegularExpressions orsaka en Denial-of-Service-attack. ASP.NET Core Frameworks API som använder RegularExpressions har en timeout.
Föregående kod:
- Förhindrar
0i{id}segmentet av rutten. - Visas som ett grundläggande exempel på hur du implementerar en anpassad begränsning. Den bör inte användas i en produktionsapp.
Följande kod är en bättre metod för att förhindra att en id innehållande en 0 bearbetas:
[HttpGet("{id}")]
public IActionResult Get(string id)
{
if (id.Contains('0'))
{
return StatusCode(StatusCodes.Status406NotAcceptable);
}
return Content(id);
}
Föregående kod har följande fördelar jämfört med NoZeroesRouteConstraint metoden:
- Det kräver ingen anpassad begränsning.
- Det returnerar ett mer beskrivande fel när vägparametern innehåller
0.
Parametertransformatorer
Parametertransformatorer:
- Utför vid generering av en länk med LinkGenerator.
- Implementera Microsoft.AspNetCore.Routing.IOutboundParameterTransformer.
- Konfigureras med ConstraintMap.
- Ta parameterns vägvärde och omvandla det till ett nytt strängvärde.
- Resulterar i att du använder det transformerade värdet i den genererade länken.
Till exempel, en anpassad slugify-parametertransformator i vägmönster blog\{article:slugify} med Url.Action(new { article = "MyTestArticle" }) genererar blog\my-test-article.
Överväg följande IOutboundParameterTransformer implementering:
public class SlugifyParameterTransformer : IOutboundParameterTransformer
{
public string? TransformOutbound(object? value)
{
if (value is null)
{
return null;
}
return Regex.Replace(
value.ToString()!,
"([a-z])([A-Z])",
"$1-$2",
RegexOptions.CultureInvariant,
TimeSpan.FromMilliseconds(100))
.ToLowerInvariant();
}
}
Om du vill använda en parametertransformator i ett vägmönster konfigurerar du den med hjälp av ConstraintMap i Program.cs:
builder.Services.AddRouting(options =>
options.ConstraintMap["slugify"] = typeof(SlugifyParameterTransformer));
ASP.NET Core-ramverket använder parametertransformatorer för att transformera den URI där en slutpunkt löser problemet. Till exempel transformerar parametertransformatorer de vägvärden som används för att matcha en area, controller, actionoch page:
app.MapControllerRoute(
name: "default",
pattern: "{controller:slugify=Home}/{action:slugify=Index}/{id?}");
Med föregående vägmall matchas åtgärden SubscriptionManagementController.GetAll med URI /subscription-management/get-all:n . En parametertransformator ändrar inte de vägvärden som används för att generera en länk. Till exempel Url.Action("GetAll", "SubscriptionManagement") ger /subscription-management/get-all.
ASP.NET Core tillhandahåller API-konventioner för användning av parametertransformatorer med genererade vägar:
- Microsoft.AspNetCore.Mvc.ApplicationModels.RouteTokenTransformerConvention MVC-konventionen tillämpar en angiven parametertransformator på alla attributvägar i appen. Parametertransformatorn transformerar attributvägstokens eftersom de ersätts. Mer information finns i Använda en parametertransformator för att anpassa tokenbyte.
- Razor Pages använder API-konventionen PageRouteTransformerConvention . Den här konventionen tillämpar en angiven parametertransformator på alla automatiskt identifierade Razor sidor. Parametertransformatoren transformerar mapp- och filnamnssegmenten Razor för Sidvägar. Mer information finns i Använda en parametertransformator för att anpassa sidvägar.
Referens för URL-generering
Det här avsnittet innehåller en referens för algoritmen som implementeras av URL-generering. I praktiken använder de flesta komplexa exempel på URL-generering styrenheter eller Razor sidor. Mer information finns i routning i kontrollanter .
URL-genereringsprocessen börjar med ett anrop till LinkGenerator.GetPathByAddress eller en liknande metod. Metoden tillhandahålls med en adress, en uppsättning vägvärden och eventuellt information om den aktuella begäran från HttpContext.
Det första steget är att använda adressen för att lösa en uppsättning kandidatslutpunkter med hjälp av en IEndpointAddressScheme<TAddress> som matchar adressens typ.
När uppsättningen kandidater hittas av adressschemat sorteras slutpunkterna och bearbetas iterativt tills en URL-genereringsåtgärd lyckas. URL-genereringen söker inte efter tvetydigheter. Det första resultatet som returneras är slutresultatet.
Felsöka URL-generering med loggning
Det första steget i felsökning av URL-generering för Microsoft.AspNetCore.Routing är att ställa in loggningsnivån till TRACE.
LinkGenerator loggar många detaljer om bearbetningen som kan vara användbar för att felsöka problem.
Mer information om URL-generering finns i REFERENS för URL-generering .
Addresses
Adresser är det begrepp i URL-generering som används för att binda ett anrop till länkgeneratorn till en uppsättning kandidatslutpunkter.
Adresser är ett utökningsbart begrepp som levereras med två implementeringar som standard:
- Använda slutpunktsnamnet (
string) som adress:- Tillhandahåller liknande funktioner som MVC:s routningsnamn.
- IEndpointNameMetadata Använder metadatatypen.
- Löser den angivna strängen mot metadata för alla registrerade slutpunkter.
- Utlöser ett undantag vid start om flera slutpunkter använder samma namn.
- Rekommenderas för generell användning utanför kontrollanter och Razor sidor.
- Använda vägvärden (RouteValuesAddress) som adress:
- Ger liknande funktioner som kontroller och äldre URL-generering för sidor.
- Mycket komplext att utöka och felsöka.
- Tillhandahåller implementeringen som används av
IUrlHelper, Tag Helpers, HTML-hjälpare, åtgärdsresultat osv.
Adressschemats roll är att göra associationen mellan adressen och matchande slutpunkter enligt godtyckliga kriterier:
- Slutpunktsnamnschemat utför en grundläggande ordlistesökning.
- Routningsvärdena har en komplex bästa delmängd av set-algoritmen.
Omgivande värden och explicita värden
Från den aktuella begäran får routning åtkomst till routningsvärdena för den aktuella begäran HttpContext.Request.RouteValues. De värden som är associerade med den aktuella begäran kallas för omgivande värden. För tydlighetens skull refererar dokumentationen till de vägvärden som skickas in till metoder som explicita värden.
I följande exempel visas omgivande värden och explicita värden. Den innehåller omgivande värden från den aktuella begäran och explicita värden:
public class WidgetController : ControllerBase
{
private readonly LinkGenerator _linkGenerator;
public WidgetController(LinkGenerator linkGenerator) =>
_linkGenerator = linkGenerator;
public IActionResult Index()
{
var indexPath = _linkGenerator.GetPathByAction(
HttpContext, values: new { id = 17 })!;
return Content(indexPath);
}
// ...
Föregående kod:
- Returnerar
/Widget/Index/17 - Hämtar LinkGenerator via DI.
Följande kod innehåller endast explicita värden och inga omgivande värden:
var subscribePath = _linkGenerator.GetPathByAction(
"Subscribe", "Home", new { id = 17 })!;
Föregående metod returnerar /Home/Subscribe/17
Följande kod i WidgetController returnerar /Widget/Subscribe/17:
var subscribePath = _linkGenerator.GetPathByAction(
HttpContext, "Subscribe", null, new { id = 17 });
Följande kod tillhandahåller kontrollern från omgivande och explicita värden i den aktuella begäran.
public class GadgetController : ControllerBase
{
public IActionResult Index() =>
Content(Url.Action("Edit", new { id = 17 })!);
}
I koden ovan:
-
/Gadget/Edit/17returneras. - Url hämtar IUrlHelper.
-
Action genererar en URL med en absolut sökväg för en åtgärdsmetod. URL:en innehåller det angivna
actionnamnet ochroutevärdena.
Följande kod innehåller omgivande värden från den aktuella begäran och explicita värden:
public class IndexModel : PageModel
{
public void OnGet()
{
var editUrl = Url.Page("./Edit", new { id = 17 });
// ...
}
}
Den föregående koden sätter url till /Edit/17 när Redigera Razor Sida innehåller följande siddirektiv:
@page "{id:int}"
Om sidan Redigera inte innehåller "{id:int}"-routemallen, är url/Edit?id=17.
Beteendet för MVC lägger IUrlHelper till ett lager av komplexitet utöver de regler som beskrivs här:
-
IUrlHelpertillhandahåller alltid vägvärdena från den aktuella begäran som omgivande värden. -
IUrlHelper.Action kopierar alltid aktuella
actionvärden ochcontrollervägvärden som explicita värden om de inte åsidosätts av utvecklaren. -
IUrlHelper.Page kopierar alltid det aktuella
pagevägvärdet som ett explicit värde om det inte åsidosätts. -
IUrlHelper.Pageåsidosätter alltid det aktuellahandlerruttvärdet mednullsom ett explicit värde såvida det inte åsidosätts.
Användarna blir ofta förvånade över beteendeinformationen för omgivande värden, eftersom MVC inte verkar följa sina egna regler. Av historiska och kompatibilitetsskäl har vissa routningsvärden som action, controller, pageoch handler ett eget specialfallsbeteende.
Motsvarande funktionalitet som tillhandahålls av LinkGenerator.GetPathByAction och LinkGenerator.GetPathByPage duplicerar dessa avvikelser i IUrlHelper för kompatibilitet.
Process för URL-generering
När uppsättningen kandidatslutpunkter hittas, algoritmen för URL-generering:
- Bearbetar slutpunkterna iterativt.
- Returnerar det första lyckade resultatet.
Det första steget i den här processen kallas ogiltigförklarande av routningsvärden. Ogiltigförklaring av routningsvärden är den process genom vilken routning avgör vilka routningsvärden från bakgrundsvärden som ska användas och vilka som ska ignoreras. Varje omgivande värde beaktas och kombineras antingen med explicita värden eller ignoreras.
Det bästa sättet att förstå rollen av omgivande värden är att de försöker spara skrivande för programutvecklare i vissa vanliga situationer. Traditionellt är scenarier där omgivande värden är användbara relaterade till MVC:
- När du länkar till en annan åtgärd i samma kontrollant behöver inte kontrollantnamnet anges.
- När du länkar till en annan kontrollant i samma område behöver du inte ange områdesnamnet.
- När du länkar till samma åtgärdsmetod behöver du inte ange vägvärden.
- När du länkar till en annan del av appen vill du inte överföra routningsvärden som inte har någon betydelse i den delen av appen.
Anrop till LinkGenerator eller IUrlHelper som returnerar null orsakas vanligtvis av bristande förståelse av ogiltigförklaring av routningsvärden. Felsöka routningsvärdets ogiltighet genom att uttryckligen ange fler av vägvärdena för att se om det löser problemet.
Ogiltigförklaring av routvärden bygger på antagandet att appens URL-schema är hierarkiskt, med en hierarki som bildas från vänster till höger. Överväg den grundläggande mallen för styrenhetsroutning {controller}/{action}/{id?} för att få en intuitiv uppfattning om hur detta fungerar i praktiken. En ändring av ett värde ogiltigförklarar alla vägvärden som visas till höger. Detta återspeglar antagandet om hierarki. Om appen har ett omgivande värde för id, och åtgärden anger ett annat värde för controller:
-
idåteranvänds inte eftersom{controller}är till vänster om{id?}.
Några exempel som visar den här principen:
- Om de explicita värdena innehåller ett värde för
idignoreras det omgivande värdet förid. Omgivande värden förcontrollerochactionkan användas. - Om de explicita värdena innehåller ett värde för
actionignoreras alla omgivande värden föraction. Omgivningsvärdena förcontrollerkan användas. Om det explicita värdet föractionskiljer sig från det omgivande värdet föractionidanvänds inte värdet. Om det tydliga värdet föractionär detsamma som det omgivande värdet föraction, kanidvärdet användas. - Om de explicita värdena innehåller ett värde för
controllerignoreras alla omgivande värden förcontroller. Om det explicita värdet förcontrollerskiljer sig från det omgivande värdet förcontrolleractionanvänds inte värdena ochid. Om det explicita värdet förcontrollerär detsamma som det omgivande värdet förcontrolleractionkan värdena ochidanvändas.
Den här processen kompliceras ytterligare av förekomsten av attributvägar och dedikerade konventionella vägar. Styrenheters konventionella vägar som {controller}/{action}/{id?} specificerar en hierarki med hjälp av ruttparametrar. För dedikerade konventionella vägar och attributvägar till styrningar och Razor sidor:
- Det finns en hierarki med vägvärden.
- De visas inte i mallen.
I dessa fall definierar URL-generering det nödvändiga värdekonceptet . Slutpunkter som skapats av kontrollanter och Razor sidor har angivna värden som gör att vägvärdets ogiltighet kan fungera.
Ruttvärdets ogiltighetsalgoritm förklarad:
- De nödvändiga värdenamnen kombineras med vägparametrarna och bearbetas sedan från vänster till höger.
- För varje parameter jämförs det omgivande värdet och det explicita värdet:
- Om det omgivande värdet och det explicita värdet är samma fortsätter processen.
- Om det omgivande värdet finns och det explicita värdet inte är det används det omgivande värdet när URL:en genereras.
- Om det omgivande värdet inte finns och det explicita värdet är avvisar du det omgivande värdet och alla efterföljande omgivande värden.
- Om det omgivande värdet och det explicita värdet finns, och de två värdena är olika, avvisar du det omgivande värdet och alla efterföljande omgivande värden.
I det här läget är URL-genereringsåtgärden redo att utvärdera routningsbegränsningar. Uppsättningen godkända värden kombineras med parameterns standardvärden, vilka tillhandahålls för begränsningar. Om alla begränsningar uppfylls fortsätter operationen.
Därefter kan de godkända värdena användas för att expandera routningsmallen. Vägmallen bearbetas:
- Från vänster till höger.
- Varje parameter har sitt godkända värde ersatt.
- Med följande specialfall:
- Om de godkända värdena saknar ett värde och parametern har ett standardvärde används standardvärdet.
- Om de godkända värdena saknar ett värde och parametern är valfri fortsätter bearbetningen.
- Om en routningsparameter till höger om en valfri parameter som saknas har ett värde misslyckas åtgärden.
- Sammanhängande standardvärdeparametrar och valfria parametrar komprimeras där det är möjligt.
Värden som uttryckligen anges som inte matchar ett segment av vägen läggs till i frågesträngen. Följande tabell visar resultatet när du använder routningsmallen {controller}/{action}/{id?}.
| Omgivande värden | Explicita värden | Result |
|---|---|---|
| controller = "Home" | action = "Om" | /Home/About |
| controller = "Home" | controller = "Beställning", action = "Om" | /Order/About |
| controller = "Home", color = "Röd" | action = "Om" | /Home/About |
| controller = "Home" | action = "Om", color = "Röd" | /Home/About?color=Red |
Valfri vägparameterordning
Valfria vägparametrar måste komma efter alla obligatoriska vägparametrar och literaler. I följande kod måste parametrarna id och name komma efter parametern color :
using Microsoft.AspNetCore.Mvc;
namespace WebApplication1.Controllers;
[Route("api/[controller]")]
public class MyController : ControllerBase
{
// GET /api/my/red/2/joe
// GET /api/my/red/2
// GET /api/my
[HttpGet("{color}/{id:int?}/{name?}")]
public IActionResult GetByIdAndOptionalName(string color, int id = 1, string? name = null)
{
return Ok($"{color} {id} {name ?? ""}");
}
}
Problem med att routningsvärdet är ogiltigt
Följande kod visar ett exempel på ett URL-genereringsschema som inte stöds av routning:
app.MapControllerRoute(
"default",
"{culture}/{controller=Home}/{action=Index}/{id?}");
app.MapControllerRoute(
"blog",
"{culture}/{**slug}",
new { controller = "Blog", action = "ReadPost" });
I föregående kod culture används routningsparametern för lokalisering. Önskan är att parametern culture alltid ska accepteras som ett omgivande värde. Parametern culture accepteras dock inte som ett omgivande värde på grund av hur nödvändiga värden fungerar:
- I routningsmallen
"default"är routningsparameternculturetill vänster omcontroller, så ändringar i kommer inte attcontrollerogiltigförklaraculture. -
"blog"I vägmallencultureanses vägparametern vara till höger omcontroller, som visas i de obligatoriska värdena.
Parsa URL-sökvägar med LinkParser
Klassen LinkParser lägger till stöd för att parsa en URL-sökväg till en uppsättning vägvärden. Metoden ParsePathByEndpointName tar ett slutpunktsnamn och en URL-sökväg och returnerar en uppsättning vägvärden som extraherats från URL-sökvägen.
I följande exempelkontrollant använder åtgärden GetProduct en routningsmall med api/Products/{id} och har en Name av GetProduct:
[ApiController]
[Route("api/[controller]")]
public class ProductsController : ControllerBase
{
[HttpGet("{id}", Name = nameof(GetProduct))]
public IActionResult GetProduct(string id)
{
// ...
I samma kontrollantklass AddRelatedProduct förväntar sig åtgärden en URL-sökväg, , pathToRelatedProductsom kan anges som en frågesträngsparameter:
[HttpPost("{id}/Related")]
public IActionResult AddRelatedProduct(
string id, string pathToRelatedProduct, [FromServices] LinkParser linkParser)
{
var routeValues = linkParser.ParsePathByEndpointName(
nameof(GetProduct), pathToRelatedProduct);
var relatedProductId = routeValues?["id"];
// ...
I föregående exempel extraherar AddRelatedProduct åtgärden id ruttvärdet från URL-sökvägen. Till exempel, med en URL-sökväg på /api/Products/1, är värdet på relatedProductId inställt till 1. Med den här metoden kan API:ets klienter använda URL-sökvägar när de refererar till resurser, utan att behöva veta hur en sådan URL är strukturerad.
Konfigurera slutpunktsmetadata
Följande länkar innehåller information om hur du konfigurerar slutpunktsmetadata:
- Aktivera Cors med slutpunktsroutning
-
Exempel på IAuthorizationPolicyProvider med ett anpassat
[MinimumAgeAuthorize]attribut - Testa autentisering med attributet [Auktorisera]
- RequireAuthorization
- Välja schemat med attributet [Auktorisera]
- Tillämpa principer med attributet [Auktorisera]
- Rollbaserad auktorisering i ASP.NET Core
Värdmatchning i rutter med RequireHost
RequireHost tillämpar en begränsning på den rutt som kräver den angivna värden. Parametern RequireHost eller [Värd] kan vara en:
- Värd:
www.domain.com, matcharwww.domain.commed valfri port. - Värd med jokertecken:
*.domain.com, matcharwww.domain.com,subdomain.domain.com, ellerwww.subdomain.domain.compå valfri port. - Port:
*:5000, matchar port 5000 med valfri värd. - Värd och port:
www.domain.com:5000eller*.domain.com:5000, matchar värd och port.
Flera parametrar kan anges med RequireHost eller [Host]. Villkoret matchar värdar som är giltiga för någon av parametrarna. Matchar till exempel [Host("domain.com", "*.domain.com")], domain.com, www.domain.com, och subdomain.domain.com.
Följande kod använder RequireHost för att kräva den angivna värden på rutten:
app.MapGet("/", () => "Contoso").RequireHost("contoso.com");
app.MapGet("/", () => "AdventureWorks").RequireHost("adventure-works.com");
app.MapHealthChecks("/healthz").RequireHost("*:8080");
Följande kod använder [Host] attributet på kontrollanten för att kräva någon av de angivna värdarna:
[Host("contoso.com", "adventure-works.com")]
public class HostsController : Controller
{
public IActionResult Index() =>
View();
[Host("example.com")]
public IActionResult Example() =>
View();
}
[Host] När attributet tillämpas på både kontrollanten och åtgärdsmetoden:
- Attributet för åtgärden används.
- Kontrollantattributet ignoreras.
Warning
API som förlitar sig på värdrubriken, till exempel HttpRequest.Host och RequireHost, är föremål för potentiell förfalskning av klienter.
Använd någon av följande metoder för att förhindra förfalskning av värd- och portar:
- Använd HttpContext.Connection (ConnectionInfo.LocalPort) där portarna är markerade.
- Använd värdfiltrering.
Routningsgrupper
Tilläggsmetoden MapGroup hjälper till att organisera grupper av slutpunkter med ett gemensamt prefix. Det minskar repetitiv kod och gör det möjligt att anpassa hela grupper av slutpunkter med ett enda anrop till metoder som RequireAuthorization och WithMetadata som lägger till slutpunktsmetadata.
Följande kod skapar till exempel två liknande grupper av slutpunkter:
app.MapGroup("/public/todos")
.MapTodosApi()
.WithTags("Public");
app.MapGroup("/private/todos")
.MapTodosApi()
.WithTags("Private")
.AddEndpointFilterFactory(QueryPrivateTodos)
.RequireAuthorization();
EndpointFilterDelegate QueryPrivateTodos(EndpointFilterFactoryContext factoryContext, EndpointFilterDelegate next)
{
var dbContextIndex = -1;
foreach (var argument in factoryContext.MethodInfo.GetParameters())
{
if (argument.ParameterType == typeof(TodoDb))
{
dbContextIndex = argument.Position;
break;
}
}
// Skip filter if the method doesn't have a TodoDb parameter.
if (dbContextIndex < 0)
{
return next;
}
return async invocationContext =>
{
var dbContext = invocationContext.GetArgument<TodoDb>(dbContextIndex);
dbContext.IsPrivate = true;
try
{
return await next(invocationContext);
}
finally
{
// This should only be relevant if you're pooling or otherwise reusing the DbContext instance.
dbContext.IsPrivate = false;
}
};
}
public static RouteGroupBuilder MapTodosApi(this RouteGroupBuilder group)
{
group.MapGet("/", GetAllTodos);
group.MapGet("/{id}", GetTodo);
group.MapPost("/", CreateTodo);
group.MapPut("/{id}", UpdateTodo);
group.MapDelete("/{id}", DeleteTodo);
return group;
}
I det här scenariot kan du använda en relativ adress för Location-rubriken i 201 Created-resultatet.
public static async Task<Created<Todo>> CreateTodo(Todo todo, TodoDb database)
{
await database.AddAsync(todo);
await database.SaveChangesAsync();
return TypedResults.Created($"{todo.Id}", todo);
}
Den första gruppen med slutpunkter matchar endast begäranden som är prefix med /public/todos och är tillgängliga utan autentisering. Den andra gruppen med slutpunkter matchar endast begäranden som är prefix med /private/todos och kräver autentisering.
QueryPrivateTodos
slutpunktfilterfabriken är en lokal funktion som ändrar rout-hanterarens TodoDb parametrar för att tillåta åtkomst till och lagring av privata data.
Routningsgrupper stöder också kapslade grupper och komplexa prefixmönster med vägparametrar och begränsningar. I följande exempel kan routhanteraren som mappas till gruppen user fånga de {org}- och {group}-routningsparametrar som definierats i de yttre gruppens prefix.
Prefixet kan också vara tomt. Detta kan vara användbart för att lägga till slutpunktsmetadata eller filter till en grupp slutpunkter utan att ändra vägmönstret.
var all = app.MapGroup("").WithOpenApi();
var org = all.MapGroup("{org}");
var user = org.MapGroup("{user}");
user.MapGet("", (string org, string user) => $"{org}/{user}");
Att lägga till filter eller metadata i en grupp fungerar på samma sätt som att lägga till dem individuellt i varje slutpunkt innan du lägger till extra filter eller metadata som kan ha lagts till i en inre grupp eller en specifik slutpunkt.
var outer = app.MapGroup("/outer");
var inner = outer.MapGroup("/inner");
inner.AddEndpointFilter((context, next) =>
{
app.Logger.LogInformation("/inner group filter");
return next(context);
});
outer.AddEndpointFilter((context, next) =>
{
app.Logger.LogInformation("/outer group filter");
return next(context);
});
inner.MapGet("/", () => "Hi!").AddEndpointFilter((context, next) =>
{
app.Logger.LogInformation("MapGet filter");
return next(context);
});
I exemplet ovan loggar det yttre filtret den inkommande begäran före det inre filtret trots att det lades till tvåa. Eftersom filtren tillämpades på olika grupper spelar det ingen roll vilken ordning de lades till i förhållande till varandra. Orderfiltren som läggs till spelar roll om de tillämpas på samma grupp eller specifika slutpunkt.
En begäran om att /outer/inner/ loggar följande:
/outer group filter
/inner group filter
MapGet filter
Prestandavägledning för routning
När en app har prestandaproblem misstänks routning ofta vara problemet. Anledningen till att routning misstänks är att ramverk som kontrollers och Razor Pages rapporterar hur lång tid som spenderas inom ramverket i sina loggningsmeddelanden. När det finns en betydande skillnad mellan den tid som rapporteras av kontrollanter och den totala tiden för begäran:
- Utvecklare eliminerar sin appkod som källa till problemet.
- Det är vanligt att anta att routning är orsaken.
Routning är prestandatestad med tusentals slutpunkter. Det är osannolikt att en typisk app kommer att stöta på ett prestandaproblem bara genom att vara för stor. Den vanligaste grundorsaken till långsamma routningsprestanda är vanligtvis ett dåligt fungerande anpassad middleware.
Följande kodexempel visar en grundläggande teknik för att begränsa fördröjningskällan:
var logger = app.Services.GetRequiredService<ILogger<Program>>();
app.Use(async (context, next) =>
{
var stopwatch = Stopwatch.StartNew();
await next(context);
stopwatch.Stop();
logger.LogInformation("Time 1: {ElapsedMilliseconds}ms", stopwatch.ElapsedMilliseconds);
});
app.UseRouting();
app.Use(async (context, next) =>
{
var stopwatch = Stopwatch.StartNew();
await next(context);
stopwatch.Stop();
logger.LogInformation("Time 2: {ElapsedMilliseconds}ms", stopwatch.ElapsedMilliseconds);
});
app.UseAuthorization();
app.Use(async (context, next) =>
{
var stopwatch = Stopwatch.StartNew();
await next(context);
stopwatch.Stop();
logger.LogInformation("Time 3: {ElapsedMilliseconds}ms", stopwatch.ElapsedMilliseconds);
});
app.MapGet("/", () => "Timing Test.");
För att schemalägga dirigeringen:
- Alternativt infoga mellanprogrammen med en kopia av tidsmellanprogrammet som visas i föregående kod.
- Lägg till en unik identifierare för att korrelera tidsdata med koden.
Det här är ett grundläggande sätt att begränsa fördröjningen när den är betydande, till exempel mer än 10ms. Subtrahera Time 2 från Time 1 rapporterar tiden som spenderats i UseRouting mellanprogrammet.
Följande kod använder en mer kompakt metod för föregående tidskod:
public sealed class AutoStopwatch : IDisposable
{
private readonly ILogger _logger;
private readonly string _message;
private readonly Stopwatch _stopwatch;
private bool _disposed;
public AutoStopwatch(ILogger logger, string message) =>
(_logger, _message, _stopwatch) = (logger, message, Stopwatch.StartNew());
public void Dispose()
{
if (_disposed)
{
return;
}
_logger.LogInformation("{Message}: {ElapsedMilliseconds}ms",
_message, _stopwatch.ElapsedMilliseconds);
_disposed = true;
}
}
var logger = app.Services.GetRequiredService<ILogger<Program>>();
var timerCount = 0;
app.Use(async (context, next) =>
{
using (new AutoStopwatch(logger, $"Time {++timerCount}"))
{
await next(context);
}
});
app.UseRouting();
app.Use(async (context, next) =>
{
using (new AutoStopwatch(logger, $"Time {++timerCount}"))
{
await next(context);
}
});
app.UseAuthorization();
app.Use(async (context, next) =>
{
using (new AutoStopwatch(logger, $"Time {++timerCount}"))
{
await next(context);
}
});
app.MapGet("/", () => "Timing Test.");
Potentiellt dyra routningsfunktioner
Följande lista ger en inblick i routningsfunktioner som är relativt dyra jämfört med grundläggande routningsmallar:
- Reguljära uttryck: Det går att skriva reguljära uttryck som är komplexa eller har lång körningstid med en liten mängd indata.
- Komplicerade segment (
{x}-{y}-{z}):- Är betydligt dyrare än att parsa ett vanligt URL-sökvägssegment.
- Resulterar i att många fler delsträngar kommer att allokeras.
- Synkron dataåtkomst: Många komplexa appar har databasåtkomst som en del av routningen. Använd utökningspunkter som MatcherPolicy och EndpointSelectorContext, som är asynkrona.
Vägledning för stora routningstabeller
Som standard använder ASP.NET Core en routningsalgoritm som byter minne mot CPU-tid. Detta har den fina effekten att vägmatchningstiden endast beror på längden på sökvägen som ska matchas och inte antalet vägar. Den här metoden kan dock vara potentiellt problematisk i vissa fall, när appen har ett stort antal vägar (i tusental) och det finns en hög mängd variabelprefix i vägarna. Om rutterna har parametrar i tidiga segment av rutten, som {parameter}/some/literal.
Det är osannolikt att en app stöter på en situation där detta är ett problem om inte:
- Det finns ett stort antal vägar i appen med det här mönstret.
- Det finns ett stort antal vägar i appen.
Så här avgör du om en app stöter på problemet med den stora routningstabellen
- Det finns två symptom att leta efter:
- Appen startar långsamt vid första användningen.
- Observera att detta är obligatoriskt men inte tillräckligt. Det finns många andra problem som inte är routningsproblem än vad som kan orsaka långsam appstart. Kontrollera om villkoret nedan är korrekt för att fastställa att appen körs i den här situationen.
- Appen förbrukar mycket minne under starten och en minnesdump visar ett stort antal
Microsoft.AspNetCore.Routing.Matching.DfaNodeinstanser.
- Appen startar långsamt vid första användningen.
Så här åtgärdar du det här problemet
Det finns flera tekniker och optimeringar som kan tillämpas på vägar som till stor del förbättrar det här scenariot:
- Tillämpa routningsbegränsningar på dina parametrar, till exempel
{parameter:int},{parameter:guid},{parameter:regex(\\d+)}osv. där det är möjligt.- På så sätt kan routningsalgoritmen internt optimera de strukturer som används för matchning och drastiskt minska det minne som används.
- I de allra flesta fall räcker detta för att återgå till ett acceptabelt beteende.
- Ändra vägarna för att flytta parametrar till senare segment i mallen.
- Detta minskar antalet möjliga "vägar" för att matcha en slutpunkt med en given väg.
- Använd en dynamisk rutt och utför mappningen till en kontroller/sida dynamiskt.
- Detta kan uppnås med hjälp av
MapDynamicControllerRouteochMapDynamicPageRoute.
- Detta kan uppnås med hjälp av
Kortslutningsmellanprogram efter routning
När routningen matchar en slutpunkt låter den vanligtvis resten av pipelinen för mellanprogram köras innan slutpunktslogik anropas. Tjänster kan minska resursanvändningen genom att filtrera bort kända begäranden tidigt i pipelinen. Använd ShortCircuit-tilläggsmetoden för att få routning att anropa slutpunktslogik omedelbart och sedan avsluta begäran. En viss väg kanske till exempel inte behöver gå igenom autentisering eller CORS-mellanprogram. Följande exempel avbryter förfrågningar som matchar den /short-circuit rutten.
app.MapGet("/short-circuit", () => "Short circuiting!").ShortCircuit();
Metoden ShortCircuit(IEndpointConventionBuilder, Nullable<Int32>) kan också ta en statuskod.
Använd metoden MapShortCircuit för att konfigurera genvägar för flera rutter samtidigt genom att skicka en parameterlista med URL-prefix till den. Webbläsare och robotar avsöker till exempel ofta servrar efter välkända sökvägar som robots.txt och favicon.ico. Om appen inte har dessa filer kan en kodrad konfigurera båda vägarna:
app.MapShortCircuit(404, "robots.txt", "favicon.ico");
MapShortCircuit returnerar IEndpointConventionBuilder så att ytterligare vägbegränsningar som värdfiltrering kan läggas till i den.
Metoderna ShortCircuit och MapShortCircuit påverkar inte mellanprogram som placerats före UseRouting. Om du försöker använda dessa metoder med slutpunkter som också har [Authorize] eller [RequireCors] metadata kommer begäranden att misslyckas med en InvalidOperationException. Dessa metadata tillämpas av [Authorize] eller [EnableCors] attribut eller av RequireCors eller RequireAuthorization metoder.
Om du vill se effekten av kortslutningsmellanprogram anger du loggningskategorin "Microsoft" till "Information" i appsettings.Development.json:
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Information",
"Microsoft.Hosting.Lifetime": "Information"
}
}
}
Kör följande kod:
var app = WebApplication.Create();
app.UseHttpLogging();
app.MapGet("/", () => "No short-circuiting!");
app.MapGet("/short-circuit", () => "Short circuiting!").ShortCircuit();
app.MapShortCircuit(404, "robots.txt", "favicon.ico");
app.Run();
Följande exempel är från de konsolloggar som skapas genom att köra endpointen /. Den innehåller utdata från loggningsmellanprogrammet:
info: Microsoft.AspNetCore.Routing.EndpointMiddleware[0]
Executing endpoint 'HTTP: GET /'
info: Microsoft.AspNetCore.Routing.EndpointMiddleware[1]
Executed endpoint 'HTTP: GET /'
info: Microsoft.AspNetCore.HttpLogging.HttpLoggingMiddleware[2]
Response:
StatusCode: 200
Content-Type: text/plain; charset=utf-8
Date: Wed, 03 May 2023 21:05:59 GMT
Server: Kestrel
Alt-Svc: h3=":5182"; ma=86400
Transfer-Encoding: chunked
Följande exempel är från när man kör slutpunkten /short-circuit. Den har inget från loggningsmellanprogrammet eftersom mellanprogrammet var kortslutet:
info: Microsoft.AspNetCore.Routing.EndpointRoutingMiddleware[4]
The endpoint 'HTTP: GET /short-circuit' is being executed without running additional middleware.
info: Microsoft.AspNetCore.Routing.EndpointRoutingMiddleware[5]
The endpoint 'HTTP: GET /short-circuit' has been executed without running additional middleware.
Vägledning för biblioteksförfattare
Det här avsnittet innehåller vägledning för biblioteksförfattare som bygger ovanpå routning. Den här informationen är avsedd att säkerställa att apputvecklare har en bra upplevelse med hjälp av bibliotek och ramverk som utökar routningen.
Definiera slutpunkter
Om du vill skapa ett ramverk som använder routning för URL-matchning börjar du med att definiera en användarupplevelse som bygger ovanpå UseEndpoints.
BYGG ovanpå IEndpointRouteBuilder. På så sätt kan användarna skapa ditt ramverk med andra ASP.NET Core-funktioner utan förväxling. Varje ASP.NET Core-mall innehåller routning. Anta att routning är närvarande och bekant för användare.
// Your framework
app.MapMyFramework(...);
app.MapHealthChecks("/healthz");
Returnera en förseglad betongtyp från ett anrop till MapMyFramework(...) som implementerar IEndpointConventionBuilder. De flesta ramverksmetoder Map... följer det här mönstret. Gränssnittet IEndpointConventionBuilder :
- Tillåter att metadata skapas.
- Är mål för en mängd olika tilläggsmetoder.
Om du deklarerar din egen typ kan du lägga till dina egna ramverksspecifika funktioner i byggaren. Det är okej att omsluta ett ramverksdeklarerat byggobjekt och vidarebefordra anrop till det.
// Your framework
app.MapMyFramework(...)
.RequireAuthorization()
.WithMyFrameworkFeature(awesome: true);
app.MapHealthChecks("/healthz");
ÖVERVÄG att skriva din egen EndpointDataSource.
EndpointDataSource är en grundläggande konstruktion för att deklarera och uppdatera en samling slutpunkter.
EndpointDataSource är ett kraftfullt API som används av kontrollanter och Razor sidor. Mer information finns i Dynamisk slutpunktsroutning.
Routningstesterna har ett grundläggande exempel på en datakälla som inte uppdateras.
ÖVERVÄG att implementera GetGroupedEndpoints. Detta ger fullständig kontroll över gruppkonventioner som körs och de slutliga metadata på de grupperade slutpunkterna. Detta gör till exempel att anpassade EndpointDataSource implementeringar kan köra slutpunktsfilter som lagts till i grupper.
Försök INTE att registrera en EndpointDataSource som standard. Kräv att användare registrerar ditt ramverk i UseEndpoints. Routningsfilosofin är att ingenting ingår som standard, och det UseEndpoints är platsen där slutpunkter ska registreras.
Skapa routningsintegrerade mellanprogram
ÖVERVÄG att definiera metadatatyper som ett gränssnitt.
Gör det möjligt att använda metadatatyper som ett attribut för klasser och metoder.
public interface ICoolMetadata
{
bool IsCool { get; }
}
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
public class CoolMetadataAttribute : Attribute, ICoolMetadata
{
public bool IsCool => true;
}
Ramverk som kontrollanter och Razor sidor stöder tillämpning av metadataattribut på typer och metoder. Om du deklarerar metadatatyper:
- Gör dem tillgängliga som attribut.
- De flesta användare är bekanta med att tillämpa attribut.
Om du deklarerar en metadatatyp som ett gränssnitt läggs ett annat flexibelt lager till:
- Gränssnitt är sammansättningsbara.
- Utvecklare kan deklarera sina egna typer som kombinerar flera principer.
Gör det möjligt att åsidosätta metadata, som du ser i följande exempel:
[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() { }
}
Det bästa sättet att följa dessa riktlinjer är att undvika att definiera markörmetadata:
- Leta inte bara efter förekomsten av en metadatatyp.
- Definiera en egenskap för metadata och kontrollera egenskapen.
Metadatasamlingen är ordnad och möjliggör att överskrida efter prioritet. När det gäller kontrollanter är metadata för åtgärdsmetoden mest specifika.
Gör mellanprogram användbara med och utan routning:
app.UseAuthorization(new AuthorizationPolicy() { ... });
// Your framework
app.MapMyFramework(...).RequireAuthorization();
Som ett exempel på den här riktlinjen bör du överväga UseAuthorization mellanprogrammet. Med mellanprogrammet för auktorisering kan du ange en reservpolicy.
Om den anges, gäller återställningsprincipen för båda:
- Slutpunkter utan en angiven policy.
- Begäranden som inte överensstämmer med en slutpunkt.
Detta gör auktoriseringsmellanprogrammet användbart utanför routningskontexten. Mellanprogrammet för auktorisering kan användas för traditionell mellanprogramprogrammering.
Felsökningsdiagnostik
För detaljerade routningsdiagnostikutdata anger du Logging:LogLevel:Microsoft till Debug. I utvecklingsmiljön anger du loggnivån i appsettings.Development.json:
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Debug",
"Microsoft.Hosting.Lifetime": "Information"
}
}
}
Ytterligare resurser
Routning ansvarar för att matcha inkommande HTTP-begäranden och skicka dessa begäranden till appens körbara slutpunkter. Slutpunkter är appens enheter för körbar kod för hantering av begäranden. Slutpunkter definieras i appen och konfigureras när appen startas. Slutpunktsmatchningsprocessen kan extrahera värden från begärans URL och ange dessa värden för bearbetning av begäranden. Med hjälp av slutpunktsinformation från appen kan routning också generera URL:er som mappar till slutpunkter.
Appar kan konfigurera routning med hjälp av:
- Controllers
- Razor sidor
- SignalR
- gRPC-tjänster
- Slutpunktsaktiverat mellanprogram , till exempel hälsokontroller.
- Delegater och lambdas som registrerats med routning.
Den här artikeln beskriver information på låg nivå om ASP.NET Core-routning. Information om hur du konfigurerar routning:
- För kontrollanter, se Routning till kontrollantåtgärder i ASP.NET Core.
- För Razor Sidor-konventioner, se Razor Sidor rout- och appkonventioner i ASP.NET Core.
Grunderna för routning
Följande kod visar ett grundläggande exempel på routning:
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
app.MapGet("/", () => "Hello World!");
app.Run();
Föregående exempel innehåller en enskild slutpunkt med hjälp av MapGet metoden:
- När en HTTP-begäran
GETskickas till rot-URL:en/:- Begärandedelegaten utförs.
-
Hello World!skrivs till HTTP-svaret.
- Om begärandemetoden inte är
GETeller om rot-URL:en inte är/, matchar ingen rutt och en HTTP 404 returneras.
Routning använder ett par mellanprogram, registrerade av UseRouting och UseEndpoints:
-
UseRoutinglägger till routningsmatchning till pipelinen för mellanprogram. Det här mellanprogrammet tittar på den uppsättning slutpunkter som definierats i appen och väljer den bästa matchningen baserat på begäran. -
UseEndpointslägger till slutpunktskörning i pipelinen för mellanprogram. Den kör delegeringen som är kopplad till den valda slutpunkten.
Appar behöver vanligtvis inte anropa UseRouting eller UseEndpoints.
WebApplicationBuilder konfigurerar en middleware-pipeline som omsluter den middleware som lagts till i Program.cs med UseRouting och UseEndpoints. Appar kan dock ändra i vilken UseRouting ordning och UseEndpoints körs genom att anropa dessa metoder explicit. Följande kod gör till exempel ett explicit anrop till UseRouting:
app.Use(async (context, next) =>
{
// ...
await next(context);
});
app.UseRouting();
app.MapGet("/", () => "Hello World!");
I koden ovan:
- Anropet till
app.Useregistrerar ett anpassat mellanprogram som körs i början av pipelinen. - Anropet till
UseRoutingkonfigurerar mellanprogrammet för ruttmatchning att köras efter det anpassade mellanprogrammet. - Slutpunkten som registrerats med
MapGetkörs i slutet av pipeline.
Om föregående exempel inte innehöll ett anrop till UseRoutingskulle det anpassade mellanprogrammet köras efter vägen som matchar mellanprogrammet.
Endpoints
Metoden MapGet används för att definiera en slutpunkt. En slutpunkt är något som kan vara:
- Vald genom att matcha URL:en och HTTP-metoden.
- Utförs genom att köra delegeringen.
Ändpunkter som kan matchas och köras av appen konfigureras i UseEndpoints. Till exempel ansluter MapGet, MapPost och liknande metoder förbinder ombud för begäranden till routningssystemet. Ytterligare metoder kan användas för att ansluta ASP.NET Core Framework-funktioner till routningssystemet:
- MapRazorPages för Razor sidor
- MapControllers för styrenheter
- MapHub<THub> för SignalR
- MapGrpcService<TService> för gRPC
I följande exempel visas routning med en mer avancerad vägmall:
app.MapGet("/hello/{name:alpha}", (string name) => $"Hello {name}!");
Strängen /hello/{name:alpha} är en vägmall. En vägmall används för att konfigurera hur slutpunkten matchas. I det här fallet matchar mallen:
- En URL som
/hello/Docs - Alla URL-sökvägar som börjar med
/hello/följt av en sekvens med alfabetiska tecken.:alphatillämpar en vägbegränsning som endast matchar alfabetiska tecken. Routningsbegränsningar beskrivs senare i den här artikeln.
Det andra segmentet i URL-sökvägen: {name:alpha}
- Är bunden till parametern
name. - Samlas in och lagras i HttpRequest.RouteValues.
I följande exempel visas routning med hälsokontroller och auktorisering:
app.UseAuthentication();
app.UseAuthorization();
app.MapHealthChecks("/healthz").RequireAuthorization();
app.MapGet("/", () => "Hello World!");
Föregående exempel visar hur:
- Mellanprogrammet för auktorisering kan användas med routning.
- Slutpunkter kan användas för att konfigurera auktoriseringsbeteende.
Anropet MapHealthChecks lägger till en slutpunkt för hälsokontroll. Länkning RequireAuthorization till det här anropet kopplar en auktoriseringsprincip till slutpunkten.
Anropar UseAuthentication och UseAuthorization lägger till mellanprogrammet för autentisering och auktorisering. Dessa mellanprogram placeras mellan UseRouting och UseEndpoints så att de kan:
- Se vilken slutpunkt som har valts av
UseRouting. - Tillämpa en auktoriseringsprincip innan UseEndpoints skickas till slutpunkten.
Slutpunktsmetadata
I föregående exempel finns det två slutpunkter, men endast slutpunkten för hälsokontroll har en auktoriseringsprincip kopplad. Om begäran matchar slutpunkten /healthzför hälsokontroll utförs en auktoriseringskontroll. Detta visar att slutpunkter kan ha extra data kopplade till sig. Dessa extra data kallas slutpunktsmetadata:
- Metadata kan bearbetas av routningsmedvetna mellanprogram.
- Metadata kan vara av valfri .NET-typ.
Routningsbegrepp
Routningssystemet bygger på pipelinen för mellanprogram genom att lägga till det kraftfulla slutpunktskonceptet . Slutpunkter representerar enheter i appens funktioner som skiljer sig från varandra när det gäller routning, auktorisering och valfritt antal ASP.NET Core-system.
ASP.NET Core-slutpunktsdefinition
En ASP.NET Core-slutpunkt är:
- Körbar: Har en RequestDelegate.
- Utökningsbar: Har en metadatasamling .
- Valbar: Om du vill kan du ha routningsinformation.
- Uppräkningsbar: Samlingen med slutpunkter kan visas genom att EndpointDataSource hämta från DI.
Följande kod visar hur du hämtar och inspekterar slutpunkten som matchar den aktuella begäran:
app.Use(async (context, next) =>
{
var currentEndpoint = context.GetEndpoint();
if (currentEndpoint is null)
{
await next(context);
return;
}
Console.WriteLine($"Endpoint: {currentEndpoint.DisplayName}");
if (currentEndpoint is RouteEndpoint routeEndpoint)
{
Console.WriteLine($" - Route Pattern: {routeEndpoint.RoutePattern}");
}
foreach (var endpointMetadata in currentEndpoint.Metadata)
{
Console.WriteLine($" - Metadata: {endpointMetadata}");
}
await next(context);
});
app.MapGet("/", () => "Inspect Endpoint.");
Slutpunkten, om den är markerad, kan hämtas från HttpContext. Dess egenskaper kan inspekteras. Slutpunktsobjekt är oföränderliga och kan inte ändras när de har skapats. Den vanligaste typen av slutpunkt är en RouteEndpoint.
RouteEndpoint innehåller information som gör att den kan väljas av routningssystemet.
I föregående kod konfigurerar app.Use en inline-mellanprogram.
Följande kod visar att det, beroende på var app.Use som anropas i pipelinen, kanske inte finns någon slutpunkt:
// Location 1: before routing runs, endpoint is always null here.
app.Use(async (context, next) =>
{
Console.WriteLine($"1. Endpoint: {context.GetEndpoint()?.DisplayName ?? "(null)"}");
await next(context);
});
app.UseRouting();
// Location 2: after routing runs, endpoint will be non-null if routing found a match.
app.Use(async (context, next) =>
{
Console.WriteLine($"2. Endpoint: {context.GetEndpoint()?.DisplayName ?? "(null)"}");
await next(context);
});
// Location 3: runs when this endpoint matches
app.MapGet("/", (HttpContext context) =>
{
Console.WriteLine($"3. Endpoint: {context.GetEndpoint()?.DisplayName ?? "(null)"}");
return "Hello World!";
}).WithDisplayName("Hello");
app.UseEndpoints(_ => { });
// Location 4: runs after UseEndpoints - will only run if there was no match.
app.Use(async (context, next) =>
{
Console.WriteLine($"4. Endpoint: {context.GetEndpoint()?.DisplayName ?? "(null)"}");
await next(context);
});
Föregående exempel lägger till Console.WriteLine instruktioner som visar om en slutpunkt har valts eller inte. För tydlighetens skull tilldelar exemplet ett visningsnamn till den angivna / slutpunkten.
Föregående exempel innehåller även anrop till UseRouting och UseEndpoints för att styra exakt när dessa mellanprogram körs i pipelinen.
Kör den här koden med en URL på / visar:
1. Endpoint: (null)
2. Endpoint: Hello
3. Endpoint: Hello
Om du kör den här koden med andra URL:ar visas:
1. Endpoint: (null)
2. Endpoint: (null)
4. Endpoint: (null)
Dessa utdata visar att:
- Slutpunkten är alltid null innan
UseRoutinganropas. - Om en matchning hittas är slutpunkten inte null mellan
UseRoutingoch UseEndpoints. - Mellanprogrammet
UseEndpointsär terminal när en matchning hittas. Terminalmellanprogram definieras senare i den här artikeln. - Mellanprogrammet efter
UseEndpointskörs endast när ingen matchning hittas.
Mellanprogrammet UseRouting använder SetEndpoint metoden för att koppla slutpunkten till den aktuella kontexten. Det går att ersätta UseRouting mellanprogrammet med anpassad logik och ändå få fördelarna med att använda slutpunkter. Ändpunkter är ett grundläggande element på låg nivå som mellanvaror och är inte kopplade till routningens implementering. De flesta appar behöver inte ersättas UseRouting med anpassad logik.
Mellanprogrammet UseEndpoints är utformat för att användas tillsammans med UseRouting mellanprogrammet. Kärnlogiken för att utföra en slutpunkt är inte komplicerad. Använd GetEndpoint för att hämta slutpunkten och anropa sedan dess RequestDelegate egenskap.
Följande kod visar hur mellanprogram kan påverka eller reagera på routning:
app.UseHttpMethodOverride();
app.UseRouting();
app.Use(async (context, next) =>
{
if (context.GetEndpoint()?.Metadata.GetMetadata<RequiresAuditAttribute>() is not null)
{
Console.WriteLine($"ACCESS TO SENSITIVE DATA AT: {DateTime.UtcNow}");
}
await next(context);
});
app.MapGet("/", () => "Audit isn't required.");
app.MapGet("/sensitive", () => "Audit required for sensitive data.")
.WithMetadata(new RequiresAuditAttribute());
public class RequiresAuditAttribute : Attribute { }
Föregående exempel visar två viktiga begrepp:
- Mellanprogram kan köras tidigare
UseRoutingför att ändra de data som routningen körs på.- Vanligtvis ändrar mellanprogram som visas innan routning någon egenskap för begäran, till exempel UseRewriter, UseHttpMethodOverrideeller UsePathBase.
- Mellanprogram kan köras mellan
UseRoutingoch UseEndpoints för att bearbeta resultatet av routingen innan slutpunkten körs.- Mellanprogram som körs mellan
UseRoutingochUseEndpoints:- Inspekterar vanligtvis metadata för att förstå slutpunkterna.
- Fattar ofta säkerhetsbeslut, som görs av
UseAuthorizationochUseCors.
- Kombinationen av mellanprogram och metadata gör det möjligt att konfigurera principer per slutpunkt.
- Mellanprogram som körs mellan
Föregående kod visar ett exempel på ett anpassat mellanprogram som stöder principer per slutpunkt. Mellanprogrammet skriver en revisionslogg av åtkomst av känsliga data till konsolen. Mellanprogrammet kan konfigureras för att granska en slutpunkt med RequiresAuditAttribute metadata. Det här exemplet visar ett opt-in-mönster där endast slutpunkter som är markerade som känsliga granskas. Det är möjligt att definiera den här logiken omvänt och granska allt som inte är markerat som säkert, till exempel. Slutpunktsmetadatasystemet är flexibelt. Den här logiken kan utformas på vilket sätt som helst som passar användningsfallet.
Föregående exempelkod är avsedd att demonstrera de grundläggande begreppen för slutpunkter. Exemplet är inte avsett för produktionsanvändning. En mer fullständig version av ett mellanprogram för granskningsloggar skulle:
- Logga in på en fil eller databas.
- Inkludera information som användaren, IP-adressen, namnet på den känsliga slutpunkten med mera.
Metadata för revisionspolicy RequiresAuditAttribute definieras som en Attribute för att enklare kunna använda klassbaserade ramverk som kontroller och SignalR. När du använder route to code:
- Metadata bifogas med ett builder-API.
- Klassbaserade ramverk innehåller alla attribut på motsvarande metod och klass när du skapar slutpunkter.
Metodtipsen för metadatatyper är att definiera dem antingen som gränssnitt eller attribut. Gränssnitt och attribut tillåter återanvändning av kod. Metadatasystemet är flexibelt och medför inga begränsningar.
Jämför terminalmellanprogram med routning
I följande exempel visas både terminalmellanprogram och routning:
// Approach 1: Terminal Middleware.
app.Use(async (context, next) =>
{
if (context.Request.Path == "/")
{
await context.Response.WriteAsync("Terminal Middleware.");
return;
}
await next(context);
});
app.UseRouting();
// Approach 2: Routing.
app.MapGet("/Routing", () => "Routing.");
Formatet för mellanprogram som visas med Approach 1: är terminalmellanprogram. Det kallas terminalmellanprogram eftersom det utför en matchande åtgärd:
- Matchningsåtgärden i föregående exempel är
Path == "/"för mellanprogrammet ochPath == "/Routing"för routning. - När en matchning lyckas, utför den vissa funktioner och returnerar istället för att anropa
next-mellanprogrammet.
Det kallas terminalmellanprogram eftersom det avslutar sökningen, kör vissa funktioner och sedan returnerar.
I följande lista jämförs terminalmellanprogram med routning:
- Båda metoderna gör det möjligt att avsluta bearbetningspipelinen:
- Mellanprogram avslutar pipelinen genom att returnera i stället för att
nextanropa . - Slutpunkter är alltid terminaler.
- Mellanprogram avslutar pipelinen genom att returnera i stället för att
- Med terminalmellanprogram kan du placera mellanprogrammet på en godtycklig plats i pipelinen:
- Slutpunkter körs på positionen UseEndpoints.
- Med terminalmellanprogram kan godtycklig kod avgöra när mellanprogrammet matchar:
- Anpassad vägmatchningskod kan vara utförlig och svår att skriva korrekt.
- Routning ger enkla lösningar för typiska appar. De flesta appar kräver inte anpassad vägmatchningskod.
- Slutpunktsgränssnitt med mellanprogram som
UseAuthorizationochUseCors.- Användning av ett terminalmellanprogram med
UseAuthorizationellerUseCorskräver manuell koppling med auktoriseringssystemet.
- Användning av ett terminalmellanprogram med
En slutpunkt definierar båda:
- Ett ombud för att bearbeta begäranden.
- En samling godtyckliga metadata. Metadata används för att implementera övergripande problem baserat på principer och konfiguration som är kopplade till varje slutpunkt.
Terminalmellanprogram kan vara ett effektivt verktyg, men kan kräva:
- En betydande mängd kodning och testning.
- Manuell integrering med andra system för att uppnå önskad flexibilitetsnivå.
Överväg att integrera med routning innan du skriver ett terminalmellanprogram.
Befintliga terminalmellanprogram som integreras med Map eller MapWhen kan vanligtvis omvandlas till en routingmedveten slutpunkt. MapHealthChecks visar mönstret för router-ware:
- Skriv en tilläggsmetod på IEndpointRouteBuilder.
- Skapa en pipeline för kapslade mellanprogram med CreateApplicationBuilder.
- Koppla mellanprogrammet till den nya pipelinen. I det här fallet UseHealthChecks.
- Build mellanprogramspipelinen till en RequestDelegate.
- Anropa
Mapoch ange den nya pipelinen för mellanprogram. - Returnera builder-objektet som tillhandahålls av
Mapfrån tilläggsmetoden.
Följande kod visar användning av MapHealthChecks:
app.UseAuthentication();
app.UseAuthorization();
app.MapHealthChecks("/healthz").RequireAuthorization();
Föregående exempel visar varför det är viktigt att returnera builder-objektet. När byggobjektet returneras kan apputvecklaren konfigurera principer som auktorisering för slutpunkten. I det här exemplet har mellanprogrammet för hälsokontroller ingen direkt integrering med auktoriseringssystemet.
Metadatasystemet skapades som svar på de problem som uppstått av utökningsförfattare med hjälp av terminalmellanprogram. Det är problematiskt för varje mellanprogram att implementera sin egen integrering med auktoriseringssystemet.
URL-matchning
- Är den process genom vilken routningen matchar en inkommande begäran till en slutpunkt.
- Baseras på data i URL-sökvägen och rubrikerna.
- Kan utökas för att överväga alla data i begäran.
När ett routningsmellanprogram körs anger det en Endpoint och dirigerar värden till en begäransfunktion på HttpContext från den aktuella begäran:
- Genom att anropa HttpContext.GetEndpoint hämtas slutpunkten.
-
HttpRequest.RouteValueshämtar samlingen av routvärden.
Mellanprogram körs efter att routningsmellanprogram har möjlighet att inspektera slutpunkten och vidta åtgärder. Till exempel kan ett mellanprogramvara för auktorisering granska och utvärdera slutpunktens metadatasamling för en auktoriseringspolicy. När alla mellanprogram i pipelinen för bearbetning av begäranden har körts anropas den valda slutpunktens ombud.
Routningssystemet i slutpunktsroutningen ansvarar för alla leveransbeslut. Eftersom mellanprogrammet tillämpar principer baserat på den valda slutpunkten är det viktigt att:
- Alla beslut som kan påverka sändningen eller tillämpningen av säkerhetsprinciper fattas i routningssystemet.
Warning
För bakåtkompatibilitet, när en Controller eller Razor Pages-slutpunktsdelegat körs, anges egenskaperna till lämpliga värden baserat på den bearbetning som hittills utförts av RouteContext.RouteData-begäran.
Typen RouteContext kommer att markeras som föråldrad i en framtida version:
- Migrera
RouteData.ValuestillHttpRequest.RouteValues. - Migrera
RouteData.DataTokensför att hämta IDataTokensMetadata från slutpunktsmetadata.
URL-matchning fungerar i en konfigurerbar uppsättning faser. I varje fas är utdata en uppsättning matchningar. Mängden matcher kan begränsas ytterligare under nästa fas. Routningsimplementeringen garanterar inte någon bearbetningsordning för matchande slutpunkter. Alla möjliga matchningar bearbetas samtidigt. Url-matchningsfaserna sker i följande ordning. ASP.NET Core:
- Bearbetar URL-sökvägen mot uppsättningen slutpunkter och deras vägmallar och samlar in alla matchningar.
- Tar den föregående listan och tar bort matchningar som inte uppfyller ruttbegränsningar som tillämpas.
- Tar föregående lista och tar bort matchningar som inte uppfyller kraven för MatcherPolicy instanser.
- Använder EndpointSelector för att fatta ett slutgiltigt beslut från föregående lista.
Listan över slutpunkter prioriteras enligt:
- Den RouteEndpoint.Order
- Prioritet för routsmall
Alla matchande ändpunkter bearbetas i varje fas tills den EndpointSelector har nåtts.
EndpointSelector är den sista fasen. Den väljer den högsta prioritetsslutpunkten från matchningarna som den bästa matchningen. Om det finns andra matchningar med samma prioritet som den bästa matchningen, kommer ett tvetydigt matchningsundantag att utlösas.
Routningsprioriteten beräknas baserat på att en mer specifik vägmall får högre prioritet. Tänk till exempel på mallarna /hello och /{message}:
- Båda matchar URL-sökvägen
/hello. -
/helloär mer specifik och därför högre prioritet.
I allmänhet gör routningsprioriteten ett bra jobb med att välja den bästa matchningen för de typer av URL-scheman som används i praktiken. Använd Order endast när det behövs för att undvika tvetydigheter.
På grund av de typer av utökningsbarhet som tillhandahålls av routning är det inte möjligt för routningssystemet att beräkna de tvetydiga vägarna i förväg. Överväg ett exempel som routningsmallarna /{message:alpha} och /{message:int}:
- Villkoret
alphamatchar endast alfabetiska tecken. - Villkoret
intmatchar endast tal. - Dessa mallar har samma vägprioritet, men det finns ingen enskild URL som båda matchar.
- Om routningssystemet rapporterade ett tvetydighetsfel vid starten skulle det blockera det här giltiga användningsfallet.
Warning
Ordningen på åtgärderna i UseEndpoints påverkar inte beteendet för routning, med ett undantag. MapControllerRoute och MapAreaRoute tilldela automatiskt ett ordervärde till sina slutpunkter baserat på den ordning som de anropas. Detta simulerar långvarigt beteende för kontrollanter utan att routningssystemet ger samma garantier som äldre routningsimplementeringar.
Slutpunktsroutning i ASP.NET Core:
- Har inte begreppet rutter.
- Ger inte ordergarantier. Alla slutpunkter bearbetas samtidigt.
Routningsmallens prioritet och slutpunktsmarkeringsordning
Prioritet för routningsmallar är ett system som tilldelar varje vägmall ett värde baserat på hur specifik den är. Prioritet för routningsmall:
- Undviker behovet av att justera ordningen på slutpunkter i vanliga fall.
- Försöker matcha allmänna förväntningar på routingbeteende.
Du kan till exempel överväga mallar /Products/List och /Products/{id}. Det är rimligt att anta att det /Products/List är en bättre matchning än /Products/{id} för URL-sökvägen /Products/List. Detta fungerar eftersom literalsegmentet /List anses ha bättre prioritet än parametersegmentet /{id}.
Information om hur prioritet fungerar är kopplat till hur routningsmallar definieras:
- Mallar med fler segment anses vara mer specifika.
- Ett segment med literaltext anses vara mer specifikt än ett parametersegment.
- Ett parametersegment med en begränsning anses vara mer specifikt än ett utan.
- Ett komplext segment anses vara lika specifikt som ett parametersegment med en begränsning.
- Catch-all-parametrar är de minst specifika. Se catch-all i avsnittet Routningsmallar för viktig information om catch-all-vägar.
Begrepp för URL-generering
URL-generering:
- Är den process genom vilken routning kan skapa en URL-sökväg baserat på en uppsättning vägvärden.
- Tillåter en logisk separation mellan slutpunkter och URL:er som har åtkomst till dem.
Slutpunktsroutning innehåller API:et LinkGenerator .
LinkGenerator är en singleton-tjänst som är tillgänglig från DI. API LinkGenerator kan användas utanför kontexten för en exekverande begäran.
Mvc.IUrlHelper och scenarier som förlitar sig på IUrlHelper, till exempel Tag Helpers, HTML Helpers och Action Results, använder API:et LinkGenerator internt för att tillhandahålla funktioner för länkgenerering.
Länkgeneratorn backas upp av begreppet adress - och adressscheman. Ett adressschema är ett sätt att fastställa de slutpunkter som ska beaktas för länkgenerering. Till exempel implementeras scenarier med routningnamn och routvärden som många användare är bekanta med från kontroller och Razor sidor såsom ett adressschema.
Länkgeneratorn kan länka till styrenheter och Razor sidor via följande tilläggsmetoder:
Överbelastningar av dessa metoder tar emot argument som inkluderar HttpContext. Dessa metoder är funktionellt likvärdiga med Url.Action och Url.Page, men ger ytterligare flexibilitet och alternativ.
Metoderna GetPath* liknar Url.Action mest och Url.Page, eftersom de genererar en URI som innehåller en absolut sökväg. Metoderna GetUri* genererar alltid en absolut URI som innehåller ett schema och en värd. De metoder som accepterar en HttpContext genererar en URI i kontexten för den körande begäran. Värden ambienta för väg, URL-bassökväg, protokoll och värd från den körande begäran används om de inte åsidosätts.
LinkGenerator anropas med en adress. Generera en URI sker i två steg:
- En adress är bunden till en lista över slutpunkter som matchar adressen.
- Varje slutpunkts RoutePattern utvärderas tills ett vägmönster som matchar de angivna värdena hittas. Resultatet kombineras med de andra URI-delarna som levereras till länkgeneratorn och returneras.
Metoderna som tillhandahålls av LinkGenerator stöder standardfunktioner för länkgenerering för alla typer av adresser. Det enklaste sättet att använda länkgeneratorn är genom tilläggsmetoder som utför åtgärder för en viss adresstyp:
| Tilläggsmetod | Description |
|---|---|
| GetPathByAddress | Genererar en URI med en absolut sökväg baserat på de angivna värdena. |
| GetUriByAddress | Genererar en absolut URI baserat på de angivna värdena. |
Warning
Var uppmärksam på följande konsekvenser av att anropa LinkGenerator metoder:
Använd
GetUri*tilläggsmetoder med försiktighet i en appkonfiguration som inte validerar headern för inkommande begäranden.HostOm rubriken för inkommande begäranden inte verifieras kan ej betrodda begärandeindata skickas tillbaka till klienten i URI:er i en vy eller sida. Vi rekommenderar att alla produktionsappar konfigurerar sin server för att kontrolleraHostheadern mot kända giltiga värden.Använd LinkGenerator med försiktighet i mellanprogram i kombination med
MapellerMapWhen.Map*ändrar basvägen för den körande begäran, vilket påverkar utdata från länkgenereringen. LinkGenerator Alla API:er tillåter att du anger en bassökväg. Ange en tom bassökväg för att ta bortMap*effekten på länkgenereringen.
Exempel på mellanprogram
I följande exempel använder ett mellanprogram API:et LinkGenerator för att skapa en länk till en åtgärdsmetod som visar lagerprodukter. Använda länkgeneratorn genom att mata in den i en klass och anrop GenerateLink är tillgängligt för alla klasser i en app:
public class ProductsMiddleware
{
private readonly LinkGenerator _linkGenerator;
public ProductsMiddleware(RequestDelegate next, LinkGenerator linkGenerator) =>
_linkGenerator = linkGenerator;
public async Task InvokeAsync(HttpContext httpContext)
{
httpContext.Response.ContentType = MediaTypeNames.Text.Plain;
var productsPath = _linkGenerator.GetPathByAction("Products", "Store");
await httpContext.Response.WriteAsync(
$"Go to {productsPath} to see our products.");
}
}
Routningsmallar
Token inom {} definierar ruttparametrar som är bundna om rutten matchas. Mer än en vägparameter kan definieras i ett vägsegment, men vägparametrarna måste avgränsas med ett literalvärde. Till exempel:
{controller=Home}{action=Index}
är inte en giltig väg eftersom det inte finns något literalvärde mellan {controller} och {action}. Routningsparametrarna måste ha ett namn och kan ha ytterligare attribut angivna.
Annan literaltext än vägparametrar (till exempel {id}) och sökvägsavgränsaren / måste matcha texten i URL:en. Textmatchning är skiftlägesokänslig och baseras på den avkodade representationen av URL:ens sökväg. Om du vill matcha en literalvägsparameter avgränsare { eller }kan du undvika avgränsare genom att upprepa tecknet. Till exempel {{ eller }}.
Asterisk * eller dubbel asterisk **:
- Kan användas som ett prefix till en vägparameter för att binda till resten av URI:n.
- Kallas för catch-all-parametrar. Till exempel
blog/{**slug}:- Matchar alla URI:er som börjar med
blog/och har ett värde som följer den. - Värdet som följer efter
blog/tilldelas som värde för slug-routen.
- Matchar alla URI:er som börjar med
Warning
En parameter kan matcha vägar felaktigt på grund av en bugg i routning. Appar som påverkas av den här buggen har följande egenskaper:
- En allomfattande rutt, till exempel
{**slug}" - Catch-all-vägen matchar inte begäranden som den ska matcha.
- Om du tar bort andra rutter börjar den allomfattande rutten att fungera.
Se GitHub-buggar 18677 och 16579 till exempel fall som drabbat den här buggen.
En anmälningskorrigering för den här buggen finns i .NET Core 3.1.301 eller senare SDK. Följande kod anger en intern växel som åtgärdar felet:
public static void Main(string[] args)
{
AppContext.SetSwitch("Microsoft.AspNetCore.Routing.UseCorrectCatchAllBehavior",
true);
CreateHostBuilder(args).Build().Run();
}
// Remaining code removed for brevity.
Catch-all-parametrar kan även matcha den tomma strängen.
Parametern catch-all undflyr lämpliga tecken när vägen används för att generera en URL, inklusive sökvägsavgränsningstecken / . Till exempel genererar rutten foo/{*path} med ruttvärden { path = "my/path" }foo/my%2Fpath. Observera det undantagna snedstrecket. Använd routningsparameterprefixet ** för att avgränsa sökvägens avgränsningstecken. Vägen foo/{**path} med { path = "my/path" } genererar foo/my/path.
URL-mönster som försöker avbilda ett filnamn med ett valfritt filnamnstillägg har ytterligare överväganden. Överväg till exempel mallen files/{filename}.{ext?}. När värden för båda filename och ext finns fylls båda värdena i. Om det bara finns ett värde för filename i URL:en matchar vägen eftersom avslutandet . är valfritt. Följande URL:er matchar den här vägen:
/files/myFile.txt/files/myFile
Routningsparametrar kan ha standardvärden som anges genom att ange standardvärdet efter parameternamnet avgränsat med ett likhetstecken (=). Definierar {controller=Home}Home till exempel som standardvärde för controller. Standardvärdet används om inget värde finns i URL:en för parametern. Routningsparametrar görs valfria genom att ett frågetecken (?) läggs till i slutet av parameternamnet. Till exempel id?. Skillnaden mellan valfria värden och standardvägsparametrar är:
- En routningsparameter med ett standardvärde genererar alltid ett värde.
- En valfri parameter har endast ett värde när ett värde tillhandahålls av begärande-URL:en.
Ruttparametrarna kan ha begränsningar som måste matcha ruttvärdet som är bundet från URL:en. Att lägga till : och villkorsnamn efter namnet på routningsparametern anger en infogad begränsning för en routningsparameter. Om villkoret kräver argument omges de av parenteser (...) efter villkorsnamnet. Du kan ange flera inline-begränsningar genom att lägga till en annan : och ett annat begränsningsnamn.
Villkorsnamnet och argumenten IInlineConstraintResolver skickas till tjänsten för att skapa en instans av IRouteConstraint som ska användas i URL-bearbetning. Routningsmallen blog/{article:minlength(10)} anger till exempel en minlength begränsning med argumentet 10. Mer information om routningsbegränsningar och en lista över de begränsningar som tillhandahålls av ramverket finns i avsnittet Routningsbegränsningar .
Routningsparametrar kan också ha parametertransformatorer. Parametertransformatorer transformerar en parameters värde vid generering av länkar och matchande åtgärder och sidor till URL:er. Precis som begränsningar kan parametertransformatorer läggas till direkt i en routparameter genom att lägga till ett : och ett transformeringsnamn efter routparameternamnet. Routningsmallen blog/{article:slugify} anger till exempel en slugify transformerare. Mer information om parametertransformatorer finns i avsnittet Parametertransformatorer .
I följande tabell visas exempel på routningsmallar och deras beteende:
| Routningsmall | Exempel på matchande URI | Förfrågan-URI:n... |
|---|---|---|
hello |
/hello |
Matchar endast den ensamma sökvägen /hello. |
{Page=Home} |
/ |
Matchar och anger Page till Home. |
{Page=Home} |
/Contact |
Matchar och anger Page till Contact. |
{controller}/{action}/{id?} |
/Products/List |
Mappar till kontroller Products och åtgärd List. |
{controller}/{action}/{id?} |
/Products/Details/123 |
Mappar till kontrollanten Products och Details åtgärden medid värdet 123. |
{controller=Home}/{action=Index}/{id?} |
/ |
Mappar till Home-kontrollern och Index-metoden.
id ignoreras. |
{controller=Home}/{action=Index}/{id?} |
/Products |
Mappar till Products-kontrollern och Index-metoden.
id ignoreras. |
Att använda en mall är vanligtvis den enklaste metoden för routning. Begränsningar och standardvärden kan också anges utanför vägmallen.
Komplexa segment
Komplexa segment bearbetas genom matchning av literalavgränsare från höger till vänster på ett icke-girigt sätt. Till exempel [Route("/a{b}c{d}")] är ett komplext segment.
Komplexa segment fungerar på ett visst sätt som måste tolkas för att kunna använda dem. Exemplet i det här avsnittet visar varför komplexa segment bara fungerar bra när avgränsartexten inte visas i parametervärdena. Att använda en regex och sedan extrahera värdena manuellt behövs för mer komplexa fall.
Warning
När du använder System.Text.RegularExpressions för att bearbeta ej betrodda indata skickar du en timeout. En obehörig användare kan ange indata för att RegularExpressions orsaka en Denial-of-Service-attack. ASP.NET Core Frameworks API som använder RegularExpressions har en timeout.
Det här är en sammanfattning av de steg som routningen utför med mallen /a{b}c{d} och URL-sökvägen /abcd.
| Används för att visualisera hur algoritmen fungerar:
- Den första literalen, från höger till vänster, är
c. Så/abcdsöks från höger och hittar/ab|c|d. - Allt till höger (
d) matchas nu med routningsparametern{d}. - Nästa literal, från höger till vänster, är
a. Så/ab|c|dgenomsöks från där vi slutade, sedan hittasa/|a|b|c|d. - Värdet till höger (
b) matchas nu med routningsparametern{b}. - Det finns ingen kvarvarande text och ingen kvarvarande mall för rutt, så det här är en matchning.
Här är ett exempel på ett negativt ärende med samma mall /a{b}c{d} och URL-sökvägen /aabcd.
| Används för att visualisera hur algoritmen fungerar. Det här fallet är inte en matchning, vilket förklaras av samma algoritm:
- Den första literalen, från höger till vänster, är
c. Så/aabcdsöks från höger och hittar/aab|c|d. - Allt till höger (
d) matchas nu med routningsparametern{d}. - Nästa literal, från höger till vänster, är
a. Så/aab|c|dgenomsöks från där vi slutade, sedan hittasa/a|a|b|c|d. - Värdet till höger (
b) matchas nu med routningsparametern{b}. - I det här läget finns det fortfarande text
a, men algoritmen har slut på vägmall för analys, så detta stämmer inte.
Eftersom matchningsalgoritmen inte är girig:
- Den matchar den minsta möjliga mängden text i varje steg.
- Alla fall där avgränsarvärdet visas i parametervärdena resulterar i att det inte matchar.
Reguljära uttryck ger mycket mer kontroll över deras matchande beteende.
Girig matchning, också kallad försiktig matchning, matchar den största möjliga strängen. Icke-giriga matchar den minsta möjliga strängen.
Routning med specialtecken
Routning med specialtecken kan leda till oväntade resultat. Tänk dig till exempel en kontrollant med följande åtgärdsmetod:
[HttpGet("{id?}/name")]
public async Task<ActionResult<string>> GetName(string id)
{
var todoItem = await _context.TodoItems.FindAsync(id);
if (todoItem == null || todoItem.Name == null)
{
return NotFound();
}
return todoItem.Name;
}
När string id innehåller följande kodade värden kan oväntade resultat inträffa:
| ASCII | Encoded |
|---|---|
/ |
%2F |
|
+ |
Routningsparametrar är inte alltid URL-avkodade. Det här problemet kan åtgärdas i framtiden. Mer information finns i det här GitHub-problemet;
Vägbegränsningar
Routningsbegränsningar körs när en matchning har hittats för den inkommande URL:en och URL-sökvägen tokeniseras till ruttvärden. Routningsbegränsningar inspekterar vanligtvis det vägvärde som är associerat via routningsmallen och fattar ett sant eller falskt beslut om huruvida värdet är acceptabelt. Vissa routningsbegränsningar använder data utanför vägvärdet för att överväga om begäran kan dirigeras. Till exempel HttpMethodRouteConstraint kan acceptera eller avvisa en begäran baserat på dess HTTP-verb. Begränsningar används i routningsbegäranden och länkgenerering.
Warning
Använd inte begränsningar för indataverifiering. Om begränsningar används för indataverifiering resulterar ogiltiga indata i ett 404 svar som inte hittades. Ogiltiga indata bör generera en 400 felaktig begäran med ett lämpligt felmeddelande. Routningsbegränsningar används för att särskilja liknande rutter, inte för att verifiera inmatningar för en viss rutt.
I följande tabell visas exempel på vägbegränsningar och deras förväntade beteende:
| constraint | Example | Exempelmatchningar | Notes |
|---|---|---|---|
int |
{id:int} |
123456789, -123456789 |
Matchar alla heltal |
bool |
{active:bool} |
true, FALSE |
Matchar true eller false. Case-insensitive |
datetime |
{dob:datetime} |
2016-12-31, 2016-12-31 7:32pm |
Matchar ett giltigt DateTime värde i den invarianta kulturen. Se föregående varning. |
decimal |
{price:decimal} |
49.99, -1,000.01 |
Matchar ett giltigt decimal värde i den invarianta kulturen. Se föregående varning. |
double |
{weight:double} |
1.234, -1,001.01e8 |
Matchar ett giltigt double värde i den invarianta kulturen. Se föregående varning. |
float |
{weight:float} |
1.234, -1,001.01e8 |
Matchar ett giltigt float värde i den invarianta kulturen. Se föregående varning. |
guid |
{id:guid} |
CD2C1638-1638-72D5-1638-DEADBEEF1638 |
Matchar ett giltigt Guid värde |
long |
{ticks:long} |
123456789, -123456789 |
Matchar ett giltigt long värde |
minlength(value) |
{username:minlength(4)} |
Rick |
Strängen måste innehålla minst 4 tecken |
maxlength(value) |
{filename:maxlength(8)} |
MyFile |
Strängen får inte innehålla fler än 8 tecken |
length(length) |
{filename:length(12)} |
somefile.txt |
Strängen måste vara exakt 12 tecken lång |
length(min,max) |
{filename:length(8,16)} |
somefile.txt |
Strängen får vara minst 8 och högst 16 tecken lång |
min(value) |
{age:min(18)} |
19 |
Heltalsvärdet måste vara minst 18 |
max(value) |
{age:max(120)} |
91 |
Heltalsvärdet får inte vara mer än 120 |
range(min,max) |
{age:range(18,120)} |
91 |
Heltalsvärdet måste vara minst 18 men högst 120 |
alpha |
{name:alpha} |
Rick |
Strängen måste bestå av ett eller flera alfabetiska tecken, och vara skiftlägesokänslig, a-z. |
regex(expression) |
{ssn:regex(^\\d{{3}}-\\d{{2}}-\\d{{4}}$)} |
123-45-6789 |
Strängen måste matcha det reguljära uttrycket. Se tips om hur du definierar ett reguljärt uttryck. |
required |
{name:required} |
Rick |
Används för att framtvinga att ett icke-parametervärde finns under URL-generering |
Warning
När du använder System.Text.RegularExpressions för att bearbeta ej betrodda indata skickar du en timeout. En obehörig användare kan ange indata för att RegularExpressions orsaka en Denial-of-Service-attack. ASP.NET Core Frameworks API som använder RegularExpressions har en timeout.
Flera, kolonavgränsade begränsningar kan tillämpas på en enskild parameter. Följande villkor begränsar till exempel en parameter till ett heltalsvärde på 1 eller högre:
[Route("users/{id:int:min(1)}")]
public User GetUserById(int id) { }
Warning
Routningsbegränsningar som verifierar URL:en och konverteras till en CLR-typ använder alltid den invarianta kulturen. Till exempel konvertering till CLR-typen int eller DateTime. Dessa begränsningar förutsätter att URL:en inte kan lokaliseras. De ramverksbaserade vägbegränsningarna ändrar inte de värden som lagras i vägvärden. Alla vägvärden som parsas från URL:en lagras som strängar. Villkoret float försöker till exempel konvertera vägvärdet till en flyttal, men det konverterade värdet används bara för att verifiera att det kan konverteras till en flyttal.
Reguljära uttryck i begränsningar
Warning
När du använder System.Text.RegularExpressions för att bearbeta ej betrodda indata skickar du en timeout. En obehörig användare kan ange indata för att RegularExpressions orsaka en Denial-of-Service-attack. ASP.NET Core Frameworks API som använder RegularExpressions har en timeout.
Reguljära uttryck kan anges som infogade begränsningar med hjälp av routningsbegränsningen regex(...) . Metoder i MapControllerRoute familjen accepterar också en objektliteral av begränsningar. Om formuläret används tolkas strängvärden som reguljära uttryck.
Följande kod använder en infogad regex-begränsning:
app.MapGet("{message:regex(^\\d{{3}}-\\d{{2}}-\\d{{4}}$)}",
() => "Inline Regex Constraint Matched");
Följande kod använder en objektliteral för att ange en regex-begränsning:
app.MapControllerRoute(
name: "people",
pattern: "people/{ssn}",
constraints: new { ssn = "^\\d{3}-\\d{2}-\\d{4}$", },
defaults: new { controller = "People", action = "List" });
Ramverket ASP.NET Core lägger RegexOptions.IgnoreCase | RegexOptions.Compiled | RegexOptions.CultureInvariant till konstruktorn för reguljära uttryck. Se RegexOptions en beskrivning av dessa medlemmar.
Reguljära uttryck använder avgränsare och token som liknar dem som används vid routning och C#-språket. Token för reguljära uttryck måste vara undantagna. Om du vill använda reguljära uttryck ^\d{3}-\d{2}-\d{4}$ i en infogad begränsning använder du något av följande:
- Ersätt
\tecken som anges i strängen som\\tecken i C#-källfilen för att undvika strängens\escape-tecken. - Verbatim strängliteraler.
Om du vill undvika dirigeringsparametertecken {, }, [, ], dubblar du tecknen i uttrycket, {{till exempel , }}, [[, . ]] I följande tabell visas ett reguljärt uttryck och dess undantagna version:
| Reguljärt uttryck | Undantagna reguljära uttryck |
|---|---|
^\d{3}-\d{2}-\d{4}$ |
^\\d{{3}}-\\d{{2}}-\\d{{4}}$ |
^[a-z]{2}$ |
^[[a-z]]{{2}}$ |
Reguljära uttryck som används i routning börjar ofta med ^ tecknet och matchar strängens startposition. Uttrycken slutar ofta med $ tecknet och matchar slutet av strängen. Tecknen ^ och $ ser till att det reguljära uttrycket matchar värdet för hela routningsparametern. Utan ^- och $-tecknen matchar det reguljära uttrycket vilken delsträng som helst i strängen, vilket ofta är oönskat. Följande tabell innehåller exempel och förklarar varför de matchar eller inte matchar:
| Expression | String | Match | Comment |
|---|---|---|---|
[a-z]{2} |
hello | Yes | Matchningar för delsträngar |
[a-z]{2} |
123abc456 | Yes | Matchningar för delsträngar |
[a-z]{2} |
mz | Yes | Matchar uttryck |
[a-z]{2} |
MZ | Yes | Inte skiftlägeskänslig |
^[a-z]{2}$ |
hello | No | Se ^ och $ ovan |
^[a-z]{2}$ |
123abc456 | No | Se ^ och $ ovan |
Mer information om syntax för reguljära uttryck finns i Reguljära .NET Framework-uttryck.
Om du vill begränsa en parameter till en känd uppsättning möjliga värden använder du ett reguljärt uttryck. Till exempel {action:regex(^(list|get|create)$)} matchar endast routningsvärdet action till list, geteller create. Om den skickas in i begränsningsordboken, så är strängen ^(list|get|create)$ likvärdig. Begränsningar som skickas i villkorsordlistan som inte matchar någon av de kända begränsningarna behandlas också som reguljära uttryck. Begränsningar som skickas i en mall som inte matchar någon av de kända begränsningarna behandlas inte som reguljära uttryck.
Begränsningar för anpassad rutt
Anpassade routningsbegränsningar kan skapas genom att implementera IRouteConstraint gränssnittet. Gränssnittet IRouteConstraint innehåller Match, som returnerar true om villkoret är uppfyllt och false på annat sätt.
Anpassade routningsbegränsningar behövs sällan. Innan du implementerar en anpassad vägbegränsning bör du överväga alternativ, till exempel modellbindning.
Mappen ASP.NET Core Constraints innehåller bra exempel på hur du skapar begränsningar. Till exempel GuidRouteConstraint.
Om du vill använda en anpassad IRouteConstraintmåste routningsbegränsningstypen registreras med appens ConstraintMap i tjänstcontainern. A ConstraintMap är en ordlista som mappar routningsbegränsningsnycklar till IRouteConstraint implementeringar som validerar dessa begränsningar. En app"s ConstraintMap kan uppdateras i Program.cs antingen som en del av ett AddRouting-anrop eller genom att konfigurera RouteOptions direkt med builder.Services.Configure<RouteOptions>. Till exempel:
builder.Services.AddRouting(options =>
options.ConstraintMap.Add("noZeroes", typeof(NoZeroesRouteConstraint)));
Föregående villkor tillämpas i följande kod:
[ApiController]
[Route("api/[controller]")]
public class NoZeroesController : ControllerBase
{
[HttpGet("{id:noZeroes}")]
public IActionResult Get(string id) =>
Content(id);
}
Implementeringen av NoZeroesRouteConstraint förhindrar 0 att den används i en vägparameter:
public class NoZeroesRouteConstraint : IRouteConstraint
{
private static readonly Regex _regex = new(
@"^[1-9]*$",
RegexOptions.CultureInvariant | RegexOptions.IgnoreCase,
TimeSpan.FromMilliseconds(100));
public bool Match(
HttpContext? httpContext, IRouter? route, string routeKey,
RouteValueDictionary values, RouteDirection routeDirection)
{
if (!values.TryGetValue(routeKey, out var routeValue))
{
return false;
}
var routeValueString = Convert.ToString(routeValue, CultureInfo.InvariantCulture);
if (routeValueString is null)
{
return false;
}
return _regex.IsMatch(routeValueString);
}
}
Warning
När du använder System.Text.RegularExpressions för att bearbeta ej betrodda indata skickar du en timeout. En obehörig användare kan ange indata för att RegularExpressions orsaka en Denial-of-Service-attack. ASP.NET Core Frameworks API som använder RegularExpressions har en timeout.
Föregående kod:
- Förhindrar
0i{id}segmentet av rutten. - Visas som ett grundläggande exempel på hur du implementerar en anpassad begränsning. Den bör inte användas i en produktionsapp.
Följande kod är en bättre metod för att förhindra att en id innehållande en 0 bearbetas:
[HttpGet("{id}")]
public IActionResult Get(string id)
{
if (id.Contains('0'))
{
return StatusCode(StatusCodes.Status406NotAcceptable);
}
return Content(id);
}
Föregående kod har följande fördelar jämfört med NoZeroesRouteConstraint metoden:
- Det kräver ingen anpassad begränsning.
- Det returnerar ett mer beskrivande fel när vägparametern innehåller
0.
Parametertransformatorer
Parametertransformatorer:
- Utför vid generering av en länk med LinkGenerator.
- Implementera Microsoft.AspNetCore.Routing.IOutboundParameterTransformer.
- Konfigureras med ConstraintMap.
- Ta parameterns vägvärde och omvandla det till ett nytt strängvärde.
- Resulterar i att du använder det transformerade värdet i den genererade länken.
Till exempel, en anpassad slugify-parametertransformator i vägmönster blog\{article:slugify} med Url.Action(new { article = "MyTestArticle" }) genererar blog\my-test-article.
Överväg följande IOutboundParameterTransformer implementering:
public class SlugifyParameterTransformer : IOutboundParameterTransformer
{
public string? TransformOutbound(object? value)
{
if (value is null)
{
return null;
}
return Regex.Replace(
value.ToString()!,
"([a-z])([A-Z])",
"$1-$2",
RegexOptions.CultureInvariant,
TimeSpan.FromMilliseconds(100))
.ToLowerInvariant();
}
}
Om du vill använda en parametertransformator i ett vägmönster konfigurerar du den med hjälp av ConstraintMap i Program.cs:
builder.Services.AddRouting(options =>
options.ConstraintMap["slugify"] = typeof(SlugifyParameterTransformer));
ASP.NET Core-ramverket använder parametertransformatorer för att transformera den URI där en slutpunkt löser problemet. Till exempel transformerar parametertransformatorer de vägvärden som används för att matcha en area, controller, actionoch page:
app.MapControllerRoute(
name: "default",
pattern: "{controller:slugify=Home}/{action:slugify=Index}/{id?}");
Med föregående vägmall matchas åtgärden SubscriptionManagementController.GetAll med URI /subscription-management/get-all:n . En parametertransformator ändrar inte de vägvärden som används för att generera en länk. Till exempel Url.Action("GetAll", "SubscriptionManagement") ger /subscription-management/get-all.
ASP.NET Core tillhandahåller API-konventioner för användning av parametertransformatorer med genererade vägar:
- Microsoft.AspNetCore.Mvc.ApplicationModels.RouteTokenTransformerConvention MVC-konventionen tillämpar en angiven parametertransformator på alla attributvägar i appen. Parametertransformatorn transformerar attributvägstokens eftersom de ersätts. Mer information finns i Använda en parametertransformator för att anpassa tokenbyte.
- Razor Pages använder API-konventionen PageRouteTransformerConvention . Den här konventionen tillämpar en angiven parametertransformator på alla automatiskt identifierade Razor sidor. Parametertransformatoren transformerar mapp- och filnamnssegmenten Razor för Sidvägar. Mer information finns i Använda en parametertransformator för att anpassa sidvägar.
Referens för URL-generering
Det här avsnittet innehåller en referens för algoritmen som implementeras av URL-generering. I praktiken använder de flesta komplexa exempel på URL-generering styrenheter eller Razor sidor. Mer information finns i routning i kontrollanter .
URL-genereringsprocessen börjar med ett anrop till LinkGenerator.GetPathByAddress eller en liknande metod. Metoden tillhandahålls med en adress, en uppsättning vägvärden och eventuellt information om den aktuella begäran från HttpContext.
Det första steget är att använda adressen för att lösa en uppsättning kandidatslutpunkter med hjälp av en IEndpointAddressScheme<TAddress> som matchar adressens typ.
När uppsättningen kandidater hittas av adressschemat sorteras slutpunkterna och bearbetas iterativt tills en URL-genereringsåtgärd lyckas. URL-genereringen söker inte efter tvetydigheter. Det första resultatet som returneras är slutresultatet.
Felsöka URL-generering med loggning
Det första steget i felsökning av URL-generering för Microsoft.AspNetCore.Routing är att ställa in loggningsnivån till TRACE.
LinkGenerator loggar många detaljer om bearbetningen som kan vara användbar för att felsöka problem.
Mer information om URL-generering finns i REFERENS för URL-generering .
Addresses
Adresser är det begrepp i URL-generering som används för att binda ett anrop till länkgeneratorn till en uppsättning kandidatslutpunkter.
Adresser är ett utökningsbart begrepp som levereras med två implementeringar som standard:
- Använda slutpunktsnamnet (
string) som adress:- Tillhandahåller liknande funktioner som MVC:s routningsnamn.
- IEndpointNameMetadata Använder metadatatypen.
- Löser den angivna strängen mot metadata för alla registrerade slutpunkter.
- Utlöser ett undantag vid start om flera slutpunkter använder samma namn.
- Rekommenderas för generell användning utanför kontrollanter och Razor sidor.
- Använda vägvärden (RouteValuesAddress) som adress:
- Ger liknande funktioner som kontroller och äldre URL-generering för sidor.
- Mycket komplext att utöka och felsöka.
- Tillhandahåller implementeringen som används av
IUrlHelper, Tag Helpers, HTML-hjälpare, åtgärdsresultat osv.
Adressschemats roll är att göra associationen mellan adressen och matchande slutpunkter enligt godtyckliga kriterier:
- Slutpunktsnamnschemat utför en grundläggande ordlistesökning.
- Routningsvärdena har en komplex bästa delmängd av set-algoritmen.
Omgivande värden och explicita värden
Från den aktuella begäran får routning åtkomst till routningsvärdena för den aktuella begäran HttpContext.Request.RouteValues. De värden som är associerade med den aktuella begäran kallas för omgivande värden. För tydlighetens skull refererar dokumentationen till de vägvärden som skickas in till metoder som explicita värden.
I följande exempel visas omgivande värden och explicita värden. Den innehåller omgivande värden från den aktuella begäran och explicita värden:
public class WidgetController : ControllerBase
{
private readonly LinkGenerator _linkGenerator;
public WidgetController(LinkGenerator linkGenerator) =>
_linkGenerator = linkGenerator;
public IActionResult Index()
{
var indexPath = _linkGenerator.GetPathByAction(
HttpContext, values: new { id = 17 })!;
return Content(indexPath);
}
// ...
Föregående kod:
- Returnerar
/Widget/Index/17 - Hämtar LinkGenerator via DI.
Följande kod innehåller endast explicita värden och inga omgivande värden:
var subscribePath = _linkGenerator.GetPathByAction(
"Subscribe", "Home", new { id = 17 })!;
Föregående metod returnerar /Home/Subscribe/17
Följande kod i WidgetController returnerar /Widget/Subscribe/17:
var subscribePath = _linkGenerator.GetPathByAction(
HttpContext, "Subscribe", null, new { id = 17 });
Följande kod tillhandahåller kontrollern från omgivande och explicita värden i den aktuella begäran.
public class GadgetController : ControllerBase
{
public IActionResult Index() =>
Content(Url.Action("Edit", new { id = 17 })!);
}
I koden ovan:
-
/Gadget/Edit/17returneras. - Url hämtar IUrlHelper.
-
Action genererar en URL med en absolut sökväg för en åtgärdsmetod. URL:en innehåller det angivna
actionnamnet ochroutevärdena.
Följande kod innehåller omgivande värden från den aktuella begäran och explicita värden:
public class IndexModel : PageModel
{
public void OnGet()
{
var editUrl = Url.Page("./Edit", new { id = 17 });
// ...
}
}
Den föregående koden sätter url till /Edit/17 när Redigera Razor Sida innehåller följande siddirektiv:
@page "{id:int}"
Om sidan Redigera inte innehåller "{id:int}"-routemallen, är url/Edit?id=17.
Beteendet för MVC lägger IUrlHelper till ett lager av komplexitet utöver de regler som beskrivs här:
-
IUrlHelpertillhandahåller alltid vägvärdena från den aktuella begäran som omgivande värden. -
IUrlHelper.Action kopierar alltid aktuella
actionvärden ochcontrollervägvärden som explicita värden om de inte åsidosätts av utvecklaren. -
IUrlHelper.Page kopierar alltid det aktuella
pagevägvärdet som ett explicit värde om det inte åsidosätts. -
IUrlHelper.Pageåsidosätter alltid det aktuellahandlerruttvärdet mednullsom ett explicit värde såvida det inte åsidosätts.
Användarna blir ofta förvånade över beteendeinformationen för omgivande värden, eftersom MVC inte verkar följa sina egna regler. Av historiska och kompatibilitetsskäl har vissa routningsvärden som action, controller, pageoch handler ett eget specialfallsbeteende.
Motsvarande funktionalitet som tillhandahålls av LinkGenerator.GetPathByAction och LinkGenerator.GetPathByPage duplicerar dessa avvikelser i IUrlHelper för kompatibilitet.
Process för URL-generering
När uppsättningen kandidatslutpunkter hittas, algoritmen för URL-generering:
- Bearbetar slutpunkterna iterativt.
- Returnerar det första lyckade resultatet.
Det första steget i den här processen kallas ogiltigförklarande av routningsvärden. Ogiltigförklaring av routningsvärden är den process genom vilken routning avgör vilka routningsvärden från bakgrundsvärden som ska användas och vilka som ska ignoreras. Varje omgivande värde beaktas och kombineras antingen med explicita värden eller ignoreras.
Det bästa sättet att förstå rollen av omgivande värden är att de försöker spara skrivande för programutvecklare i vissa vanliga situationer. Traditionellt är scenarier där omgivande värden är användbara relaterade till MVC:
- När du länkar till en annan åtgärd i samma kontrollant behöver inte kontrollantnamnet anges.
- När du länkar till en annan kontrollant i samma område behöver du inte ange områdesnamnet.
- När du länkar till samma åtgärdsmetod behöver du inte ange vägvärden.
- När du länkar till en annan del av appen vill du inte överföra routningsvärden som inte har någon betydelse i den delen av appen.
Anrop till LinkGenerator eller IUrlHelper som returnerar null orsakas vanligtvis av bristande förståelse av ogiltigförklaring av routningsvärden. Felsöka routningsvärdets ogiltighet genom att uttryckligen ange fler av vägvärdena för att se om det löser problemet.
Ogiltigförklaring av routvärden bygger på antagandet att appens URL-schema är hierarkiskt, med en hierarki som bildas från vänster till höger. Överväg den grundläggande mallen för styrenhetsroutning {controller}/{action}/{id?} för att få en intuitiv uppfattning om hur detta fungerar i praktiken. En ändring av ett värde ogiltigförklarar alla vägvärden som visas till höger. Detta återspeglar antagandet om hierarki. Om appen har ett omgivande värde för id, och åtgärden anger ett annat värde för controller:
-
idåteranvänds inte eftersom{controller}är till vänster om{id?}.
Några exempel som visar den här principen:
- Om de explicita värdena innehåller ett värde för
idignoreras det omgivande värdet förid. Omgivande värden förcontrollerochactionkan användas. - Om de explicita värdena innehåller ett värde för
actionignoreras alla omgivande värden föraction. Omgivningsvärdena förcontrollerkan användas. Om det explicita värdet föractionskiljer sig från det omgivande värdet föractionidanvänds inte värdet. Om det tydliga värdet föractionär detsamma som det omgivande värdet föraction, kanidvärdet användas. - Om de explicita värdena innehåller ett värde för
controllerignoreras alla omgivande värden förcontroller. Om det explicita värdet förcontrollerskiljer sig från det omgivande värdet förcontrolleractionanvänds inte värdena ochid. Om det explicita värdet förcontrollerär detsamma som det omgivande värdet förcontrolleractionkan värdena ochidanvändas.
Den här processen kompliceras ytterligare av förekomsten av attributvägar och dedikerade konventionella vägar. Styrenheters konventionella vägar som {controller}/{action}/{id?} specificerar en hierarki med hjälp av ruttparametrar. För dedikerade konventionella vägar och attributvägar till styrningar och Razor sidor:
- Det finns en hierarki med vägvärden.
- De visas inte i mallen.
I dessa fall definierar URL-generering det nödvändiga värdekonceptet . Slutpunkter som skapats av kontrollanter och Razor sidor har angivna värden som gör att vägvärdets ogiltighet kan fungera.
Ruttvärdets ogiltighetsalgoritm förklarad:
- De nödvändiga värdenamnen kombineras med vägparametrarna och bearbetas sedan från vänster till höger.
- För varje parameter jämförs det omgivande värdet och det explicita värdet:
- Om det omgivande värdet och det explicita värdet är samma fortsätter processen.
- Om det omgivande värdet finns och det explicita värdet inte är det används det omgivande värdet när URL:en genereras.
- Om det omgivande värdet inte finns och det explicita värdet är avvisar du det omgivande värdet och alla efterföljande omgivande värden.
- Om det omgivande värdet och det explicita värdet finns, och de två värdena är olika, avvisar du det omgivande värdet och alla efterföljande omgivande värden.
I det här läget är URL-genereringsåtgärden redo att utvärdera routningsbegränsningar. Uppsättningen godkända värden kombineras med parameterns standardvärden, vilka tillhandahålls för begränsningar. Om alla begränsningar uppfylls fortsätter operationen.
Därefter kan de godkända värdena användas för att expandera routningsmallen. Vägmallen bearbetas:
- Från vänster till höger.
- Varje parameter har sitt godkända värde ersatt.
- Med följande specialfall:
- Om de godkända värdena saknar ett värde och parametern har ett standardvärde används standardvärdet.
- Om de godkända värdena saknar ett värde och parametern är valfri fortsätter bearbetningen.
- Om en routningsparameter till höger om en valfri parameter som saknas har ett värde misslyckas åtgärden.
- Sammanhängande standardvärdeparametrar och valfria parametrar komprimeras där det är möjligt.
Värden som uttryckligen anges som inte matchar ett segment av vägen läggs till i frågesträngen. Följande tabell visar resultatet när du använder routningsmallen {controller}/{action}/{id?}.
| Omgivande värden | Explicita värden | Result |
|---|---|---|
| controller = "Home" | action = "Om" | /Home/About |
| controller = "Home" | controller = "Beställning", action = "Om" | /Order/About |
| controller = "Home", color = "Röd" | action = "Om" | /Home/About |
| controller = "Home" | action = "Om", color = "Röd" | /Home/About?color=Red |
Valfri vägparameterordning
Valfria vägparametrar måste komma efter alla obligatoriska vägparametrar. I följande kod måste parametrarna id och name komma efter parametern color :
using Microsoft.AspNetCore.Mvc;
namespace WebApplication1.Controllers;
[Route("api/[controller]")]
public class MyController : ControllerBase
{
// GET /api/my/red/2/joe
// GET /api/my/red/2
// GET /api/my
[HttpGet("{color}/{id:int?}/{name?}")]
public IActionResult GetByIdAndOptionalName(string color, int id = 1, string? name = null)
{
return Ok($"{color} {id} {name ?? ""}");
}
}
Problem med att routningsvärdet är ogiltigt
Följande kod visar ett exempel på ett URL-genereringsschema som inte stöds av routning:
app.MapControllerRoute(
"default",
"{culture}/{controller=Home}/{action=Index}/{id?}");
app.MapControllerRoute(
"blog",
"{culture}/{**slug}",
new { controller = "Blog", action = "ReadPost" });
I föregående kod culture används routningsparametern för lokalisering. Önskan är att parametern culture alltid ska accepteras som ett omgivande värde. Parametern culture accepteras dock inte som ett omgivande värde på grund av hur nödvändiga värden fungerar:
- I routningsmallen
"default"är routningsparameternculturetill vänster omcontroller, så ändringar i kommer inte attcontrollerogiltigförklaraculture. -
"blog"I vägmallencultureanses vägparametern vara till höger omcontroller, som visas i de obligatoriska värdena.
Parsa URL-sökvägar med LinkParser
Klassen LinkParser lägger till stöd för att parsa en URL-sökväg till en uppsättning vägvärden. Metoden ParsePathByEndpointName tar ett slutpunktsnamn och en URL-sökväg och returnerar en uppsättning vägvärden som extraherats från URL-sökvägen.
I följande exempelkontrollant använder åtgärden GetProduct en routningsmall med api/Products/{id} och har en Name av GetProduct:
[ApiController]
[Route("api/[controller]")]
public class ProductsController : ControllerBase
{
[HttpGet("{id}", Name = nameof(GetProduct))]
public IActionResult GetProduct(string id)
{
// ...
I samma kontrollantklass AddRelatedProduct förväntar sig åtgärden en URL-sökväg, , pathToRelatedProductsom kan anges som en frågesträngsparameter:
[HttpPost("{id}/Related")]
public IActionResult AddRelatedProduct(
string id, string pathToRelatedProduct, [FromServices] LinkParser linkParser)
{
var routeValues = linkParser.ParsePathByEndpointName(
nameof(GetProduct), pathToRelatedProduct);
var relatedProductId = routeValues?["id"];
// ...
I föregående exempel extraherar AddRelatedProduct åtgärden id ruttvärdet från URL-sökvägen. Till exempel, med en URL-sökväg på /api/Products/1, är värdet på relatedProductId inställt till 1. Med den här metoden kan API:ets klienter använda URL-sökvägar när de refererar till resurser, utan att behöva veta hur en sådan URL är strukturerad.
Konfigurera slutpunktsmetadata
Följande länkar innehåller information om hur du konfigurerar slutpunktsmetadata:
- Aktivera Cors med slutpunktsroutning
-
Exempel på IAuthorizationPolicyProvider med ett anpassat
[MinimumAgeAuthorize]attribut - Testa autentisering med attributet [Auktorisera]
- RequireAuthorization
- Välja schemat med attributet [Auktorisera]
- Tillämpa principer med attributet [Auktorisera]
- Rollbaserad auktorisering i ASP.NET Core
Värdmatchning i rutter med RequireHost
RequireHost tillämpar en begränsning på den rutt som kräver den angivna värden. Parametern RequireHost eller [Värd] kan vara en:
- Värd:
www.domain.com, matcharwww.domain.commed valfri port. - Värd med jokertecken:
*.domain.com, matcharwww.domain.com,subdomain.domain.com, ellerwww.subdomain.domain.compå valfri port. - Port:
*:5000, matchar port 5000 med valfri värd. - Värd och port:
www.domain.com:5000eller*.domain.com:5000, matchar värd och port.
Flera parametrar kan anges med RequireHost eller [Host]. Villkoret matchar värdar som är giltiga för någon av parametrarna. Matchar till exempel [Host("domain.com", "*.domain.com")], domain.com, www.domain.com, och subdomain.domain.com.
Följande kod använder RequireHost för att kräva den angivna värden på rutten:
app.MapGet("/", () => "Contoso").RequireHost("contoso.com");
app.MapGet("/", () => "AdventureWorks").RequireHost("adventure-works.com");
app.MapHealthChecks("/healthz").RequireHost("*:8080");
Följande kod använder [Host] attributet på kontrollanten för att kräva någon av de angivna värdarna:
[Host("contoso.com", "adventure-works.com")]
public class HostsController : Controller
{
public IActionResult Index() =>
View();
[Host("example.com")]
public IActionResult Example() =>
View();
}
[Host] När attributet tillämpas på både kontrollanten och åtgärdsmetoden:
- Attributet för åtgärden används.
- Kontrollantattributet ignoreras.
Routningsgrupper
Tilläggsmetoden MapGroup hjälper till att organisera grupper av slutpunkter med ett gemensamt prefix. Det minskar repetitiv kod och gör det möjligt att anpassa hela grupper av slutpunkter med ett enda anrop till metoder som RequireAuthorization och WithMetadata som lägger till slutpunktsmetadata.
Följande kod skapar till exempel två liknande grupper av slutpunkter:
app.MapGroup("/public/todos")
.MapTodosApi()
.WithTags("Public");
app.MapGroup("/private/todos")
.MapTodosApi()
.WithTags("Private")
.AddEndpointFilterFactory(QueryPrivateTodos)
.RequireAuthorization();
EndpointFilterDelegate QueryPrivateTodos(EndpointFilterFactoryContext factoryContext, EndpointFilterDelegate next)
{
var dbContextIndex = -1;
foreach (var argument in factoryContext.MethodInfo.GetParameters())
{
if (argument.ParameterType == typeof(TodoDb))
{
dbContextIndex = argument.Position;
break;
}
}
// Skip filter if the method doesn't have a TodoDb parameter.
if (dbContextIndex < 0)
{
return next;
}
return async invocationContext =>
{
var dbContext = invocationContext.GetArgument<TodoDb>(dbContextIndex);
dbContext.IsPrivate = true;
try
{
return await next(invocationContext);
}
finally
{
// This should only be relevant if you're pooling or otherwise reusing the DbContext instance.
dbContext.IsPrivate = false;
}
};
}
public static RouteGroupBuilder MapTodosApi(this RouteGroupBuilder group)
{
group.MapGet("/", GetAllTodos);
group.MapGet("/{id}", GetTodo);
group.MapPost("/", CreateTodo);
group.MapPut("/{id}", UpdateTodo);
group.MapDelete("/{id}", DeleteTodo);
return group;
}
I det här scenariot kan du använda en relativ adress för Location-rubriken i 201 Created-resultatet.
public static async Task<Created<Todo>> CreateTodo(Todo todo, TodoDb database)
{
await database.AddAsync(todo);
await database.SaveChangesAsync();
return TypedResults.Created($"{todo.Id}", todo);
}
Den första gruppen med slutpunkter matchar endast begäranden som är prefix med /public/todos och är tillgängliga utan autentisering. Den andra gruppen med slutpunkter matchar endast begäranden som är prefix med /private/todos och kräver autentisering.
QueryPrivateTodos
slutpunktfilterfabriken är en lokal funktion som ändrar rout-hanterarens TodoDb parametrar för att tillåta åtkomst till och lagring av privata data.
Routningsgrupper stöder också kapslade grupper och komplexa prefixmönster med vägparametrar och begränsningar. I följande exempel kan routhanteraren som mappas till gruppen user fånga de {org}- och {group}-routningsparametrar som definierats i de yttre gruppens prefix.
Prefixet kan också vara tomt. Detta kan vara användbart för att lägga till slutpunktsmetadata eller filter till en grupp slutpunkter utan att ändra vägmönstret.
var all = app.MapGroup("").WithOpenApi();
var org = all.MapGroup("{org}");
var user = org.MapGroup("{user}");
user.MapGet("", (string org, string user) => $"{org}/{user}");
Att lägga till filter eller metadata i en grupp fungerar på samma sätt som att lägga till dem individuellt i varje slutpunkt innan du lägger till extra filter eller metadata som kan ha lagts till i en inre grupp eller en specifik slutpunkt.
var outer = app.MapGroup("/outer");
var inner = outer.MapGroup("/inner");
inner.AddEndpointFilter((context, next) =>
{
app.Logger.LogInformation("/inner group filter");
return next(context);
});
outer.AddEndpointFilter((context, next) =>
{
app.Logger.LogInformation("/outer group filter");
return next(context);
});
inner.MapGet("/", () => "Hi!").AddEndpointFilter((context, next) =>
{
app.Logger.LogInformation("MapGet filter");
return next(context);
});
I exemplet ovan loggar det yttre filtret den inkommande begäran före det inre filtret trots att det lades till tvåa. Eftersom filtren tillämpades på olika grupper spelar det ingen roll vilken ordning de lades till i förhållande till varandra. Orderfiltren som läggs till spelar roll om de tillämpas på samma grupp eller specifika slutpunkt.
En begäran om att /outer/inner/ loggar följande:
/outer group filter
/inner group filter
MapGet filter
Prestandavägledning för routning
När en app har prestandaproblem misstänks routning ofta vara problemet. Anledningen till att routning misstänks är att ramverk som kontrollers och Razor Pages rapporterar hur lång tid som spenderas inom ramverket i sina loggningsmeddelanden. När det finns en betydande skillnad mellan den tid som rapporteras av kontrollanter och den totala tiden för begäran:
- Utvecklare eliminerar sin appkod som källa till problemet.
- Det är vanligt att anta att routning är orsaken.
Routning är prestandatestad med tusentals slutpunkter. Det är osannolikt att en typisk app kommer att stöta på ett prestandaproblem bara genom att vara för stor. Den vanligaste grundorsaken till långsamma routningsprestanda är vanligtvis ett dåligt fungerande anpassad middleware.
Följande kodexempel visar en grundläggande teknik för att begränsa fördröjningskällan:
var logger = app.Services.GetRequiredService<ILogger<Program>>();
app.Use(async (context, next) =>
{
var stopwatch = Stopwatch.StartNew();
await next(context);
stopwatch.Stop();
logger.LogInformation("Time 1: {ElapsedMilliseconds}ms", stopwatch.ElapsedMilliseconds);
});
app.UseRouting();
app.Use(async (context, next) =>
{
var stopwatch = Stopwatch.StartNew();
await next(context);
stopwatch.Stop();
logger.LogInformation("Time 2: {ElapsedMilliseconds}ms", stopwatch.ElapsedMilliseconds);
});
app.UseAuthorization();
app.Use(async (context, next) =>
{
var stopwatch = Stopwatch.StartNew();
await next(context);
stopwatch.Stop();
logger.LogInformation("Time 3: {ElapsedMilliseconds}ms", stopwatch.ElapsedMilliseconds);
});
app.MapGet("/", () => "Timing Test.");
För att schemalägga dirigeringen:
- Alternativt infoga mellanprogrammen med en kopia av tidsmellanprogrammet som visas i föregående kod.
- Lägg till en unik identifierare för att korrelera tidsdata med koden.
Det här är ett grundläggande sätt att begränsa fördröjningen när den är betydande, till exempel mer än 10ms. Subtrahera Time 2 från Time 1 rapporterar tiden som spenderats i UseRouting mellanprogrammet.
Följande kod använder en mer kompakt metod för föregående tidskod:
public sealed class AutoStopwatch : IDisposable
{
private readonly ILogger _logger;
private readonly string _message;
private readonly Stopwatch _stopwatch;
private bool _disposed;
public AutoStopwatch(ILogger logger, string message) =>
(_logger, _message, _stopwatch) = (logger, message, Stopwatch.StartNew());
public void Dispose()
{
if (_disposed)
{
return;
}
_logger.LogInformation("{Message}: {ElapsedMilliseconds}ms",
_message, _stopwatch.ElapsedMilliseconds);
_disposed = true;
}
}
var logger = app.Services.GetRequiredService<ILogger<Program>>();
var timerCount = 0;
app.Use(async (context, next) =>
{
using (new AutoStopwatch(logger, $"Time {++timerCount}"))
{
await next(context);
}
});
app.UseRouting();
app.Use(async (context, next) =>
{
using (new AutoStopwatch(logger, $"Time {++timerCount}"))
{
await next(context);
}
});
app.UseAuthorization();
app.Use(async (context, next) =>
{
using (new AutoStopwatch(logger, $"Time {++timerCount}"))
{
await next(context);
}
});
app.MapGet("/", () => "Timing Test.");
Potentiellt dyra routningsfunktioner
Följande lista ger en inblick i routningsfunktioner som är relativt dyra jämfört med grundläggande routningsmallar:
- Reguljära uttryck: Det går att skriva reguljära uttryck som är komplexa eller har lång körningstid med en liten mängd indata.
- Komplicerade segment (
{x}-{y}-{z}):- Är betydligt dyrare än att parsa ett vanligt URL-sökvägssegment.
- Resulterar i att många fler delsträngar kommer att allokeras.
- Synkron dataåtkomst: Många komplexa appar har databasåtkomst som en del av routningen. Använd utökningspunkter som MatcherPolicy och EndpointSelectorContext, som är asynkrona.
Vägledning för stora routningstabeller
Som standard använder ASP.NET Core en routningsalgoritm som byter minne mot CPU-tid. Detta har den fina effekten att vägmatchningstiden endast beror på längden på sökvägen som ska matchas och inte antalet vägar. Den här metoden kan dock vara potentiellt problematisk i vissa fall, när appen har ett stort antal vägar (i tusental) och det finns en hög mängd variabelprefix i vägarna. Om rutterna har parametrar i tidiga segment av rutten, som {parameter}/some/literal.
Det är osannolikt att en app stöter på en situation där detta är ett problem om inte:
- Det finns ett stort antal vägar i appen med det här mönstret.
- Det finns ett stort antal vägar i appen.
Så här avgör du om en app stöter på problemet med den stora routningstabellen
- Det finns två symptom att leta efter:
- Appen startar långsamt vid första användningen.
- Observera att detta är obligatoriskt men inte tillräckligt. Det finns många andra problem som inte är routningsproblem än vad som kan orsaka långsam appstart. Kontrollera om villkoret nedan är korrekt för att fastställa att appen körs i den här situationen.
- Appen förbrukar mycket minne under starten och en minnesdump visar ett stort antal
Microsoft.AspNetCore.Routing.Matching.DfaNodeinstanser.
- Appen startar långsamt vid första användningen.
Så här åtgärdar du det här problemet
Det finns flera tekniker och optimeringar som kan tillämpas på vägar som till stor del förbättrar det här scenariot:
- Tillämpa routningsbegränsningar på dina parametrar, till exempel
{parameter:int},{parameter:guid},{parameter:regex(\\d+)}osv. där det är möjligt.- På så sätt kan routningsalgoritmen internt optimera de strukturer som används för matchning och drastiskt minska det minne som används.
- I de allra flesta fall räcker detta för att återgå till ett acceptabelt beteende.
- Ändra vägarna för att flytta parametrar till senare segment i mallen.
- Detta minskar antalet möjliga "vägar" för att matcha en slutpunkt med en given väg.
- Använd en dynamisk rutt och utför mappningen till en kontroller/sida dynamiskt.
- Detta kan uppnås med hjälp av
MapDynamicControllerRouteochMapDynamicPageRoute.
- Detta kan uppnås med hjälp av
Vägledning för biblioteksförfattare
Det här avsnittet innehåller vägledning för biblioteksförfattare som bygger ovanpå routning. Den här informationen är avsedd att säkerställa att apputvecklare har en bra upplevelse med hjälp av bibliotek och ramverk som utökar routningen.
Definiera slutpunkter
Om du vill skapa ett ramverk som använder routning för URL-matchning börjar du med att definiera en användarupplevelse som bygger ovanpå UseEndpoints.
BYGG ovanpå IEndpointRouteBuilder. På så sätt kan användarna skapa ditt ramverk med andra ASP.NET Core-funktioner utan förväxling. Varje ASP.NET Core-mall innehåller routning. Anta att routning är närvarande och bekant för användare.
// Your framework
app.MapMyFramework(...);
app.MapHealthChecks("/healthz");
Returnera en förseglad betongtyp från ett anrop till MapMyFramework(...) som implementerar IEndpointConventionBuilder. De flesta ramverksmetoder Map... följer det här mönstret. Gränssnittet IEndpointConventionBuilder :
- Tillåter att metadata skapas.
- Är mål för en mängd olika tilläggsmetoder.
Om du deklarerar din egen typ kan du lägga till dina egna ramverksspecifika funktioner i byggaren. Det är okej att omsluta ett ramverksdeklarerat byggobjekt och vidarebefordra anrop till det.
// Your framework
app.MapMyFramework(...)
.RequireAuthorization()
.WithMyFrameworkFeature(awesome: true);
app.MapHealthChecks("/healthz");
ÖVERVÄG att skriva din egen EndpointDataSource.
EndpointDataSource är en grundläggande konstruktion för att deklarera och uppdatera en samling slutpunkter.
EndpointDataSource är ett kraftfullt API som används av kontrollanter och Razor sidor.
Routningstesterna har ett grundläggande exempel på en datakälla som inte uppdateras.
ÖVERVÄG att implementera GetGroupedEndpoints. Detta ger fullständig kontroll över gruppkonventioner som körs och de slutliga metadata på de grupperade slutpunkterna. Detta gör till exempel att anpassade EndpointDataSource implementeringar kan köra slutpunktsfilter som lagts till i grupper.
Försök INTE att registrera en EndpointDataSource som standard. Kräv att användare registrerar ditt ramverk i UseEndpoints. Routningsfilosofin är att ingenting ingår som standard, och det UseEndpoints är platsen där slutpunkter ska registreras.
Skapa routningsintegrerade mellanprogram
ÖVERVÄG att definiera metadatatyper som ett gränssnitt.
Gör det möjligt att använda metadatatyper som ett attribut för klasser och metoder.
public interface ICoolMetadata
{
bool IsCool { get; }
}
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
public class CoolMetadataAttribute : Attribute, ICoolMetadata
{
public bool IsCool => true;
}
Ramverk som kontrollanter och Razor sidor stöder tillämpning av metadataattribut på typer och metoder. Om du deklarerar metadatatyper:
- Gör dem tillgängliga som attribut.
- De flesta användare är bekanta med att tillämpa attribut.
Om du deklarerar en metadatatyp som ett gränssnitt läggs ett annat flexibelt lager till:
- Gränssnitt är sammansättningsbara.
- Utvecklare kan deklarera sina egna typer som kombinerar flera principer.
Gör det möjligt att åsidosätta metadata, som du ser i följande exempel:
[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() { }
}
Det bästa sättet att följa dessa riktlinjer är att undvika att definiera markörmetadata:
- Leta inte bara efter förekomsten av en metadatatyp.
- Definiera en egenskap för metadata och kontrollera egenskapen.
Metadatasamlingen är ordnad och möjliggör att överskrida efter prioritet. När det gäller kontrollanter är metadata för åtgärdsmetoden mest specifika.
Gör mellanprogram användbara med och utan routning:
app.UseAuthorization(new AuthorizationPolicy() { ... });
// Your framework
app.MapMyFramework(...).RequireAuthorization();
Som ett exempel på den här riktlinjen bör du överväga UseAuthorization mellanprogrammet. Med mellanprogrammet för auktorisering kan du ange en reservpolicy.
Om den anges, gäller återställningsprincipen för båda:
- Slutpunkter utan en angiven policy.
- Begäranden som inte överensstämmer med en slutpunkt.
Detta gör auktoriseringsmellanprogrammet användbart utanför routningskontexten. Mellanprogrammet för auktorisering kan användas för traditionell mellanprogramprogrammering.
Felsökningsdiagnostik
För detaljerade routningsdiagnostikutdata anger du Logging:LogLevel:Microsoft till Debug. I utvecklingsmiljön anger du loggnivån i appsettings.Development.json:
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Debug",
"Microsoft.Hosting.Lifetime": "Information"
}
}
}
Ytterligare resurser
Routning ansvarar för att matcha inkommande HTTP-begäranden och skicka dessa begäranden till appens körbara slutpunkter. Slutpunkter är appens enheter för körbar kod för hantering av begäranden. Slutpunkter definieras i appen och konfigureras när appen startas. Slutpunktsmatchningsprocessen kan extrahera värden från begärans URL och ange dessa värden för bearbetning av begäranden. Med hjälp av slutpunktsinformation från appen kan routning också generera URL:er som mappar till slutpunkter.
Appar kan konfigurera routning med hjälp av:
- Controllers
- Razor sidor
- SignalR
- gRPC-tjänster
- Slutpunktsaktiverat mellanprogram , till exempel hälsokontroller.
- Delegater och lambdas som registrerats med routning.
Den här artikeln beskriver information på låg nivå om ASP.NET Core-routning. Information om hur du konfigurerar routning:
- För kontrollanter, se Routning till kontrollantåtgärder i ASP.NET Core.
- För Razor Sidor-konventioner, se Razor Sidor rout- och appkonventioner i ASP.NET Core.
Grunderna för routning
Följande kod visar ett grundläggande exempel på routning:
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
app.MapGet("/", () => "Hello World!");
app.Run();
Föregående exempel innehåller en enskild slutpunkt med hjälp av MapGet metoden:
- När en HTTP-begäran
GETskickas till rot-URL:en/:- Begärandedelegaten utförs.
-
Hello World!skrivs till HTTP-svaret.
- Om begärandemetoden inte är
GETeller om rot-URL:en inte är/, matchar ingen rutt och en HTTP 404 returneras.
Routning använder ett par mellanprogram, registrerade av UseRouting och UseEndpoints:
-
UseRoutinglägger till routningsmatchning till pipelinen för mellanprogram. Det här mellanprogrammet tittar på den uppsättning slutpunkter som definierats i appen och väljer den bästa matchningen baserat på begäran. -
UseEndpointslägger till slutpunktskörning i pipelinen för mellanprogram. Den kör delegeringen som är kopplad till den valda slutpunkten.
Appar behöver vanligtvis inte anropa UseRouting eller UseEndpoints.
WebApplicationBuilder konfigurerar en middleware-pipeline som omsluter den middleware som lagts till i Program.cs med UseRouting och UseEndpoints. Appar kan dock ändra i vilken UseRouting ordning och UseEndpoints körs genom att anropa dessa metoder explicit. Följande kod gör till exempel ett explicit anrop till UseRouting:
app.Use(async (context, next) =>
{
// ...
await next(context);
});
app.UseRouting();
app.MapGet("/", () => "Hello World!");
I koden ovan:
- Anropet till
app.Useregistrerar ett anpassat mellanprogram som körs i början av pipelinen. - Anropet till
UseRoutingkonfigurerar mellanprogrammet för ruttmatchning att köras efter det anpassade mellanprogrammet. - Slutpunkten som registrerats med
MapGetkörs i slutet av pipeline.
Om föregående exempel inte innehöll ett anrop till UseRoutingskulle det anpassade mellanprogrammet köras efter vägen som matchar mellanprogrammet.
Endpoints
Metoden MapGet används för att definiera en slutpunkt. En slutpunkt är något som kan vara:
- Vald genom att matcha URL:en och HTTP-metoden.
- Utförs genom att köra delegeringen.
Ändpunkter som kan matchas och köras av appen konfigureras i UseEndpoints. Till exempel ansluter MapGet, MapPost och liknande metoder förbinder ombud för begäranden till routningssystemet. Ytterligare metoder kan användas för att ansluta ASP.NET Core Framework-funktioner till routningssystemet:
- MapRazorPages för Razor sidor
- MapControllers för styrenheter
- MapHub<THub> för SignalR
- MapGrpcService<TService> för gRPC
I följande exempel visas routning med en mer avancerad vägmall:
app.MapGet("/hello/{name:alpha}", (string name) => $"Hello {name}!");
Strängen /hello/{name:alpha} är en vägmall. En vägmall används för att konfigurera hur slutpunkten matchas. I det här fallet matchar mallen:
- En URL som
/hello/Docs - Alla URL-sökvägar som börjar med
/hello/följt av en sekvens med alfabetiska tecken.:alphatillämpar en vägbegränsning som endast matchar alfabetiska tecken. Routningsbegränsningar beskrivs senare i den här artikeln.
Det andra segmentet i URL-sökvägen: {name:alpha}
- Är bunden till parametern
name. - Samlas in och lagras i HttpRequest.RouteValues.
I följande exempel visas routning med hälsokontroller och auktorisering:
app.UseAuthentication();
app.UseAuthorization();
app.MapHealthChecks("/healthz").RequireAuthorization();
app.MapGet("/", () => "Hello World!");
Föregående exempel visar hur:
- Mellanprogrammet för auktorisering kan användas med routning.
- Slutpunkter kan användas för att konfigurera auktoriseringsbeteende.
Anropet MapHealthChecks lägger till en slutpunkt för hälsokontroll. Länkning RequireAuthorization till det här anropet kopplar en auktoriseringsprincip till slutpunkten.
Anropar UseAuthentication och UseAuthorization lägger till mellanprogrammet för autentisering och auktorisering. Dessa mellanprogram placeras mellan UseRouting och UseEndpoints så att de kan:
- Se vilken slutpunkt som har valts av
UseRouting. - Tillämpa en auktoriseringsprincip innan UseEndpoints skickas till slutpunkten.
Slutpunktsmetadata
I föregående exempel finns det två slutpunkter, men endast slutpunkten för hälsokontroll har en auktoriseringsprincip kopplad. Om begäran matchar slutpunkten /healthzför hälsokontroll utförs en auktoriseringskontroll. Detta visar att slutpunkter kan ha extra data kopplade till sig. Dessa extra data kallas slutpunktsmetadata:
- Metadata kan bearbetas av routningsmedvetna mellanprogram.
- Metadata kan vara av valfri .NET-typ.
Routningsbegrepp
Routningssystemet bygger på pipelinen för mellanprogram genom att lägga till det kraftfulla slutpunktskonceptet . Slutpunkter representerar enheter i appens funktioner som skiljer sig från varandra när det gäller routning, auktorisering och valfritt antal ASP.NET Core-system.
ASP.NET Core-slutpunktsdefinition
En ASP.NET Core-slutpunkt är:
- Körbar: Har en RequestDelegate.
- Utökningsbar: Har en metadatasamling .
- Valbar: Om du vill kan du ha routningsinformation.
- Uppräkningsbar: Samlingen med slutpunkter kan visas genom att EndpointDataSource hämta från DI.
Följande kod visar hur du hämtar och inspekterar slutpunkten som matchar den aktuella begäran:
app.Use(async (context, next) =>
{
var currentEndpoint = context.GetEndpoint();
if (currentEndpoint is null)
{
await next(context);
return;
}
Console.WriteLine($"Endpoint: {currentEndpoint.DisplayName}");
if (currentEndpoint is RouteEndpoint routeEndpoint)
{
Console.WriteLine($" - Route Pattern: {routeEndpoint.RoutePattern}");
}
foreach (var endpointMetadata in currentEndpoint.Metadata)
{
Console.WriteLine($" - Metadata: {endpointMetadata}");
}
await next(context);
});
app.MapGet("/", () => "Inspect Endpoint.");
Slutpunkten, om den är markerad, kan hämtas från HttpContext. Dess egenskaper kan inspekteras. Slutpunktsobjekt är oföränderliga och kan inte ändras när de har skapats. Den vanligaste typen av slutpunkt är en RouteEndpoint.
RouteEndpoint innehåller information som gör att den kan väljas av routningssystemet.
I föregående kod konfigurerar app.Use en inline-mellanprogram.
Följande kod visar att det, beroende på var app.Use som anropas i pipelinen, kanske inte finns någon slutpunkt:
// Location 1: before routing runs, endpoint is always null here.
app.Use(async (context, next) =>
{
Console.WriteLine($"1. Endpoint: {context.GetEndpoint()?.DisplayName ?? "(null)"}");
await next(context);
});
app.UseRouting();
// Location 2: after routing runs, endpoint will be non-null if routing found a match.
app.Use(async (context, next) =>
{
Console.WriteLine($"2. Endpoint: {context.GetEndpoint()?.DisplayName ?? "(null)"}");
await next(context);
});
// Location 3: runs when this endpoint matches
app.MapGet("/", (HttpContext context) =>
{
Console.WriteLine($"3. Endpoint: {context.GetEndpoint()?.DisplayName ?? "(null)"}");
return "Hello World!";
}).WithDisplayName("Hello");
app.UseEndpoints(_ => { });
// Location 4: runs after UseEndpoints - will only run if there was no match.
app.Use(async (context, next) =>
{
Console.WriteLine($"4. Endpoint: {context.GetEndpoint()?.DisplayName ?? "(null)"}");
await next(context);
});
Föregående exempel lägger till Console.WriteLine instruktioner som visar om en slutpunkt har valts eller inte. För tydlighetens skull tilldelar exemplet ett visningsnamn till den angivna / slutpunkten.
Föregående exempel innehåller även anrop till UseRouting och UseEndpoints för att styra exakt när dessa mellanprogram körs i pipelinen.
Kör den här koden med en URL på / visar:
1. Endpoint: (null)
2. Endpoint: Hello
3. Endpoint: Hello
Om du kör den här koden med andra URL:ar visas:
1. Endpoint: (null)
2. Endpoint: (null)
4. Endpoint: (null)
Dessa utdata visar att:
- Slutpunkten är alltid null innan
UseRoutinganropas. - Om en matchning hittas är slutpunkten inte null mellan
UseRoutingoch UseEndpoints. - Mellanprogrammet
UseEndpointsär terminal när en matchning hittas. Terminalmellanprogram definieras senare i den här artikeln. - Mellanprogrammet efter
UseEndpointskörs endast när ingen matchning hittas.
Mellanprogrammet UseRouting använder SetEndpoint metoden för att koppla slutpunkten till den aktuella kontexten. Det går att ersätta UseRouting mellanprogrammet med anpassad logik och ändå få fördelarna med att använda slutpunkter. Ändpunkter är ett grundläggande element på låg nivå som mellanvaror och är inte kopplade till routningens implementering. De flesta appar behöver inte ersättas UseRouting med anpassad logik.
Mellanprogrammet UseEndpoints är utformat för att användas tillsammans med UseRouting mellanprogrammet. Kärnlogiken för att utföra en slutpunkt är inte komplicerad. Använd GetEndpoint för att hämta slutpunkten och anropa sedan dess RequestDelegate egenskap.
Följande kod visar hur mellanprogram kan påverka eller reagera på routning:
app.UseHttpMethodOverride();
app.UseRouting();
app.Use(async (context, next) =>
{
if (context.GetEndpoint()?.Metadata.GetMetadata<RequiresAuditAttribute>() is not null)
{
Console.WriteLine($"ACCESS TO SENSITIVE DATA AT: {DateTime.UtcNow}");
}
await next(context);
});
app.MapGet("/", () => "Audit isn't required.");
app.MapGet("/sensitive", () => "Audit required for sensitive data.")
.WithMetadata(new RequiresAuditAttribute());
public class RequiresAuditAttribute : Attribute { }
Föregående exempel visar två viktiga begrepp:
- Mellanprogram kan köras tidigare
UseRoutingför att ändra de data som routningen körs på.- Vanligtvis ändrar mellanprogram som visas innan routning någon egenskap för begäran, till exempel UseRewriter, UseHttpMethodOverrideeller UsePathBase.
- Mellanprogram kan köras mellan
UseRoutingoch UseEndpoints för att bearbeta resultatet av routingen innan slutpunkten körs.- Mellanprogram som körs mellan
UseRoutingochUseEndpoints:- Inspekterar vanligtvis metadata för att förstå slutpunkterna.
- Fattar ofta säkerhetsbeslut, som görs av
UseAuthorizationochUseCors.
- Kombinationen av mellanprogram och metadata gör det möjligt att konfigurera principer per slutpunkt.
- Mellanprogram som körs mellan
Föregående kod visar ett exempel på ett anpassat mellanprogram som stöder principer per slutpunkt. Mellanprogrammet skriver en revisionslogg av åtkomst av känsliga data till konsolen. Mellanprogrammet kan konfigureras för att granska en slutpunkt med RequiresAuditAttribute metadata. Det här exemplet visar ett opt-in-mönster där endast slutpunkter som är markerade som känsliga granskas. Det är möjligt att definiera den här logiken omvänt och granska allt som inte är markerat som säkert, till exempel. Slutpunktsmetadatasystemet är flexibelt. Den här logiken kan utformas på vilket sätt som helst som passar användningsfallet.
Föregående exempelkod är avsedd att demonstrera de grundläggande begreppen för slutpunkter. Exemplet är inte avsett för produktionsanvändning. En mer fullständig version av ett mellanprogram för granskningsloggar skulle:
- Logga in på en fil eller databas.
- Inkludera information som användaren, IP-adressen, namnet på den känsliga slutpunkten med mera.
Metadata för revisionspolicy RequiresAuditAttribute definieras som en Attribute för att enklare kunna använda klassbaserade ramverk som kontroller och SignalR. När du använder route to code:
- Metadata bifogas med ett builder-API.
- Klassbaserade ramverk innehåller alla attribut på motsvarande metod och klass när du skapar slutpunkter.
Metodtipsen för metadatatyper är att definiera dem antingen som gränssnitt eller attribut. Gränssnitt och attribut tillåter återanvändning av kod. Metadatasystemet är flexibelt och medför inga begränsningar.
Jämför terminalmellanprogram med routning
I följande exempel visas både terminalmellanprogram och routning:
// Approach 1: Terminal Middleware.
app.Use(async (context, next) =>
{
if (context.Request.Path == "/")
{
await context.Response.WriteAsync("Terminal Middleware.");
return;
}
await next(context);
});
app.UseRouting();
// Approach 2: Routing.
app.MapGet("/Routing", () => "Routing.");
Formatet för mellanprogram som visas med Approach 1: är terminalmellanprogram. Det kallas terminalmellanprogram eftersom det utför en matchande åtgärd:
- Matchningsåtgärden i föregående exempel är
Path == "/"för mellanprogrammet ochPath == "/Routing"för routning. - När en matchning lyckas, utför den vissa funktioner och returnerar istället för att anropa
next-mellanprogrammet.
Det kallas terminalmellanprogram eftersom det avslutar sökningen, kör vissa funktioner och sedan returnerar.
I följande lista jämförs terminalmellanprogram med routning:
- Båda metoderna gör det möjligt att avsluta bearbetningspipelinen:
- Mellanprogram avslutar pipelinen genom att returnera i stället för att
nextanropa . - Slutpunkter är alltid terminaler.
- Mellanprogram avslutar pipelinen genom att returnera i stället för att
- Med terminalmellanprogram kan du placera mellanprogrammet på en godtycklig plats i pipelinen:
- Slutpunkter körs på positionen UseEndpoints.
- Med terminalmellanprogram kan godtycklig kod avgöra när mellanprogrammet matchar:
- Anpassad vägmatchningskod kan vara utförlig och svår att skriva korrekt.
- Routning ger enkla lösningar för typiska appar. De flesta appar kräver inte anpassad vägmatchningskod.
- Slutpunktsgränssnitt med mellanprogram som
UseAuthorizationochUseCors.- Användning av ett terminalmellanprogram med
UseAuthorizationellerUseCorskräver manuell koppling med auktoriseringssystemet.
- Användning av ett terminalmellanprogram med
En slutpunkt definierar båda:
- Ett ombud för att bearbeta begäranden.
- En samling godtyckliga metadata. Metadata används för att implementera övergripande problem baserat på principer och konfiguration som är kopplade till varje slutpunkt.
Terminalmellanprogram kan vara ett effektivt verktyg, men kan kräva:
- En betydande mängd kodning och testning.
- Manuell integrering med andra system för att uppnå önskad flexibilitetsnivå.
Överväg att integrera med routning innan du skriver ett terminalmellanprogram.
Befintliga terminalmellanprogram som integreras med Map eller MapWhen kan vanligtvis omvandlas till en routingmedveten slutpunkt. MapHealthChecks visar mönstret för router-ware:
- Skriv en tilläggsmetod på IEndpointRouteBuilder.
- Skapa en pipeline för kapslade mellanprogram med CreateApplicationBuilder.
- Koppla mellanprogrammet till den nya pipelinen. I det här fallet UseHealthChecks.
- Build mellanprogramspipelinen till en RequestDelegate.
- Anropa
Mapoch ange den nya pipelinen för mellanprogram. - Returnera builder-objektet som tillhandahålls av
Mapfrån tilläggsmetoden.
Följande kod visar användning av MapHealthChecks:
app.UseAuthentication();
app.UseAuthorization();
app.MapHealthChecks("/healthz").RequireAuthorization();
Föregående exempel visar varför det är viktigt att returnera builder-objektet. När byggobjektet returneras kan apputvecklaren konfigurera principer som auktorisering för slutpunkten. I det här exemplet har mellanprogrammet för hälsokontroller ingen direkt integrering med auktoriseringssystemet.
Metadatasystemet skapades som svar på de problem som uppstått av utökningsförfattare med hjälp av terminalmellanprogram. Det är problematiskt för varje mellanprogram att implementera sin egen integrering med auktoriseringssystemet.
URL-matchning
- Är den process genom vilken routningen matchar en inkommande begäran till en slutpunkt.
- Baseras på data i URL-sökvägen och rubrikerna.
- Kan utökas för att överväga alla data i begäran.
När ett routningsmellanprogram körs anger det en Endpoint och dirigerar värden till en begäransfunktion på HttpContext från den aktuella begäran:
- Genom att anropa HttpContext.GetEndpoint hämtas slutpunkten.
-
HttpRequest.RouteValueshämtar samlingen av routvärden.
Mellanprogram körs efter att routningsmellanprogram har möjlighet att inspektera slutpunkten och vidta åtgärder. Till exempel kan ett mellanprogramvara för auktorisering granska och utvärdera slutpunktens metadatasamling för en auktoriseringspolicy. När alla mellanprogram i pipelinen för bearbetning av begäranden har körts anropas den valda slutpunktens ombud.
Routningssystemet i slutpunktsroutningen ansvarar för alla leveransbeslut. Eftersom mellanprogrammet tillämpar principer baserat på den valda slutpunkten är det viktigt att:
- Alla beslut som kan påverka sändningen eller tillämpningen av säkerhetsprinciper fattas i routningssystemet.
Warning
För bakåtkompatibilitet, när en Controller eller Razor Pages-slutpunktsdelegat körs, anges egenskaperna till lämpliga värden baserat på den bearbetning som hittills utförts av RouteContext.RouteData-begäran.
Typen RouteContext kommer att markeras som föråldrad i en framtida version:
- Migrera
RouteData.ValuestillHttpRequest.RouteValues. - Migrera
RouteData.DataTokensför att hämta IDataTokensMetadata från slutpunktsmetadata.
URL-matchning fungerar i en konfigurerbar uppsättning faser. I varje fas är utdata en uppsättning matchningar. Mängden matcher kan begränsas ytterligare under nästa fas. Routningsimplementeringen garanterar inte någon bearbetningsordning för matchande slutpunkter. Alla möjliga matchningar bearbetas samtidigt. Url-matchningsfaserna sker i följande ordning. ASP.NET Core:
- Bearbetar URL-sökvägen mot uppsättningen slutpunkter och deras vägmallar och samlar in alla matchningar.
- Tar den föregående listan och tar bort matchningar som inte uppfyller ruttbegränsningar som tillämpas.
- Tar föregående lista och tar bort matchningar som inte uppfyller kraven för MatcherPolicy instanser.
- Använder EndpointSelector för att fatta ett slutgiltigt beslut från föregående lista.
Listan över slutpunkter prioriteras enligt:
- Den RouteEndpoint.Order
- Prioritet för routsmall
Alla matchande ändpunkter bearbetas i varje fas tills den EndpointSelector har nåtts.
EndpointSelector är den sista fasen. Den väljer den högsta prioritetsslutpunkten från matchningarna som den bästa matchningen. Om det finns andra matchningar med samma prioritet som den bästa matchningen, kommer ett tvetydigt matchningsundantag att utlösas.
Routningsprioriteten beräknas baserat på att en mer specifik vägmall får högre prioritet. Tänk till exempel på mallarna /hello och /{message}:
- Båda matchar URL-sökvägen
/hello. -
/helloär mer specifik och därför högre prioritet.
I allmänhet gör routningsprioriteten ett bra jobb med att välja den bästa matchningen för de typer av URL-scheman som används i praktiken. Använd Order endast när det behövs för att undvika tvetydigheter.
På grund av de typer av utökningsbarhet som tillhandahålls av routning är det inte möjligt för routningssystemet att beräkna de tvetydiga vägarna i förväg. Överväg ett exempel som routningsmallarna /{message:alpha} och /{message:int}:
- Villkoret
alphamatchar endast alfabetiska tecken. - Villkoret
intmatchar endast tal. - Dessa mallar har samma vägprioritet, men det finns ingen enskild URL som båda matchar.
- Om routningssystemet rapporterade ett tvetydighetsfel vid starten skulle det blockera det här giltiga användningsfallet.
Warning
Ordningen på åtgärderna i UseEndpoints påverkar inte beteendet för routning, med ett undantag. MapControllerRoute och MapAreaRoute tilldela automatiskt ett ordervärde till sina slutpunkter baserat på den ordning som de anropas. Detta simulerar långvarigt beteende för kontrollanter utan att routningssystemet ger samma garantier som äldre routningsimplementeringar.
Slutpunktsroutning i ASP.NET Core:
- Har inte begreppet rutter.
- Ger inte ordergarantier. Alla slutpunkter bearbetas samtidigt.
Routningsmallens prioritet och slutpunktsmarkeringsordning
Prioritet för routningsmallar är ett system som tilldelar varje vägmall ett värde baserat på hur specifik den är. Prioritet för routningsmall:
- Undviker behovet av att justera ordningen på slutpunkter i vanliga fall.
- Försöker matcha allmänna förväntningar på routingbeteende.
Du kan till exempel överväga mallar /Products/List och /Products/{id}. Det är rimligt att anta att det /Products/List är en bättre matchning än /Products/{id} för URL-sökvägen /Products/List. Detta fungerar eftersom literalsegmentet /List anses ha bättre prioritet än parametersegmentet /{id}.
Information om hur prioritet fungerar är kopplat till hur routningsmallar definieras:
- Mallar med fler segment anses vara mer specifika.
- Ett segment med literaltext anses vara mer specifikt än ett parametersegment.
- Ett parametersegment med en begränsning anses vara mer specifikt än ett utan.
- Ett komplext segment anses vara lika specifikt som ett parametersegment med en begränsning.
- Catch-all-parametrar är de minst specifika. Se catch-all i avsnittet Routningsmallar för viktig information om catch-all-vägar.
Begrepp för URL-generering
URL-generering:
- Är den process genom vilken routning kan skapa en URL-sökväg baserat på en uppsättning vägvärden.
- Tillåter en logisk separation mellan slutpunkter och URL:er som har åtkomst till dem.
Slutpunktsroutning innehåller API:et LinkGenerator .
LinkGenerator är en singleton-tjänst som är tillgänglig från DI. API LinkGenerator kan användas utanför kontexten för en exekverande begäran.
Mvc.IUrlHelper och scenarier som förlitar sig på IUrlHelper, till exempel Tag Helpers, HTML Helpers och Action Results, använder API:et LinkGenerator internt för att tillhandahålla funktioner för länkgenerering.
Länkgeneratorn backas upp av begreppet adress - och adressscheman. Ett adressschema är ett sätt att fastställa de slutpunkter som ska beaktas för länkgenerering. Till exempel implementeras scenarier med routningnamn och routvärden som många användare är bekanta med från kontroller och Razor sidor såsom ett adressschema.
Länkgeneratorn kan länka till styrenheter och Razor sidor via följande tilläggsmetoder:
Överbelastningar av dessa metoder tar emot argument som inkluderar HttpContext. Dessa metoder är funktionellt likvärdiga med Url.Action och Url.Page, men ger ytterligare flexibilitet och alternativ.
Metoderna GetPath* liknar Url.Action mest och Url.Page, eftersom de genererar en URI som innehåller en absolut sökväg. Metoderna GetUri* genererar alltid en absolut URI som innehåller ett schema och en värd. De metoder som accepterar en HttpContext genererar en URI i kontexten för den körande begäran. Värden ambienta för väg, URL-bassökväg, protokoll och värd från den körande begäran används om de inte åsidosätts.
LinkGenerator anropas med en adress. Generera en URI sker i två steg:
- En adress är bunden till en lista över slutpunkter som matchar adressen.
- Varje slutpunkts RoutePattern utvärderas tills ett vägmönster som matchar de angivna värdena hittas. Resultatet kombineras med de andra URI-delarna som levereras till länkgeneratorn och returneras.
Metoderna som tillhandahålls av LinkGenerator stöder standardfunktioner för länkgenerering för alla typer av adresser. Det enklaste sättet att använda länkgeneratorn är genom tilläggsmetoder som utför åtgärder för en viss adresstyp:
| Tilläggsmetod | Description |
|---|---|
| GetPathByAddress | Genererar en URI med en absolut sökväg baserat på de angivna värdena. |
| GetUriByAddress | Genererar en absolut URI baserat på de angivna värdena. |
Warning
Var uppmärksam på följande konsekvenser av att anropa LinkGenerator metoder:
Använd
GetUri*tilläggsmetoder med försiktighet i en appkonfiguration som inte validerar headern för inkommande begäranden.HostOm rubriken för inkommande begäranden inte verifieras kan ej betrodda begärandeindata skickas tillbaka till klienten i URI:er i en vy eller sida. Vi rekommenderar att alla produktionsappar konfigurerar sin server för att kontrolleraHostheadern mot kända giltiga värden.Använd LinkGenerator med försiktighet i mellanprogram i kombination med
MapellerMapWhen.Map*ändrar basvägen för den körande begäran, vilket påverkar utdata från länkgenereringen. LinkGenerator Alla API:er tillåter att du anger en bassökväg. Ange en tom bassökväg för att ta bortMap*effekten på länkgenereringen.
Exempel på mellanprogram
I följande exempel använder ett mellanprogram API:et LinkGenerator för att skapa en länk till en åtgärdsmetod som visar lagerprodukter. Använda länkgeneratorn genom att mata in den i en klass och anrop GenerateLink är tillgängligt för alla klasser i en app:
public class ProductsMiddleware
{
private readonly LinkGenerator _linkGenerator;
public ProductsMiddleware(RequestDelegate next, LinkGenerator linkGenerator) =>
_linkGenerator = linkGenerator;
public async Task InvokeAsync(HttpContext httpContext)
{
httpContext.Response.ContentType = MediaTypeNames.Text.Plain;
var productsPath = _linkGenerator.GetPathByAction("Products", "Store");
await httpContext.Response.WriteAsync(
$"Go to {productsPath} to see our products.");
}
}
Routningsmallar
Token inom {} definierar ruttparametrar som är bundna om rutten matchas. Mer än en vägparameter kan definieras i ett vägsegment, men vägparametrarna måste avgränsas med ett literalvärde. Till exempel:
{controller=Home}{action=Index}
är inte en giltig väg eftersom det inte finns något literalvärde mellan {controller} och {action}. Routningsparametrarna måste ha ett namn och kan ha ytterligare attribut angivna.
Annan literaltext än vägparametrar (till exempel {id}) och sökvägsavgränsaren / måste matcha texten i URL:en. Textmatchning är skiftlägesokänslig och baseras på den avkodade representationen av URL:ens sökväg. Om du vill matcha en literalvägsparameter avgränsare { eller }kan du undvika avgränsare genom att upprepa tecknet. Till exempel {{ eller }}.
Asterisk * eller dubbel asterisk **:
- Kan användas som ett prefix till en vägparameter för att binda till resten av URI:n.
- Kallas för catch-all-parametrar. Till exempel
blog/{**slug}:- Matchar alla URI:er som börjar med
blog/och har ett värde som följer den. - Värdet som följer efter
blog/tilldelas som värde för slug-routen.
- Matchar alla URI:er som börjar med
Warning
En parameter kan matcha vägar felaktigt på grund av en bugg i routning. Appar som påverkas av den här buggen har följande egenskaper:
- En allomfattande rutt, till exempel
{**slug}" - Catch-all-vägen matchar inte begäranden som den ska matcha.
- Om du tar bort andra rutter börjar den allomfattande rutten att fungera.
Se GitHub-buggar 18677 och 16579 till exempel fall som drabbat den här buggen.
En anmälningskorrigering för den här buggen finns i .NET Core 3.1.301 eller senare SDK. Följande kod anger en intern växel som åtgärdar felet:
public static void Main(string[] args)
{
AppContext.SetSwitch("Microsoft.AspNetCore.Routing.UseCorrectCatchAllBehavior",
true);
CreateHostBuilder(args).Build().Run();
}
// Remaining code removed for brevity.
Catch-all-parametrar kan även matcha den tomma strängen.
Parametern catch-all undflyr lämpliga tecken när vägen används för att generera en URL, inklusive sökvägsavgränsningstecken / . Till exempel genererar rutten foo/{*path} med ruttvärden { path = "my/path" }foo/my%2Fpath. Observera det undantagna snedstrecket. Använd routningsparameterprefixet ** för att avgränsa sökvägens avgränsningstecken. Vägen foo/{**path} med { path = "my/path" } genererar foo/my/path.
URL-mönster som försöker avbilda ett filnamn med ett valfritt filnamnstillägg har ytterligare överväganden. Överväg till exempel mallen files/{filename}.{ext?}. När värden för båda filename och ext finns fylls båda värdena i. Om det bara finns ett värde för filename i URL:en matchar vägen eftersom avslutandet . är valfritt. Följande URL:er matchar den här vägen:
/files/myFile.txt/files/myFile
Routningsparametrar kan ha standardvärden som anges genom att ange standardvärdet efter parameternamnet avgränsat med ett likhetstecken (=). Definierar {controller=Home}Home till exempel som standardvärde för controller. Standardvärdet används om inget värde finns i URL:en för parametern. Routningsparametrar görs valfria genom att ett frågetecken (?) läggs till i slutet av parameternamnet. Till exempel id?. Skillnaden mellan valfria värden och standardvägsparametrar är:
- En routningsparameter med ett standardvärde genererar alltid ett värde.
- En valfri parameter har endast ett värde när ett värde tillhandahålls av begärande-URL:en.
Ruttparametrarna kan ha begränsningar som måste matcha ruttvärdet som är bundet från URL:en. Att lägga till : och villkorsnamn efter namnet på routningsparametern anger en infogad begränsning för en routningsparameter. Om villkoret kräver argument omges de av parenteser (...) efter villkorsnamnet. Du kan ange flera inline-begränsningar genom att lägga till en annan : och ett annat begränsningsnamn.
Villkorsnamnet och argumenten IInlineConstraintResolver skickas till tjänsten för att skapa en instans av IRouteConstraint som ska användas i URL-bearbetning. Routningsmallen blog/{article:minlength(10)} anger till exempel en minlength begränsning med argumentet 10. Mer information om routningsbegränsningar och en lista över de begränsningar som tillhandahålls av ramverket finns i avsnittet Routningsbegränsningar .
Routningsparametrar kan också ha parametertransformatorer. Parametertransformatorer transformerar en parameters värde vid generering av länkar och matchande åtgärder och sidor till URL:er. Precis som begränsningar kan parametertransformatorer läggas till direkt i en routparameter genom att lägga till ett : och ett transformeringsnamn efter routparameternamnet. Routningsmallen blog/{article:slugify} anger till exempel en slugify transformerare. Mer information om parametertransformatorer finns i avsnittet Parametertransformatorer .
I följande tabell visas exempel på routningsmallar och deras beteende:
| Routningsmall | Exempel på matchande URI | Förfrågan-URI:n... |
|---|---|---|
hello |
/hello |
Matchar endast den ensamma sökvägen /hello. |
{Page=Home} |
/ |
Matchar och anger Page till Home. |
{Page=Home} |
/Contact |
Matchar och anger Page till Contact. |
{controller}/{action}/{id?} |
/Products/List |
Mappar till kontroller Products och åtgärd List. |
{controller}/{action}/{id?} |
/Products/Details/123 |
Mappar till kontrollanten Products och Details åtgärden medid värdet 123. |
{controller=Home}/{action=Index}/{id?} |
/ |
Mappar till Home-kontrollern och Index-metoden.
id ignoreras. |
{controller=Home}/{action=Index}/{id?} |
/Products |
Mappar till Products-kontrollern och Index-metoden.
id ignoreras. |
Att använda en mall är vanligtvis den enklaste metoden för routning. Begränsningar och standardvärden kan också anges utanför vägmallen.
Komplexa segment
Komplexa segment bearbetas genom matchning av literalavgränsare från höger till vänster på ett icke-girigt sätt. Till exempel [Route("/a{b}c{d}")] är ett komplext segment.
Komplexa segment fungerar på ett visst sätt som måste tolkas för att kunna använda dem. Exemplet i det här avsnittet visar varför komplexa segment bara fungerar bra när avgränsartexten inte visas i parametervärdena. Att använda en regex och sedan extrahera värdena manuellt behövs för mer komplexa fall.
Warning
När du använder System.Text.RegularExpressions för att bearbeta ej betrodda indata skickar du en timeout. En obehörig användare kan ange indata för att RegularExpressions orsaka en Denial-of-Service-attack. ASP.NET Core Frameworks API som använder RegularExpressions har en timeout.
Det här är en sammanfattning av de steg som routningen utför med mallen /a{b}c{d} och URL-sökvägen /abcd.
| Används för att visualisera hur algoritmen fungerar:
- Den första literalen, från höger till vänster, är
c. Så/abcdsöks från höger och hittar/ab|c|d. - Allt till höger (
d) matchas nu med routningsparametern{d}. - Nästa literal, från höger till vänster, är
a. Så/ab|c|dgenomsöks från där vi slutade, sedan hittasa/|a|b|c|d. - Värdet till höger (
b) matchas nu med routningsparametern{b}. - Det finns ingen kvarvarande text och ingen kvarvarande mall för rutt, så det här är en matchning.
Här är ett exempel på ett negativt ärende med samma mall /a{b}c{d} och URL-sökvägen /aabcd.
| Används för att visualisera hur algoritmen fungerar. Det här fallet är inte en matchning, vilket förklaras av samma algoritm:
- Den första literalen, från höger till vänster, är
c. Så/aabcdsöks från höger och hittar/aab|c|d. - Allt till höger (
d) matchas nu med routningsparametern{d}. - Nästa literal, från höger till vänster, är
a. Så/aab|c|dgenomsöks från där vi slutade, sedan hittasa/a|a|b|c|d. - Värdet till höger (
b) matchas nu med routningsparametern{b}. - I det här läget finns det fortfarande text
a, men algoritmen har slut på vägmall för analys, så detta stämmer inte.
Eftersom matchningsalgoritmen inte är girig:
- Den matchar den minsta möjliga mängden text i varje steg.
- Alla fall där avgränsarvärdet visas i parametervärdena resulterar i att det inte matchar.
Reguljära uttryck ger mycket mer kontroll över deras matchande beteende.
Girig matchning, också kallad försiktig matchning, matchar den största möjliga strängen. Icke-giriga matchar den minsta möjliga strängen.
Routning med specialtecken
Routning med specialtecken kan leda till oväntade resultat. Tänk dig till exempel en kontrollant med följande åtgärdsmetod:
[HttpGet("{id?}/name")]
public async Task<ActionResult<string>> GetName(string id)
{
var todoItem = await _context.TodoItems.FindAsync(id);
if (todoItem == null || todoItem.Name == null)
{
return NotFound();
}
return todoItem.Name;
}
När string id innehåller följande kodade värden kan oväntade resultat inträffa:
| ASCII | Encoded |
|---|---|
/ |
%2F |
|
+ |
Routningsparametrar är inte alltid URL-avkodade. Det här problemet kan åtgärdas i framtiden. Mer information finns i det här GitHub-problemet;
Vägbegränsningar
Routningsbegränsningar körs när en matchning har hittats för den inkommande URL:en och URL-sökvägen tokeniseras till ruttvärden. Routningsbegränsningar inspekterar vanligtvis det vägvärde som är associerat via routningsmallen och fattar ett sant eller falskt beslut om huruvida värdet är acceptabelt. Vissa routningsbegränsningar använder data utanför vägvärdet för att överväga om begäran kan dirigeras. Till exempel HttpMethodRouteConstraint kan acceptera eller avvisa en begäran baserat på dess HTTP-verb. Begränsningar används i routningsbegäranden och länkgenerering.
Warning
Använd inte begränsningar för indataverifiering. Om begränsningar används för indataverifiering resulterar ogiltiga indata i ett 404 svar som inte hittades. Ogiltiga indata bör generera en 400 felaktig begäran med ett lämpligt felmeddelande. Routningsbegränsningar används för att särskilja liknande rutter, inte för att verifiera inmatningar för en viss rutt.
I följande tabell visas exempel på vägbegränsningar och deras förväntade beteende:
| constraint | Example | Exempelmatchningar | Notes |
|---|---|---|---|
int |
{id:int} |
123456789, -123456789 |
Matchar alla heltal |
bool |
{active:bool} |
true, FALSE |
Matchar true eller false. Case-insensitive |
datetime |
{dob:datetime} |
2016-12-31, 2016-12-31 7:32pm |
Matchar ett giltigt DateTime värde i den invarianta kulturen. Se föregående varning. |
decimal |
{price:decimal} |
49.99, -1,000.01 |
Matchar ett giltigt decimal värde i den invarianta kulturen. Se föregående varning. |
double |
{weight:double} |
1.234, -1,001.01e8 |
Matchar ett giltigt double värde i den invarianta kulturen. Se föregående varning. |
float |
{weight:float} |
1.234, -1,001.01e8 |
Matchar ett giltigt float värde i den invarianta kulturen. Se föregående varning. |
guid |
{id:guid} |
CD2C1638-1638-72D5-1638-DEADBEEF1638 |
Matchar ett giltigt Guid värde |
long |
{ticks:long} |
123456789, -123456789 |
Matchar ett giltigt long värde |
minlength(value) |
{username:minlength(4)} |
Rick |
Strängen måste innehålla minst 4 tecken |
maxlength(value) |
{filename:maxlength(8)} |
MyFile |
Strängen får inte innehålla fler än 8 tecken |
length(length) |
{filename:length(12)} |
somefile.txt |
Strängen måste vara exakt 12 tecken lång |
length(min,max) |
{filename:length(8,16)} |
somefile.txt |
Strängen får vara minst 8 och högst 16 tecken lång |
min(value) |
{age:min(18)} |
19 |
Heltalsvärdet måste vara minst 18 |
max(value) |
{age:max(120)} |
91 |
Heltalsvärdet får inte vara mer än 120 |
range(min,max) |
{age:range(18,120)} |
91 |
Heltalsvärdet måste vara minst 18 men högst 120 |
alpha |
{name:alpha} |
Rick |
Strängen måste bestå av ett eller flera alfabetiska tecken, och vara skiftlägesokänslig, a-z. |
regex(expression) |
{ssn:regex(^\\d{{3}}-\\d{{2}}-\\d{{4}}$)} |
123-45-6789 |
Strängen måste matcha det reguljära uttrycket. Se tips om hur du definierar ett reguljärt uttryck. |
required |
{name:required} |
Rick |
Används för att framtvinga att ett icke-parametervärde finns under URL-generering |
Warning
När du använder System.Text.RegularExpressions för att bearbeta ej betrodda indata skickar du en timeout. En obehörig användare kan ange indata för att RegularExpressions orsaka en Denial-of-Service-attack. ASP.NET Core Frameworks API som använder RegularExpressions har en timeout.
Flera, kolonavgränsade begränsningar kan tillämpas på en enskild parameter. Följande villkor begränsar till exempel en parameter till ett heltalsvärde på 1 eller högre:
[Route("users/{id:int:min(1)}")]
public User GetUserById(int id) { }
Warning
Routningsbegränsningar som verifierar URL:en och konverteras till en CLR-typ använder alltid den invarianta kulturen. Till exempel konvertering till CLR-typen int eller DateTime. Dessa begränsningar förutsätter att URL:en inte kan lokaliseras. De ramverksbaserade vägbegränsningarna ändrar inte de värden som lagras i vägvärden. Alla vägvärden som parsas från URL:en lagras som strängar. Villkoret float försöker till exempel konvertera vägvärdet till en flyttal, men det konverterade värdet används bara för att verifiera att det kan konverteras till en flyttal.
Reguljära uttryck i begränsningar
Warning
När du använder System.Text.RegularExpressions för att bearbeta ej betrodda indata skickar du en timeout. En obehörig användare kan ange indata för att RegularExpressions orsaka en Denial-of-Service-attack. ASP.NET Core Frameworks API som använder RegularExpressions har en timeout.
Reguljära uttryck kan anges som infogade begränsningar med hjälp av routningsbegränsningen regex(...) . Metoder i MapControllerRoute familjen accepterar också en objektliteral av begränsningar. Om formuläret används tolkas strängvärden som reguljära uttryck.
Följande kod använder en infogad regex-begränsning:
app.MapGet("{message:regex(^\\d{{3}}-\\d{{2}}-\\d{{4}}$)}",
() => "Inline Regex Constraint Matched");
Följande kod använder en objektliteral för att ange en regex-begränsning:
app.MapControllerRoute(
name: "people",
pattern: "people/{ssn}",
constraints: new { ssn = "^\\d{3}-\\d{2}-\\d{4}$", },
defaults: new { controller = "People", action = "List" });
Ramverket ASP.NET Core lägger RegexOptions.IgnoreCase | RegexOptions.Compiled | RegexOptions.CultureInvariant till konstruktorn för reguljära uttryck. Se RegexOptions en beskrivning av dessa medlemmar.
Reguljära uttryck använder avgränsare och token som liknar dem som används vid routning och C#-språket. Token för reguljära uttryck måste vara undantagna. Om du vill använda reguljära uttryck ^\d{3}-\d{2}-\d{4}$ i en infogad begränsning använder du något av följande:
- Ersätt
\tecken som anges i strängen som\\tecken i C#-källfilen för att undvika strängens\escape-tecken. - Verbatim strängliteraler.
Om du vill undvika dirigeringsparametertecken {, }, [, ], dubblar du tecknen i uttrycket, {{till exempel , }}, [[, . ]] I följande tabell visas ett reguljärt uttryck och dess undantagna version:
| Reguljärt uttryck | Undantagna reguljära uttryck |
|---|---|
^\d{3}-\d{2}-\d{4}$ |
^\\d{{3}}-\\d{{2}}-\\d{{4}}$ |
^[a-z]{2}$ |
^[[a-z]]{{2}}$ |
Reguljära uttryck som används i routning börjar ofta med ^ tecknet och matchar strängens startposition. Uttrycken slutar ofta med $ tecknet och matchar slutet av strängen. Tecknen ^ och $ ser till att det reguljära uttrycket matchar värdet för hela routningsparametern. Utan ^- och $-tecknen matchar det reguljära uttrycket vilken delsträng som helst i strängen, vilket ofta är oönskat. Följande tabell innehåller exempel och förklarar varför de matchar eller inte matchar:
| Expression | String | Match | Comment |
|---|---|---|---|
[a-z]{2} |
hello | Yes | Matchningar för delsträngar |
[a-z]{2} |
123abc456 | Yes | Matchningar för delsträngar |
[a-z]{2} |
mz | Yes | Matchar uttryck |
[a-z]{2} |
MZ | Yes | Inte skiftlägeskänslig |
^[a-z]{2}$ |
hello | No | Se ^ och $ ovan |
^[a-z]{2}$ |
123abc456 | No | Se ^ och $ ovan |
Mer information om syntax för reguljära uttryck finns i Reguljära .NET Framework-uttryck.
Om du vill begränsa en parameter till en känd uppsättning möjliga värden använder du ett reguljärt uttryck. Till exempel {action:regex(^(list|get|create)$)} matchar endast routningsvärdet action till list, geteller create. Om den skickas in i begränsningsordboken, så är strängen ^(list|get|create)$ likvärdig. Begränsningar som skickas i villkorsordlistan som inte matchar någon av de kända begränsningarna behandlas också som reguljära uttryck. Begränsningar som skickas i en mall som inte matchar någon av de kända begränsningarna behandlas inte som reguljära uttryck.
Begränsningar för anpassad rutt
Anpassade routningsbegränsningar kan skapas genom att implementera IRouteConstraint gränssnittet. Gränssnittet IRouteConstraint innehåller Match, som returnerar true om villkoret är uppfyllt och false på annat sätt.
Anpassade routningsbegränsningar behövs sällan. Innan du implementerar en anpassad vägbegränsning bör du överväga alternativ, till exempel modellbindning.
Mappen ASP.NET Core Constraints innehåller bra exempel på hur du skapar begränsningar. Till exempel GuidRouteConstraint.
Om du vill använda en anpassad IRouteConstraintmåste routningsbegränsningstypen registreras med appens ConstraintMap i tjänstcontainern. A ConstraintMap är en ordlista som mappar routningsbegränsningsnycklar till IRouteConstraint implementeringar som validerar dessa begränsningar. En app"s ConstraintMap kan uppdateras i Program.cs antingen som en del av ett AddRouting-anrop eller genom att konfigurera RouteOptions direkt med builder.Services.Configure<RouteOptions>. Till exempel:
builder.Services.AddRouting(options =>
options.ConstraintMap.Add("noZeroes", typeof(NoZeroesRouteConstraint)));
Föregående villkor tillämpas i följande kod:
[ApiController]
[Route("api/[controller]")]
public class NoZeroesController : ControllerBase
{
[HttpGet("{id:noZeroes}")]
public IActionResult Get(string id) =>
Content(id);
}
Implementeringen av NoZeroesRouteConstraint förhindrar 0 att den används i en vägparameter:
public class NoZeroesRouteConstraint : IRouteConstraint
{
private static readonly Regex _regex = new(
@"^[1-9]*$",
RegexOptions.CultureInvariant | RegexOptions.IgnoreCase,
TimeSpan.FromMilliseconds(100));
public bool Match(
HttpContext? httpContext, IRouter? route, string routeKey,
RouteValueDictionary values, RouteDirection routeDirection)
{
if (!values.TryGetValue(routeKey, out var routeValue))
{
return false;
}
var routeValueString = Convert.ToString(routeValue, CultureInfo.InvariantCulture);
if (routeValueString is null)
{
return false;
}
return _regex.IsMatch(routeValueString);
}
}
Warning
När du använder System.Text.RegularExpressions för att bearbeta ej betrodda indata skickar du en timeout. En obehörig användare kan ange indata för att RegularExpressions orsaka en Denial-of-Service-attack. ASP.NET Core Frameworks API som använder RegularExpressions har en timeout.
Föregående kod:
- Förhindrar
0i{id}segmentet av rutten. - Visas som ett grundläggande exempel på hur du implementerar en anpassad begränsning. Den bör inte användas i en produktionsapp.
Följande kod är en bättre metod för att förhindra att en id innehållande en 0 bearbetas:
[HttpGet("{id}")]
public IActionResult Get(string id)
{
if (id.Contains('0'))
{
return StatusCode(StatusCodes.Status406NotAcceptable);
}
return Content(id);
}
Föregående kod har följande fördelar jämfört med NoZeroesRouteConstraint metoden:
- Det kräver ingen anpassad begränsning.
- Det returnerar ett mer beskrivande fel när vägparametern innehåller
0.
Parametertransformatorer
Parametertransformatorer:
- Utför vid generering av en länk med LinkGenerator.
- Implementera Microsoft.AspNetCore.Routing.IOutboundParameterTransformer.
- Konfigureras med ConstraintMap.
- Ta parameterns vägvärde och omvandla det till ett nytt strängvärde.
- Resulterar i att du använder det transformerade värdet i den genererade länken.
Till exempel, en anpassad slugify-parametertransformator i vägmönster blog\{article:slugify} med Url.Action(new { article = "MyTestArticle" }) genererar blog\my-test-article.
Överväg följande IOutboundParameterTransformer implementering:
public class SlugifyParameterTransformer : IOutboundParameterTransformer
{
public string? TransformOutbound(object? value)
{
if (value is null)
{
return null;
}
return Regex.Replace(
value.ToString()!,
"([a-z])([A-Z])",
"$1-$2",
RegexOptions.CultureInvariant,
TimeSpan.FromMilliseconds(100))
.ToLowerInvariant();
}
}
Om du vill använda en parametertransformator i ett vägmönster konfigurerar du den med hjälp av ConstraintMap i Program.cs:
builder.Services.AddRouting(options =>
options.ConstraintMap["slugify"] = typeof(SlugifyParameterTransformer));
ASP.NET Core-ramverket använder parametertransformatorer för att transformera den URI där en slutpunkt löser problemet. Till exempel transformerar parametertransformatorer de vägvärden som används för att matcha en area, controller, actionoch page:
app.MapControllerRoute(
name: "default",
pattern: "{controller:slugify=Home}/{action:slugify=Index}/{id?}");
Med föregående vägmall matchas åtgärden SubscriptionManagementController.GetAll med URI /subscription-management/get-all:n . En parametertransformator ändrar inte de vägvärden som används för att generera en länk. Till exempel Url.Action("GetAll", "SubscriptionManagement") ger /subscription-management/get-all.
ASP.NET Core tillhandahåller API-konventioner för användning av parametertransformatorer med genererade vägar:
- Microsoft.AspNetCore.Mvc.ApplicationModels.RouteTokenTransformerConvention MVC-konventionen tillämpar en angiven parametertransformator på alla attributvägar i appen. Parametertransformatorn transformerar attributvägstokens eftersom de ersätts. Mer information finns i Använda en parametertransformator för att anpassa tokenbyte.
- Razor Pages använder API-konventionen PageRouteTransformerConvention . Den här konventionen tillämpar en angiven parametertransformator på alla automatiskt identifierade Razor sidor. Parametertransformatoren transformerar mapp- och filnamnssegmenten Razor för Sidvägar. Mer information finns i Använda en parametertransformator för att anpassa sidvägar.
Referens för URL-generering
Det här avsnittet innehåller en referens för algoritmen som implementeras av URL-generering. I praktiken använder de flesta komplexa exempel på URL-generering styrenheter eller Razor sidor. Mer information finns i routning i kontrollanter .
URL-genereringsprocessen börjar med ett anrop till LinkGenerator.GetPathByAddress eller en liknande metod. Metoden tillhandahålls med en adress, en uppsättning vägvärden och eventuellt information om den aktuella begäran från HttpContext.
Det första steget är att använda adressen för att lösa en uppsättning kandidatslutpunkter med hjälp av en IEndpointAddressScheme<TAddress> som matchar adressens typ.
När uppsättningen kandidater hittas av adressschemat sorteras slutpunkterna och bearbetas iterativt tills en URL-genereringsåtgärd lyckas. URL-genereringen söker inte efter tvetydigheter. Det första resultatet som returneras är slutresultatet.
Felsöka URL-generering med loggning
Det första steget i felsökning av URL-generering för Microsoft.AspNetCore.Routing är att ställa in loggningsnivån till TRACE.
LinkGenerator loggar många detaljer om bearbetningen som kan vara användbar för att felsöka problem.
Mer information om URL-generering finns i REFERENS för URL-generering .
Addresses
Adresser är det begrepp i URL-generering som används för att binda ett anrop till länkgeneratorn till en uppsättning kandidatslutpunkter.
Adresser är ett utökningsbart begrepp som levereras med två implementeringar som standard:
- Använda slutpunktsnamnet (
string) som adress:- Tillhandahåller liknande funktioner som MVC:s routningsnamn.
- IEndpointNameMetadata Använder metadatatypen.
- Löser den angivna strängen mot metadata för alla registrerade slutpunkter.
- Utlöser ett undantag vid start om flera slutpunkter använder samma namn.
- Rekommenderas för generell användning utanför kontrollanter och Razor sidor.
- Använda vägvärden (RouteValuesAddress) som adress:
- Ger liknande funktioner som kontroller och äldre URL-generering för sidor.
- Mycket komplext att utöka och felsöka.
- Tillhandahåller implementeringen som används av
IUrlHelper, Tag Helpers, HTML-hjälpare, åtgärdsresultat osv.
Adressschemats roll är att göra associationen mellan adressen och matchande slutpunkter enligt godtyckliga kriterier:
- Slutpunktsnamnschemat utför en grundläggande ordlistesökning.
- Routningsvärdena har en komplex bästa delmängd av set-algoritmen.
Omgivande värden och explicita värden
Från den aktuella begäran får routning åtkomst till routningsvärdena för den aktuella begäran HttpContext.Request.RouteValues. De värden som är associerade med den aktuella begäran kallas för omgivande värden. För tydlighetens skull refererar dokumentationen till de vägvärden som skickas in till metoder som explicita värden.
I följande exempel visas omgivande värden och explicita värden. Den innehåller omgivande värden från den aktuella begäran och explicita värden:
public class WidgetController : ControllerBase
{
private readonly LinkGenerator _linkGenerator;
public WidgetController(LinkGenerator linkGenerator) =>
_linkGenerator = linkGenerator;
public IActionResult Index()
{
var indexPath = _linkGenerator.GetPathByAction(
HttpContext, values: new { id = 17 })!;
return Content(indexPath);
}
// ...
Föregående kod:
- Returnerar
/Widget/Index/17 - Hämtar LinkGenerator via DI.
Följande kod innehåller endast explicita värden och inga omgivande värden:
var subscribePath = _linkGenerator.GetPathByAction(
"Subscribe", "Home", new { id = 17 })!;
Föregående metod returnerar /Home/Subscribe/17
Följande kod i WidgetController returnerar /Widget/Subscribe/17:
var subscribePath = _linkGenerator.GetPathByAction(
HttpContext, "Subscribe", null, new { id = 17 });
Följande kod tillhandahåller kontrollern från omgivande och explicita värden i den aktuella begäran.
public class GadgetController : ControllerBase
{
public IActionResult Index() =>
Content(Url.Action("Edit", new { id = 17 })!);
}
I koden ovan:
-
/Gadget/Edit/17returneras. - Url hämtar IUrlHelper.
-
Action genererar en URL med en absolut sökväg för en åtgärdsmetod. URL:en innehåller det angivna
actionnamnet ochroutevärdena.
Följande kod innehåller omgivande värden från den aktuella begäran och explicita värden:
public class IndexModel : PageModel
{
public void OnGet()
{
var editUrl = Url.Page("./Edit", new { id = 17 });
// ...
}
}
Den föregående koden sätter url till /Edit/17 när Redigera Razor Sida innehåller följande siddirektiv:
@page "{id:int}"
Om sidan Redigera inte innehåller "{id:int}"-routemallen, är url/Edit?id=17.
Beteendet för MVC lägger IUrlHelper till ett lager av komplexitet utöver de regler som beskrivs här:
-
IUrlHelpertillhandahåller alltid vägvärdena från den aktuella begäran som omgivande värden. -
IUrlHelper.Action kopierar alltid aktuella
actionvärden ochcontrollervägvärden som explicita värden om de inte åsidosätts av utvecklaren. -
IUrlHelper.Page kopierar alltid det aktuella
pagevägvärdet som ett explicit värde om det inte åsidosätts. -
IUrlHelper.Pageåsidosätter alltid det aktuellahandlerruttvärdet mednullsom ett explicit värde såvida det inte åsidosätts.
Användarna blir ofta förvånade över beteendeinformationen för omgivande värden, eftersom MVC inte verkar följa sina egna regler. Av historiska och kompatibilitetsskäl har vissa routningsvärden som action, controller, pageoch handler ett eget specialfallsbeteende.
Motsvarande funktionalitet som tillhandahålls av LinkGenerator.GetPathByAction och LinkGenerator.GetPathByPage duplicerar dessa avvikelser i IUrlHelper för kompatibilitet.
Process för URL-generering
När uppsättningen kandidatslutpunkter hittas, algoritmen för URL-generering:
- Bearbetar slutpunkterna iterativt.
- Returnerar det första lyckade resultatet.
Det första steget i den här processen kallas ogiltigförklarande av routningsvärden. Ogiltigförklaring av routningsvärden är den process genom vilken routning avgör vilka routningsvärden från bakgrundsvärden som ska användas och vilka som ska ignoreras. Varje omgivande värde beaktas och kombineras antingen med explicita värden eller ignoreras.
Det bästa sättet att förstå rollen av omgivande värden är att de försöker spara skrivande för programutvecklare i vissa vanliga situationer. Traditionellt är scenarier där omgivande värden är användbara relaterade till MVC:
- När du länkar till en annan åtgärd i samma kontrollant behöver inte kontrollantnamnet anges.
- När du länkar till en annan kontrollant i samma område behöver du inte ange områdesnamnet.
- När du länkar till samma åtgärdsmetod behöver du inte ange vägvärden.
- När du länkar till en annan del av appen vill du inte överföra routningsvärden som inte har någon betydelse i den delen av appen.
Anrop till LinkGenerator eller IUrlHelper som returnerar null orsakas vanligtvis av bristande förståelse av ogiltigförklaring av routningsvärden. Felsöka routningsvärdets ogiltighet genom att uttryckligen ange fler av vägvärdena för att se om det löser problemet.
Ogiltigförklaring av routvärden bygger på antagandet att appens URL-schema är hierarkiskt, med en hierarki som bildas från vänster till höger. Överväg den grundläggande mallen för styrenhetsroutning {controller}/{action}/{id?} för att få en intuitiv uppfattning om hur detta fungerar i praktiken. En ändring av ett värde ogiltigförklarar alla vägvärden som visas till höger. Detta återspeglar antagandet om hierarki. Om appen har ett omgivande värde för id, och åtgärden anger ett annat värde för controller:
-
idåteranvänds inte eftersom{controller}är till vänster om{id?}.
Några exempel som visar den här principen:
- Om de explicita värdena innehåller ett värde för
idignoreras det omgivande värdet förid. Omgivande värden förcontrollerochactionkan användas. - Om de explicita värdena innehåller ett värde för
actionignoreras alla omgivande värden föraction. Omgivningsvärdena förcontrollerkan användas. Om det explicita värdet föractionskiljer sig från det omgivande värdet föractionidanvänds inte värdet. Om det tydliga värdet föractionär detsamma som det omgivande värdet föraction, kanidvärdet användas. - Om de explicita värdena innehåller ett värde för
controllerignoreras alla omgivande värden förcontroller. Om det explicita värdet förcontrollerskiljer sig från det omgivande värdet förcontrolleractionanvänds inte värdena ochid. Om det explicita värdet förcontrollerär detsamma som det omgivande värdet förcontrolleractionkan värdena ochidanvändas.
Den här processen kompliceras ytterligare av förekomsten av attributvägar och dedikerade konventionella vägar. Styrenheters konventionella vägar som {controller}/{action}/{id?} specificerar en hierarki med hjälp av ruttparametrar. För dedikerade konventionella vägar och attributvägar till styrningar och Razor sidor:
- Det finns en hierarki med vägvärden.
- De visas inte i mallen.
I dessa fall definierar URL-generering det nödvändiga värdekonceptet . Slutpunkter som skapats av kontrollanter och Razor sidor har angivna värden som gör att vägvärdets ogiltighet kan fungera.
Ruttvärdets ogiltighetsalgoritm förklarad:
- De nödvändiga värdenamnen kombineras med vägparametrarna och bearbetas sedan från vänster till höger.
- För varje parameter jämförs det omgivande värdet och det explicita värdet:
- Om det omgivande värdet och det explicita värdet är samma fortsätter processen.
- Om det omgivande värdet finns och det explicita värdet inte är det används det omgivande värdet när URL:en genereras.
- Om det omgivande värdet inte finns och det explicita värdet är avvisar du det omgivande värdet och alla efterföljande omgivande värden.
- Om det omgivande värdet och det explicita värdet finns, och de två värdena är olika, avvisar du det omgivande värdet och alla efterföljande omgivande värden.
I det här läget är URL-genereringsåtgärden redo att utvärdera routningsbegränsningar. Uppsättningen godkända värden kombineras med parameterns standardvärden, vilka tillhandahålls för begränsningar. Om alla begränsningar uppfylls fortsätter operationen.
Därefter kan de godkända värdena användas för att expandera routningsmallen. Vägmallen bearbetas:
- Från vänster till höger.
- Varje parameter har sitt godkända värde ersatt.
- Med följande specialfall:
- Om de godkända värdena saknar ett värde och parametern har ett standardvärde används standardvärdet.
- Om de godkända värdena saknar ett värde och parametern är valfri fortsätter bearbetningen.
- Om en routningsparameter till höger om en valfri parameter som saknas har ett värde misslyckas åtgärden.
- Sammanhängande standardvärdeparametrar och valfria parametrar komprimeras där det är möjligt.
Värden som uttryckligen anges som inte matchar ett segment av vägen läggs till i frågesträngen. Följande tabell visar resultatet när du använder routningsmallen {controller}/{action}/{id?}.
| Omgivande värden | Explicita värden | Result |
|---|---|---|
| controller = "Home" | action = "Om" | /Home/About |
| controller = "Home" | controller = "Beställning", action = "Om" | /Order/About |
| controller = "Home", color = "Röd" | action = "Om" | /Home/About |
| controller = "Home" | action = "Om", color = "Röd" | /Home/About?color=Red |
Problem med att routningsvärdet är ogiltigt
Följande kod visar ett exempel på ett URL-genereringsschema som inte stöds av routning:
app.MapControllerRoute(
"default",
"{culture}/{controller=Home}/{action=Index}/{id?}");
app.MapControllerRoute(
"blog",
"{culture}/{**slug}",
new { controller = "Blog", action = "ReadPost" });
I föregående kod culture används routningsparametern för lokalisering. Önskan är att parametern culture alltid ska accepteras som ett omgivande värde. Parametern culture accepteras dock inte som ett omgivande värde på grund av hur nödvändiga värden fungerar:
- I routningsmallen
"default"är routningsparameternculturetill vänster omcontroller, så ändringar i kommer inte attcontrollerogiltigförklaraculture. -
"blog"I vägmallencultureanses vägparametern vara till höger omcontroller, som visas i de obligatoriska värdena.
Parsa URL-sökvägar med LinkParser
Klassen LinkParser lägger till stöd för att parsa en URL-sökväg till en uppsättning vägvärden. Metoden ParsePathByEndpointName tar ett slutpunktsnamn och en URL-sökväg och returnerar en uppsättning vägvärden som extraherats från URL-sökvägen.
I följande exempelkontrollant använder åtgärden GetProduct en routningsmall med api/Products/{id} och har en Name av GetProduct:
[ApiController]
[Route("api/[controller]")]
public class ProductsController : ControllerBase
{
[HttpGet("{id}", Name = nameof(GetProduct))]
public IActionResult GetProduct(string id)
{
// ...
I samma kontrollantklass AddRelatedProduct förväntar sig åtgärden en URL-sökväg, , pathToRelatedProductsom kan anges som en frågesträngsparameter:
[HttpPost("{id}/Related")]
public IActionResult AddRelatedProduct(
string id, string pathToRelatedProduct, [FromServices] LinkParser linkParser)
{
var routeValues = linkParser.ParsePathByEndpointName(
nameof(GetProduct), pathToRelatedProduct);
var relatedProductId = routeValues?["id"];
// ...
I föregående exempel extraherar AddRelatedProduct åtgärden id ruttvärdet från URL-sökvägen. Till exempel, med en URL-sökväg på /api/Products/1, är värdet på relatedProductId inställt till 1. Med den här metoden kan API:ets klienter använda URL-sökvägar när de refererar till resurser, utan att behöva veta hur en sådan URL är strukturerad.
Konfigurera slutpunktsmetadata
Följande länkar innehåller information om hur du konfigurerar slutpunktsmetadata:
- Aktivera Cors med slutpunktsroutning
-
Exempel på IAuthorizationPolicyProvider med ett anpassat
[MinimumAgeAuthorize]attribut - Testa autentisering med attributet [Auktorisera]
- RequireAuthorization
- Välja schemat med attributet [Auktorisera]
- Tillämpa principer med attributet [Auktorisera]
- Rollbaserad auktorisering i ASP.NET Core
Värdmatchning i rutter med RequireHost
RequireHost tillämpar en begränsning på den rutt som kräver den angivna värden. Parametern RequireHost eller [Värd] kan vara en:
- Värd:
www.domain.com, matcharwww.domain.commed valfri port. - Värd med jokertecken:
*.domain.com, matcharwww.domain.com,subdomain.domain.com, ellerwww.subdomain.domain.compå valfri port. - Port:
*:5000, matchar port 5000 med valfri värd. - Värd och port:
www.domain.com:5000eller*.domain.com:5000, matchar värd och port.
Flera parametrar kan anges med RequireHost eller [Host]. Villkoret matchar värdar som är giltiga för någon av parametrarna. Matchar till exempel [Host("domain.com", "*.domain.com")], domain.com, www.domain.com, och subdomain.domain.com.
Följande kod använder RequireHost för att kräva den angivna värden på rutten:
app.MapGet("/", () => "Contoso").RequireHost("contoso.com");
app.MapGet("/", () => "AdventureWorks").RequireHost("adventure-works.com");
app.MapHealthChecks("/healthz").RequireHost("*:8080");
Följande kod använder [Host] attributet på kontrollanten för att kräva någon av de angivna värdarna:
[Host("contoso.com", "adventure-works.com")]
public class HostsController : Controller
{
public IActionResult Index() =>
View();
[Host("example.com")]
public IActionResult Example() =>
View();
}
[Host] När attributet tillämpas på både kontrollanten och åtgärdsmetoden:
- Attributet för åtgärden används.
- Kontrollantattributet ignoreras.
Prestandavägledning för routning
När en app har prestandaproblem misstänks routning ofta vara problemet. Anledningen till att routning misstänks är att ramverk som kontrollers och Razor Pages rapporterar hur lång tid som spenderas inom ramverket i sina loggningsmeddelanden. När det finns en betydande skillnad mellan den tid som rapporteras av kontrollanter och den totala tiden för begäran:
- Utvecklare eliminerar sin appkod som källa till problemet.
- Det är vanligt att anta att routning är orsaken.
Routning är prestandatestad med tusentals slutpunkter. Det är osannolikt att en typisk app kommer att stöta på ett prestandaproblem bara genom att vara för stor. Den vanligaste grundorsaken till långsamma routningsprestanda är vanligtvis ett dåligt fungerande anpassad middleware.
Följande kodexempel visar en grundläggande teknik för att begränsa fördröjningskällan:
var logger = app.Services.GetRequiredService<ILogger<Program>>();
app.Use(async (context, next) =>
{
var stopwatch = Stopwatch.StartNew();
await next(context);
stopwatch.Stop();
logger.LogInformation("Time 1: {ElapsedMilliseconds}ms", stopwatch.ElapsedMilliseconds);
});
app.UseRouting();
app.Use(async (context, next) =>
{
var stopwatch = Stopwatch.StartNew();
await next(context);
stopwatch.Stop();
logger.LogInformation("Time 2: {ElapsedMilliseconds}ms", stopwatch.ElapsedMilliseconds);
});
app.UseAuthorization();
app.Use(async (context, next) =>
{
var stopwatch = Stopwatch.StartNew();
await next(context);
stopwatch.Stop();
logger.LogInformation("Time 3: {ElapsedMilliseconds}ms", stopwatch.ElapsedMilliseconds);
});
app.MapGet("/", () => "Timing Test.");
För att schemalägga dirigeringen:
- Alternativt infoga mellanprogrammen med en kopia av tidsmellanprogrammet som visas i föregående kod.
- Lägg till en unik identifierare för att korrelera tidsdata med koden.
Det här är ett grundläggande sätt att begränsa fördröjningen när den är betydande, till exempel mer än 10ms. Subtrahera Time 2 från Time 1 rapporterar tiden som spenderats i UseRouting mellanprogrammet.
Följande kod använder en mer kompakt metod för föregående tidskod:
public sealed class AutoStopwatch : IDisposable
{
private readonly ILogger _logger;
private readonly string _message;
private readonly Stopwatch _stopwatch;
private bool _disposed;
public AutoStopwatch(ILogger logger, string message) =>
(_logger, _message, _stopwatch) = (logger, message, Stopwatch.StartNew());
public void Dispose()
{
if (_disposed)
{
return;
}
_logger.LogInformation("{Message}: {ElapsedMilliseconds}ms",
_message, _stopwatch.ElapsedMilliseconds);
_disposed = true;
}
}
var logger = app.Services.GetRequiredService<ILogger<Program>>();
var timerCount = 0;
app.Use(async (context, next) =>
{
using (new AutoStopwatch(logger, $"Time {++timerCount}"))
{
await next(context);
}
});
app.UseRouting();
app.Use(async (context, next) =>
{
using (new AutoStopwatch(logger, $"Time {++timerCount}"))
{
await next(context);
}
});
app.UseAuthorization();
app.Use(async (context, next) =>
{
using (new AutoStopwatch(logger, $"Time {++timerCount}"))
{
await next(context);
}
});
app.MapGet("/", () => "Timing Test.");
Potentiellt dyra routningsfunktioner
Följande lista ger en inblick i routningsfunktioner som är relativt dyra jämfört med grundläggande routningsmallar:
- Reguljära uttryck: Det går att skriva reguljära uttryck som är komplexa eller har lång körningstid med en liten mängd indata.
- Komplicerade segment (
{x}-{y}-{z}):- Är betydligt dyrare än att parsa ett vanligt URL-sökvägssegment.
- Resulterar i att många fler delsträngar kommer att allokeras.
- Synkron dataåtkomst: Många komplexa appar har databasåtkomst som en del av routningen. Använd utökningspunkter som MatcherPolicy och EndpointSelectorContext, som är asynkrona.
Vägledning för stora routningstabeller
Som standard använder ASP.NET Core en routningsalgoritm som byter minne mot CPU-tid. Detta har den fina effekten att vägmatchningstiden endast beror på längden på sökvägen som ska matchas och inte antalet vägar. Den här metoden kan dock vara potentiellt problematisk i vissa fall, när appen har ett stort antal vägar (i tusental) och det finns en hög mängd variabelprefix i vägarna. Om rutterna har parametrar i tidiga segment av rutten, som {parameter}/some/literal.
Det är osannolikt att en app stöter på en situation där detta är ett problem om inte:
- Det finns ett stort antal vägar i appen med det här mönstret.
- Det finns ett stort antal vägar i appen.
Så här avgör du om en app stöter på problemet med den stora routningstabellen
- Det finns två symptom att leta efter:
- Appen startar långsamt vid första användningen.
- Observera att detta är obligatoriskt men inte tillräckligt. Det finns många andra problem som inte är routningsproblem än vad som kan orsaka långsam appstart. Kontrollera om villkoret nedan är korrekt för att fastställa att appen körs i den här situationen.
- Appen förbrukar mycket minne under starten och en minnesdump visar ett stort antal
Microsoft.AspNetCore.Routing.Matching.DfaNodeinstanser.
- Appen startar långsamt vid första användningen.
Så här åtgärdar du det här problemet
Det finns flera tekniker och optimeringar som kan tillämpas på vägar som till stor del förbättrar det här scenariot:
- Tillämpa routningsbegränsningar på dina parametrar, till exempel
{parameter:int},{parameter:guid},{parameter:regex(\\d+)}osv. där det är möjligt.- På så sätt kan routningsalgoritmen internt optimera de strukturer som används för matchning och drastiskt minska det minne som används.
- I de allra flesta fall räcker detta för att återgå till ett acceptabelt beteende.
- Ändra vägarna för att flytta parametrar till senare segment i mallen.
- Detta minskar antalet möjliga "vägar" för att matcha en slutpunkt med en given väg.
- Använd en dynamisk rutt och utför mappningen till en kontroller/sida dynamiskt.
- Detta kan uppnås med hjälp av
MapDynamicControllerRouteochMapDynamicPageRoute.
- Detta kan uppnås med hjälp av
Vägledning för biblioteksförfattare
Det här avsnittet innehåller vägledning för biblioteksförfattare som bygger ovanpå routning. Den här informationen är avsedd att säkerställa att apputvecklare har en bra upplevelse med hjälp av bibliotek och ramverk som utökar routningen.
Definiera slutpunkter
Om du vill skapa ett ramverk som använder routning för URL-matchning börjar du med att definiera en användarupplevelse som bygger ovanpå UseEndpoints.
BYGG ovanpå IEndpointRouteBuilder. På så sätt kan användarna skapa ditt ramverk med andra ASP.NET Core-funktioner utan förväxling. Varje ASP.NET Core-mall innehåller routning. Anta att routning är närvarande och bekant för användare.
// Your framework
app.MapMyFramework(...);
app.MapHealthChecks("/healthz");
Returnera en förseglad betongtyp från ett anrop till MapMyFramework(...) som implementerar IEndpointConventionBuilder. De flesta ramverksmetoder Map... följer det här mönstret. Gränssnittet IEndpointConventionBuilder :
- Tillåter att metadata skapas.
- Är mål för en mängd olika tilläggsmetoder.
Om du deklarerar din egen typ kan du lägga till dina egna ramverksspecifika funktioner i byggaren. Det är okej att omsluta ett ramverksdeklarerat byggobjekt och vidarebefordra anrop till det.
// Your framework
app.MapMyFramework(...)
.RequireAuthorization()
.WithMyFrameworkFeature(awesome: true);
app.MapHealthChecks("/healthz");
ÖVERVÄG att skriva din egen EndpointDataSource.
EndpointDataSource är en grundläggande konstruktion för att deklarera och uppdatera en samling slutpunkter.
EndpointDataSource är ett kraftfullt API som används av kontrollanter och Razor sidor.
Routningstesterna har ett grundläggande exempel på en datakälla som inte uppdateras.
Försök INTE att registrera en EndpointDataSource som standard. Kräv att användare registrerar ditt ramverk i UseEndpoints. Routningsfilosofin är att ingenting ingår som standard, och det UseEndpoints är platsen där slutpunkter ska registreras.
Skapa routningsintegrerade mellanprogram
ÖVERVÄG att definiera metadatatyper som ett gränssnitt.
Gör det möjligt att använda metadatatyper som ett attribut för klasser och metoder.
public interface ICoolMetadata
{
bool IsCool { get; }
}
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
public class CoolMetadataAttribute : Attribute, ICoolMetadata
{
public bool IsCool => true;
}
Ramverk som kontrollanter och Razor sidor stöder tillämpning av metadataattribut på typer och metoder. Om du deklarerar metadatatyper:
- Gör dem tillgängliga som attribut.
- De flesta användare är bekanta med att tillämpa attribut.
Om du deklarerar en metadatatyp som ett gränssnitt läggs ett annat flexibelt lager till:
- Gränssnitt är sammansättningsbara.
- Utvecklare kan deklarera sina egna typer som kombinerar flera principer.
Gör det möjligt att åsidosätta metadata, som du ser i följande exempel:
[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() { }
}
Det bästa sättet att följa dessa riktlinjer är att undvika att definiera markörmetadata:
- Leta inte bara efter förekomsten av en metadatatyp.
- Definiera en egenskap för metadata och kontrollera egenskapen.
Metadatasamlingen är ordnad och möjliggör att överskrida efter prioritet. När det gäller kontrollanter är metadata för åtgärdsmetoden mest specifika.
Gör mellanprogram användbara med och utan routning:
app.UseAuthorization(new AuthorizationPolicy() { ... });
// Your framework
app.MapMyFramework(...).RequireAuthorization();
Som ett exempel på den här riktlinjen bör du överväga UseAuthorization mellanprogrammet. Med mellanprogrammet för auktorisering kan du ange en reservpolicy.
Om den anges, gäller återställningsprincipen för båda:
- Slutpunkter utan en angiven policy.
- Begäranden som inte överensstämmer med en slutpunkt.
Detta gör auktoriseringsmellanprogrammet användbart utanför routningskontexten. Mellanprogrammet för auktorisering kan användas för traditionell mellanprogramprogrammering.
Felsökningsdiagnostik
För detaljerade routningsdiagnostikutdata anger du Logging:LogLevel:Microsoft till Debug. I utvecklingsmiljön anger du loggnivån i appsettings.Development.json:
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Debug",
"Microsoft.Hosting.Lifetime": "Information"
}
}
}
Ytterligare resurser
Routning ansvarar för att matcha inkommande HTTP-begäranden och skicka dessa begäranden till appens körbara slutpunkter. Slutpunkter är appens enheter för körbar kod för hantering av begäranden. Slutpunkter definieras i appen och konfigureras när appen startas. Slutpunktsmatchningsprocessen kan extrahera värden från begärans URL och ange dessa värden för bearbetning av begäranden. Med hjälp av slutpunktsinformation från appen kan routning också generera URL:er som mappar till slutpunkter.
Appar kan konfigurera routning med hjälp av:
- Controllers
- Razor sidor
- SignalR
- gRPC-tjänster
- Slutpunktsaktiverat mellanprogram , till exempel hälsokontroller.
- Delegater och lambdas som registrerats med routning.
Det här dokumentet beskriver information på låg nivå om ASP.NET Core-routning. Information om hur du konfigurerar routning:
- För kontrollanter, se Routning till kontrollantåtgärder i ASP.NET Core.
- För Razor Sidor-konventioner, se Razor Sidor rout- och appkonventioner i ASP.NET Core.
Slutpunktsroutningssystemet som beskrivs i det här dokumentet gäller för ASP.NET Core 3.0 eller senare. Om du vill ha information om det tidigare routningssystemet baserat på IRouterväljer du ASP.NET Core 2.1-versionen med någon av följande metoder:
- Versionsväljaren för en tidigare version.
- Välj ASP.NET Core 2.1-routning.
Visa eller ladda ned exempelkod (hur du laddar ned)
Nedladdningsexemplen för det här dokumentet aktiveras av en specifik Startup klass. Om du vill köra ett specifikt exempel ändrar du Program.cs för att anropa önskad Startup klass.
Grunderna för routning
Alla ASP.NET Core-mallar inkluderar routning i den genererade koden. Routning registreras i middleware-pipelinen i Startup.Configure.
Följande kod visar ett grundläggande exempel på routning:
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!");
});
});
}
Routning använder ett par mellanprogram, registrerade av UseRouting och UseEndpoints:
-
UseRoutinglägger till routningsmatchning till pipelinen för mellanprogram. Det här mellanprogrammet tittar på den uppsättning slutpunkter som definierats i appen och väljer den bästa matchningen baserat på begäran. -
UseEndpointslägger till slutpunktskörning i pipelinen för mellanprogram. Den kör delegeringen som är kopplad till den valda slutpunkten.
Föregående exempel innehåller en enda väg till kodslutpunkten med metoden MapGet :
- När en HTTP-begäran
GETskickas till rot-URL:en/:- Delegeringen för begäran som visas utförs.
-
Hello World!skrivs till HTTP-svaret. Som standard är rot-URL:en/ärhttps://localhost:5001/.
- Om begärandemetoden inte är
GETeller om rot-URL:en inte är/, matchar ingen rutt och en HTTP 404 returneras.
Endpoint
Metoden MapGet används för att definiera en slutpunkt. En slutpunkt är något som kan vara:
- Vald genom att matcha URL:en och HTTP-metoden.
- Utförs genom att köra delegeringen.
Ändpunkter som kan matchas och köras av appen konfigureras i UseEndpoints. Till exempel ansluter MapGet, MapPost och liknande metoder förbinder ombud för begäranden till routningssystemet. Ytterligare metoder kan användas för att ansluta ASP.NET Core Framework-funktioner till routningssystemet:
- MapRazorPages för Razor sidor
- MapControllers för styrenheter
- MapHub<THub> för SignalR
- MapGrpcService<TService> för gRPC
I följande exempel visas routning med en mer avancerad vägmall:
app.UseEndpoints(endpoints =>
{
endpoints.MapGet("/hello/{name:alpha}", async context =>
{
var name = context.Request.RouteValues["name"];
await context.Response.WriteAsync($"Hello {name}!");
});
});
Strängen /hello/{name:alpha} är en vägmall. Den används för att konfigurera hur slutpunkten matchas. I det här fallet matchar mallen:
- En URL som
/hello/Ryan - Alla URL-sökvägar som börjar med
/hello/följt av en sekvens med alfabetiska tecken.:alphatillämpar en vägbegränsning som endast matchar alfabetiska tecken. Routningsbegränsningar beskrivs senare i det här dokumentet.
Det andra segmentet i URL-sökvägen: {name:alpha}
- Är bunden till parametern
name. - Samlas in och lagras i HttpRequest.RouteValues.
Slutpunktsroutningssystemet som beskrivs i det här dokumentet är nytt från och med ASP.NET Core 3.0. Alla versioner av ASP.NET Core stöder dock samma uppsättning routningsmallsfunktioner och routningsbegränsningar.
I följande exempel visas routning med hälsokontroller och auktorisering:
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!");
});
});
}
Om du vill se kodkommentar översatta till andra språk än engelska kan du meddela oss i det här GitHub-diskussionsproblemet.
Föregående exempel visar hur:
- Mellanprogrammet för auktorisering kan användas med routning.
- Slutpunkter kan användas för att konfigurera auktoriseringsbeteende.
Anropet MapHealthChecks lägger till en slutpunkt för hälsokontroll. Länkning RequireAuthorization till det här anropet kopplar en auktoriseringsprincip till slutpunkten.
Anropar UseAuthentication och UseAuthorization lägger till mellanprogrammet för autentisering och auktorisering. Dessa mellanprogram placeras mellan UseRouting och UseEndpoints så att de kan:
- Se vilken slutpunkt som har valts av
UseRouting. - Tillämpa en auktoriseringsprincip innan UseEndpoints skickas till slutpunkten.
Slutpunktsmetadata
I föregående exempel finns det två slutpunkter, men endast slutpunkten för hälsokontroll har en auktoriseringsprincip kopplad. Om begäran matchar slutpunkten /healthzför hälsokontroll utförs en auktoriseringskontroll. Detta visar att slutpunkter kan ha extra data kopplade till sig. Dessa extra data kallas slutpunktsmetadata:
- Metadata kan bearbetas av routningsmedvetna mellanprogram.
- Metadata kan vara av valfri .NET-typ.
Routningsbegrepp
Routningssystemet bygger på pipelinen för mellanprogram genom att lägga till det kraftfulla slutpunktskonceptet . Slutpunkter representerar enheter i appens funktioner som skiljer sig från varandra när det gäller routning, auktorisering och valfritt antal ASP.NET Core-system.
ASP.NET Core-slutpunktsdefinition
En ASP.NET Core-slutpunkt är:
- Körbar: Har en RequestDelegate.
- Utökningsbar: Har en metadatasamling .
- Valbar: Om du vill kan du ha routningsinformation.
- Uppräkningsbar: Samlingen med slutpunkter kan visas genom att EndpointDataSource hämta från DI.
Följande kod visar hur du hämtar och inspekterar slutpunkten som matchar den aktuella begäran:
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!");
});
});
}
Slutpunkten, om den är markerad, kan hämtas från HttpContext. Dess egenskaper kan inspekteras. Slutpunktsobjekt är oföränderliga och kan inte ändras när de har skapats. Den vanligaste typen av slutpunkt är en RouteEndpoint.
RouteEndpoint innehåller information som gör att den kan väljas av routningssystemet.
I föregående kod, app. Använd konfigurerar ett infogat mellanprogram.
Följande kod visar att det, beroende på var app.Use som anropas i pipelinen, kanske inte finns någon slutpunkt:
// 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);
});
Det här föregående exemplet lägger till Console.WriteLine instruktioner som visar om en slutpunkt har valts eller inte. För tydlighetens skull tilldelar exemplet ett visningsnamn till den angivna / slutpunkten.
Kör den här koden med en URL på / visar:
1. Endpoint: (null)
2. Endpoint: Hello
3. Endpoint: Hello
Om du kör den här koden med andra URL:ar visas:
1. Endpoint: (null)
2. Endpoint: (null)
4. Endpoint: (null)
Dessa utdata visar att:
- Slutpunkten är alltid null innan
UseRoutinganropas. - Om en matchning hittas är slutpunkten inte null mellan
UseRoutingoch UseEndpoints. - Mellanprogrammet
UseEndpointsär terminal när en matchning hittas. Terminalmellanprogram definieras senare i det här dokumentet. - Mellanprogrammet efter
UseEndpointskörs endast när ingen matchning hittas.
Mellanprogrammet UseRouting använder metoden SetEndpoint för att koppla slutpunkten till den aktuella kontexten. Det går att ersätta UseRouting mellanprogrammet med anpassad logik och ändå få fördelarna med att använda slutpunkter. Ändpunkter är ett grundläggande element på låg nivå som mellanvaror och är inte kopplade till routningens implementering. De flesta appar behöver inte ersättas UseRouting med anpassad logik.
Mellanprogrammet UseEndpoints är utformat för att användas tillsammans med UseRouting mellanprogrammet. Kärnlogiken för att utföra en slutpunkt är inte komplicerad. Använd GetEndpoint för att hämta slutpunkten och anropa sedan dess RequestDelegate egenskap.
Följande kod visar hur mellanprogram kan påverka eller reagera på routning:
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; }
}
Föregående exempel visar två viktiga begrepp:
- Mellanprogram kan köras tidigare
UseRoutingför att ändra de data som routningen körs på.- Vanligtvis ändrar mellanprogram som visas innan routning någon egenskap för begäran, till exempel UseRewriter, UseHttpMethodOverrideeller UsePathBase.
- Mellanprogram kan köras mellan
UseRoutingoch UseEndpoints för att bearbeta resultatet av routingen innan slutpunkten körs.- Mellanprogram som körs mellan
UseRoutingochUseEndpoints:- Inspekterar vanligtvis metadata för att förstå slutpunkterna.
- Fattar ofta säkerhetsbeslut, som görs av
UseAuthorizationochUseCors.
- Kombinationen av mellanprogram och metadata gör det möjligt att konfigurera principer per slutpunkt.
- Mellanprogram som körs mellan
Föregående kod visar ett exempel på ett anpassat mellanprogram som stöder principer per slutpunkt. Mellanprogrammet skriver en revisionslogg av åtkomst av känsliga data till konsolen. Mellanprogrammet kan konfigureras för att granska en slutpunkt med AuditPolicyAttribute metadata. Det här exemplet visar ett opt-in-mönster där endast slutpunkter som är markerade som känsliga granskas. Det är möjligt att definiera den här logiken omvänt och granska allt som inte är markerat som säkert, till exempel. Slutpunktsmetadatasystemet är flexibelt. Den här logiken kan utformas på vilket sätt som helst som passar användningsfallet.
Föregående exempelkod är avsedd att demonstrera de grundläggande begreppen för slutpunkter. Exemplet är inte avsett för produktionsanvändning. En mer fullständig version av ett mellanprogram för granskningsloggar skulle:
- Logga in på en fil eller databas.
- Inkludera information som användaren, IP-adressen, namnet på den känsliga slutpunkten med mera.
Metadata för revisionspolicy AuditPolicyAttribute definieras som en Attribute för att enklare kunna använda klassbaserade ramverk som kontroller och SignalR. När du använder route to code:
- Metadata bifogas med ett builder-API.
- Klassbaserade ramverk innehåller alla attribut på motsvarande metod och klass när du skapar slutpunkter.
Metodtipsen för metadatatyper är att definiera dem antingen som gränssnitt eller attribut. Gränssnitt och attribut tillåter återanvändning av kod. Metadatasystemet är flexibelt och medför inga begränsningar.
Jämföra ett terminalmellanprogram och routning
Följande kodexempel jämför användningen av mellanprogram med användningen av routning:
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!");
});
});
}
Formatet för mellanprogram som visas med Approach 1: är terminalmellanprogram. Det kallas terminalmellanprogram eftersom det utför en matchande åtgärd:
- Matchningsåtgärden i föregående exempel är
Path == "/"för mellanprogrammet ochPath == "/Movie"för routning. - När en matchning lyckas, utför den vissa funktioner och returnerar istället för att anropa
next-mellanprogrammet.
Det kallas terminalmellanprogram eftersom det avslutar sökningen, kör vissa funktioner och sedan returnerar.
Jämföra ett terminalmellanprogram och routning:
- Båda metoderna gör det möjligt att avsluta bearbetningspipelinen:
- Mellanprogram avslutar pipelinen genom att returnera i stället för att
nextanropa . - Slutpunkter är alltid terminaler.
- Mellanprogram avslutar pipelinen genom att returnera i stället för att
- Med terminalmellanprogram kan du placera mellanprogrammet på en godtycklig plats i pipelinen:
- Slutpunkter körs på positionen UseEndpoints.
- Med terminalmellanprogram kan godtycklig kod avgöra när mellanprogrammet matchar:
- Anpassad vägmatchningskod kan vara utförlig och svår att skriva korrekt.
- Routning ger enkla lösningar för typiska appar. De flesta appar kräver inte anpassad vägmatchningskod.
- Slutpunktsgränssnitt med mellanprogram som
UseAuthorizationochUseCors.- Användning av ett terminalmellanprogram med
UseAuthorizationellerUseCorskräver manuell koppling med auktoriseringssystemet.
- Användning av ett terminalmellanprogram med
En slutpunkt definierar båda:
- Ett ombud för att bearbeta begäranden.
- En samling godtyckliga metadata. Metadata används för att implementera övergripande problem baserat på principer och konfiguration som är kopplade till varje slutpunkt.
Terminalmellanprogram kan vara ett effektivt verktyg, men kan kräva:
- En betydande mängd kodning och testning.
- Manuell integrering med andra system för att uppnå önskad flexibilitetsnivå.
Överväg att integrera med routning innan du skriver ett terminalmellanprogram.
Befintliga terminalmellanprogram som integreras med Map eller MapWhen kan vanligtvis omvandlas till en routingmedveten slutpunkt. MapHealthChecks visar mönstret för router-ware:
- Skriv en tilläggsmetod på IEndpointRouteBuilder.
- Skapa en pipeline för kapslade mellanprogram med CreateApplicationBuilder.
- Koppla mellanprogrammet till den nya pipelinen. I det här fallet UseHealthChecks.
- Build mellanprogramspipelinen till en RequestDelegate.
- Anropa
Mapoch ange den nya pipelinen för mellanprogram. - Returnera builder-objektet som tillhandahålls av
Mapfrån tilläggsmetoden.
Följande kod visar användning av 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!");
});
});
}
Föregående exempel visar varför det är viktigt att returnera builder-objektet. När byggobjektet returneras kan apputvecklaren konfigurera principer som auktorisering för slutpunkten. I det här exemplet har mellanprogrammet för hälsokontroller ingen direkt integrering med auktoriseringssystemet.
Metadatasystemet skapades som svar på de problem som uppstått av utökningsförfattare med hjälp av terminalmellanprogram. Det är problematiskt för varje mellanprogram att implementera sin egen integrering med auktoriseringssystemet.
URL-matchning
- Är den process genom vilken routningen matchar en inkommande begäran till en slutpunkt.
- Baseras på data i URL-sökvägen och rubrikerna.
- Kan utökas för att överväga alla data i begäran.
När ett routningsmellanprogram körs anger det en Endpoint och dirigerar värden till en begäransfunktion på HttpContext från den aktuella begäran:
- Genom att anropa HttpContext.GetEndpoint hämtas slutpunkten.
-
HttpRequest.RouteValueshämtar samlingen av routvärden.
Mellanprogram körs efter att routningsmellanprogram har möjlighet att inspektera slutpunkten och vidta åtgärder. Till exempel kan ett mellanprogramvara för auktorisering granska och utvärdera slutpunktens metadatasamling för en auktoriseringspolicy. När alla mellanprogram i pipelinen för bearbetning av begäranden har körts anropas den valda slutpunktens ombud.
Routningssystemet i slutpunktsroutningen ansvarar för alla leveransbeslut. Eftersom mellanprogrammet tillämpar principer baserat på den valda slutpunkten är det viktigt att:
- Alla beslut som kan påverka sändningen eller tillämpningen av säkerhetsprinciper fattas i routningssystemet.
Warning
För bakåtkompatibilitet, när en kontroller eller Razor Pages-slutpunktsdelegat körs, anges egenskaperna för RouteContext.RouteData till lämpliga värden baserat på den bearbetning av begäranden som utförts hittills.
Typen RouteContext kommer att markeras som föråldrad i en framtida version:
- Migrera
RouteData.ValuestillHttpRequest.RouteValues. - Migrera
RouteData.DataTokensför att hämta IDataTokensMetadata från slutpunktsmetadata.
URL-matchning fungerar i en konfigurerbar uppsättning faser. I varje fas är utdata en uppsättning matchningar. Mängden matcher kan begränsas ytterligare under nästa fas. Routningsimplementeringen garanterar inte någon bearbetningsordning för matchande slutpunkter. Alla möjliga matchningar bearbetas samtidigt. Url-matchningsfaserna sker i följande ordning. ASP.NET Core:
- Bearbetar URL-sökvägen mot uppsättningen slutpunkter och deras vägmallar och samlar in alla matchningar.
- Tar den föregående listan och tar bort matchningar som inte uppfyller ruttbegränsningar som tillämpas.
- Tar den föregående listan och tar bort matchningar som inte uppfyller kraven i MatcherPolicy-instanser.
- Använder EndpointSelector för att fatta ett slutgiltigt beslut från föregående lista.
Listan över slutpunkter prioriteras enligt:
- RouteEndpoint.Order
- Prioritet för routsmall
Alla matchande ändpunkter bearbetas i varje fas tills den EndpointSelector har nåtts.
EndpointSelector är den sista fasen. Den väljer den högsta prioritetsslutpunkten från matchningarna som den bästa matchningen. Om det finns andra matchningar med samma prioritet som den bästa matchningen, kommer ett tvetydigt matchningsundantag att utlösas.
Routningsprioriteten beräknas baserat på att en mer specifik vägmall får högre prioritet. Tänk till exempel på mallarna /hello och /{message}:
- Båda matchar URL-sökvägen
/hello. -
/helloär mer specifik och därför högre prioritet.
I allmänhet gör routningsprioriteten ett bra jobb med att välja den bästa matchningen för de typer av URL-scheman som används i praktiken. Använd Order endast när det behövs för att undvika tvetydigheter.
På grund av de typer av utökningsbarhet som tillhandahålls av routning är det inte möjligt för routningssystemet att beräkna de tvetydiga vägarna i förväg. Överväg ett exempel som routningsmallarna /{message:alpha} och /{message:int}:
- Villkoret
alphamatchar endast alfabetiska tecken. - Villkoret
intmatchar endast tal. - Dessa mallar har samma vägprioritet, men det finns ingen enskild URL som båda matchar.
- Om routningssystemet rapporterade ett tvetydighetsfel vid starten skulle det blockera det här giltiga användningsfallet.
Warning
Ordningen på åtgärderna i UseEndpoints påverkar inte beteendet för routning, med ett undantag. MapControllerRoute och MapAreaRoute tilldela automatiskt ett ordervärde till sina slutpunkter baserat på den ordning som de anropas. Detta simulerar långvarigt beteende för kontrollanter utan att routningssystemet ger samma garantier som äldre routningsimplementeringar.
I den äldre implementeringen av routning är det möjligt att implementera utökningsbarhet för routning som har ett beroende av i vilken ordning vägar bearbetas. Slutpunktsroutning i ASP.NET Core 3.0 eller senare:
- Har inget begrepp om vägar.
- Ger inte ordergarantier. Alla slutpunkter bearbetas samtidigt.
Routningsmallens prioritet och slutpunktsmarkeringsordning
Prioritet för routningsmallar är ett system som tilldelar varje vägmall ett värde baserat på hur specifik den är. Prioritet för routningsmall:
- Undviker behovet av att justera ordningen på slutpunkter i vanliga fall.
- Försöker matcha allmänna förväntningar på routingbeteende.
Du kan till exempel överväga mallar /Products/List och /Products/{id}. Det är rimligt att anta att det /Products/List är en bättre matchning än /Products/{id} för URL-sökvägen /Products/List. Detta fungerar eftersom literalsegmentet /List anses ha bättre prioritet än parametersegmentet /{id}.
Information om hur prioritet fungerar är kopplat till hur routningsmallar definieras:
- Mallar med fler segment anses vara mer specifika.
- Ett segment med literaltext anses vara mer specifikt än ett parametersegment.
- Ett parametersegment med en begränsning anses vara mer specifikt än ett utan.
- Ett komplext segment anses vara lika specifikt som ett parametersegment med en begränsning.
- Catch-all-parametrar är de minst specifika. Se catch-all i referensen för routningsmallen för viktig information om catch-all-vägar.
Se källkoden på GitHub för en referens till exakta värden.
Begrepp för URL-generering
URL-generering:
- Är den process genom vilken routning kan skapa en URL-sökväg baserat på en uppsättning vägvärden.
- Tillåter en logisk separation mellan slutpunkter och URL:er som har åtkomst till dem.
Slutpunktsroutning innehåller API:et LinkGenerator .
LinkGenerator är en singleton-tjänst som är tillgänglig från DI. API LinkGenerator kan användas utanför kontexten för en exekverande begäran.
Mvc.IUrlHelper och scenarier som förlitar sig på IUrlHelper, till exempel Tag Helpers, HTML Helpers och Action Results, använder API:et LinkGenerator internt för att tillhandahålla funktioner för länkgenerering.
Länkgeneratorn backas upp av begreppet adress - och adressscheman. Ett adressschema är ett sätt att fastställa de slutpunkter som ska beaktas för länkgenerering. Till exempel implementeras scenarier med routningnamn och routvärden som många användare är bekanta med från kontroller och Razor sidor såsom ett adressschema.
Länkgeneratorn kan länka till styrenheter och Razor sidor via följande tilläggsmetoder:
Överbelastningar av dessa metoder tar emot argument som inkluderar HttpContext. Dessa metoder är funktionellt likvärdiga med Url.Action och Url.Page, men ger ytterligare flexibilitet och alternativ.
Metoderna GetPath* liknar Url.Action mest och Url.Page, eftersom de genererar en URI som innehåller en absolut sökväg. Metoderna GetUri* genererar alltid en absolut URI som innehåller ett schema och en värd. De metoder som accepterar en HttpContext genererar en URI i kontexten för den körande begäran. Värden ambienta för väg, URL-bassökväg, protokoll och värd från den körande begäran används om de inte åsidosätts.
LinkGenerator anropas med en adress. Generera en URI sker i två steg:
- En adress är bunden till en lista över slutpunkter som matchar adressen.
- Varje slutpunkts RoutePattern utvärderas tills ett vägmönster som matchar de angivna värdena hittas. Resultatet kombineras med de andra URI-delarna som levereras till länkgeneratorn och returneras.
Metoderna som tillhandahålls av LinkGenerator stöder standardfunktioner för länkgenerering för alla typer av adresser. Det enklaste sättet att använda länkgeneratorn är genom tilläggsmetoder som utför åtgärder för en viss adresstyp:
| Tilläggsmetod | Description |
|---|---|
| GetPathByAddress | Genererar en URI med en absolut sökväg baserat på de angivna värdena. |
| GetUriByAddress | Genererar en absolut URI baserat på de angivna värdena. |
Warning
Var uppmärksam på följande konsekvenser av att anropa LinkGenerator metoder:
Använd
GetUri*tilläggsmetoder med försiktighet i en appkonfiguration som inte validerar headern för inkommande begäranden.HostOm rubriken för inkommande begäranden inte verifieras kan ej betrodda begärandeindata skickas tillbaka till klienten i URI:er i en vy eller sida. Vi rekommenderar att alla produktionsappar konfigurerar sin server för att kontrolleraHostheadern mot kända giltiga värden.Använd LinkGenerator med försiktighet i mellanprogram i kombination med
MapellerMapWhen.Map*ändrar basvägen för den körande begäran, vilket påverkar utdata från länkgenereringen. LinkGenerator Alla API:er tillåter att du anger en bassökväg. Ange en tom bassökväg för att ta bortMap*effekten på länkgenereringen.
Exempel på mellanprogram
I följande exempel använder ett mellanprogram API:et LinkGenerator för att skapa en länk till en åtgärdsmetod som visar lagerprodukter. Använda länkgeneratorn genom att mata in den i en klass och anrop GenerateLink är tillgängligt för alla klasser i en app:
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.");
}
}
Referens för routningsmall
Token inom {} definierar ruttparametrar som är bundna om rutten matchas. Mer än en vägparameter kan definieras i ett vägsegment, men vägparametrarna måste avgränsas med ett literalvärde. Till exempel {controller=Home}{action=Index} är inte en giltig väg, eftersom det inte finns något literalvärde mellan {controller} och {action}. Routningsparametrarna måste ha ett namn och kan ha ytterligare attribut angivna.
Annan literaltext än vägparametrar (till exempel {id}) och sökvägsavgränsaren / måste matcha texten i URL:en. Textmatchning är skiftlägesokänslig och baseras på den avkodade representationen av URL:ens sökväg. Om du vill matcha en literalvägsparameter avgränsare { eller }kan du undvika avgränsare genom att upprepa tecknet. Till exempel {{ eller }}.
Asterisk * eller dubbel asterisk **:
- Kan användas som ett prefix till en vägparameter för att binda till resten av URI:n.
- Kallas för catch-all-parametrar. Till exempel
blog/{**slug}:- Matchar alla URI:er som börjar med
/blogoch har ett värde som följer den. - Värdet som följer efter
/blogtilldelas som värde för slug-routen.
- Matchar alla URI:er som börjar med
Warning
En parameter kan matcha vägar felaktigt på grund av en bugg i routning. Appar som påverkas av den här buggen har följande egenskaper:
- En allomfattande rutt, till exempel
{**slug}" - Catch-all-vägen matchar inte begäranden som den ska matcha.
- Om du tar bort andra rutter börjar den allomfattande rutten att fungera.
Se GitHub-buggar 18677 och 16579 till exempel fall som drabbat den här buggen.
En anmälningskorrigering för den här buggen finns i .NET Core 3.1.301 eller senare SDK. Följande kod anger en intern växel som åtgärdar felet:
public static void Main(string[] args)
{
AppContext.SetSwitch("Microsoft.AspNetCore.Routing.UseCorrectCatchAllBehavior",
true);
CreateHostBuilder(args).Build().Run();
}
// Remaining code removed for brevity.
Catch-all-parametrar kan även matcha den tomma strängen.
Parametern catch-all undflyr lämpliga tecken när vägen används för att generera en URL, inklusive sökvägsavgränsningstecken / . Till exempel genererar rutten foo/{*path} med ruttvärden { path = "my/path" }foo/my%2Fpath. Observera det undantagna snedstrecket. Använd routningsparameterprefixet ** för att avgränsa sökvägens avgränsningstecken. Vägen foo/{**path} med { path = "my/path" } genererar foo/my/path.
URL-mönster som försöker avbilda ett filnamn med ett valfritt filnamnstillägg har ytterligare överväganden. Överväg till exempel mallen files/{filename}.{ext?}. När värden för båda filename och ext finns fylls båda värdena i. Om det bara finns ett värde för filename i URL:en matchar vägen eftersom avslutandet . är valfritt. Följande URL:er matchar den här vägen:
/files/myFile.txt/files/myFile
Routningsparametrar kan ha standardvärden som anges genom att ange standardvärdet efter parameternamnet avgränsat med ett likhetstecken (=). Definierar {controller=Home}Home till exempel som standardvärde för controller. Standardvärdet används om inget värde finns i URL:en för parametern. Routningsparametrar görs valfria genom att ett frågetecken (?) läggs till i slutet av parameternamnet. Till exempel id?. Skillnaden mellan valfria värden och standardvägsparametrar är:
- En routningsparameter med ett standardvärde genererar alltid ett värde.
- En valfri parameter har endast ett värde när ett värde tillhandahålls av begärande-URL:en.
Ruttparametrarna kan ha begränsningar som måste matcha ruttvärdet som är bundet från URL:en. Att lägga till : och villkorsnamn efter namnet på routningsparametern anger en infogad begränsning för en routningsparameter. Om villkoret kräver argument omges de av parenteser (...) efter villkorsnamnet. Du kan ange flera inline-begränsningar genom att lägga till en annan : och ett annat begränsningsnamn.
Villkorsnamnet och argumenten IInlineConstraintResolver skickas till tjänsten för att skapa en instans av IRouteConstraint som ska användas i URL-bearbetning. Routningsmallen blog/{article:minlength(10)} anger till exempel en minlength begränsning med argumentet 10. Mer information om routningsbegränsningar och en lista över de begränsningar som tillhandahålls av ramverket finns i avsnittet Referens för routningsbegränsningar .
Routningsparametrar kan också ha parametertransformatorer. Parametertransformatorer transformerar en parameters värde vid generering av länkar och matchande åtgärder och sidor till URL:er. Precis som begränsningar kan parametertransformatorer läggas till direkt i en routparameter genom att lägga till ett : och ett transformeringsnamn efter routparameternamnet. Routningsmallen blog/{article:slugify} anger till exempel en slugify transformerare. Mer information om parametertransformatorer finns i referensavsnittet Parametertransformator .
I följande tabell visas exempel på routningsmallar och deras beteende:
| Routningsmall | Exempel på matchande URI | Förfrågan-URI:n... |
|---|---|---|
hello |
/hello |
Matchar endast den ensamma sökvägen /hello. |
{Page=Home} |
/ |
Matchar och anger Page till Home. |
{Page=Home} |
/Contact |
Matchar och anger Page till Contact. |
{controller}/{action}/{id?} |
/Products/List |
Mappar till kontroller Products och åtgärd List. |
{controller}/{action}/{id?} |
/Products/Details/123 |
Mappar till kontrollanten Products och Details åtgärden medid värdet 123. |
{controller=Home}/{action=Index}/{id?} |
/ |
Mappar till Home-kontrollern och Index-metoden.
id ignoreras. |
{controller=Home}/{action=Index}/{id?} |
/Products |
Mappar till Products-kontrollern och Index-metoden.
id ignoreras. |
Att använda en mall är vanligtvis den enklaste metoden för routning. Begränsningar och standardvärden kan också anges utanför vägmallen.
Komplexa segment
Komplexa segment bearbetas genom matchning av literalavgränsare från höger till vänster på ett icke-girigt sätt. Till exempel [Route("/a{b}c{d}")] är ett komplext segment.
Komplexa segment fungerar på ett visst sätt som måste tolkas för att kunna använda dem. Exemplet i det här avsnittet visar varför komplexa segment bara fungerar bra när avgränsartexten inte visas i parametervärdena. Att använda en regex och sedan extrahera värdena manuellt behövs för mer komplexa fall.
Warning
När du använder System.Text.RegularExpressions för att bearbeta ej betrodda indata skickar du en timeout. En obehörig användare kan ange indata för att RegularExpressions orsaka en Denial-of-Service-attack. ASP.NET Core Frameworks API som använder RegularExpressions har en timeout.
Det här är en sammanfattning av de steg som routningen utför med mallen /a{b}c{d} och URL-sökvägen /abcd.
| Används för att visualisera hur algoritmen fungerar:
- Den första literalen, från höger till vänster, är
c. Så/abcdsöks från höger och hittar/ab|c|d. - Allt till höger (
d) matchas nu med routningsparametern{d}. - Nästa literal, från höger till vänster, är
a. Så/ab|c|dgenomsöks från där vi slutade, sedan hittasa/|a|b|c|d. - Värdet till höger (
b) matchas nu med routningsparametern{b}. - Det finns ingen kvarvarande text och ingen kvarvarande mall för rutt, så det här är en matchning.
Här är ett exempel på ett negativt ärende med samma mall /a{b}c{d} och URL-sökvägen /aabcd.
| Används för att visualisera hur algoritmen fungerar. Det här fallet är inte en matchning, vilket förklaras av samma algoritm:
- Den första literalen, från höger till vänster, är
c. Så/aabcdsöks från höger och hittar/aab|c|d. - Allt till höger (
d) matchas nu med routningsparametern{d}. - Nästa literal, från höger till vänster, är
a. Så/aab|c|dgenomsöks från där vi slutade, sedan hittasa/a|a|b|c|d. - Värdet till höger (
b) matchas nu med routningsparametern{b}. - I det här läget finns det fortfarande text
a, men algoritmen har slut på vägmall för analys, så detta stämmer inte.
Eftersom matchningsalgoritmen inte är girig:
- Den matchar den minsta möjliga mängden text i varje steg.
- Alla fall där avgränsarvärdet visas i parametervärdena resulterar i att det inte matchar.
Reguljära uttryck ger mycket mer kontroll över deras matchande beteende.
Girig matchning, också kallad försiktig matchning, matchar den största möjliga strängen. Icke-giriga matchar den minsta möjliga strängen.
Referens för routningsbegränsningar
Routningsbegränsningar körs när en matchning har hittats för den inkommande URL:en och URL-sökvägen tokeniseras till ruttvärden. Routningsbegränsningar inspekterar vanligtvis det vägvärde som är associerat via routningsmallen och fattar ett sant eller falskt beslut om huruvida värdet är acceptabelt. Vissa routningsbegränsningar använder data utanför vägvärdet för att överväga om begäran kan dirigeras. Till exempel HttpMethodRouteConstraint kan acceptera eller avvisa en begäran baserat på dess HTTP-verb. Begränsningar används i routningsbegäranden och länkgenerering.
Warning
Använd inte begränsningar för indataverifiering. Om begränsningar används för indataverifiering resulterar ogiltiga indata i ett 404 svar som inte hittades. Ogiltiga indata bör generera en 400 felaktig begäran med ett lämpligt felmeddelande. Routningsbegränsningar används för att särskilja liknande rutter, inte för att verifiera inmatningar för en viss rutt.
I följande tabell visas exempel på vägbegränsningar och deras förväntade beteende:
| constraint | Example | Exempelmatchningar | Notes |
|---|---|---|---|
int |
{id:int} |
123456789, -123456789 |
Matchar alla heltal |
bool |
{active:bool} |
true, FALSE |
Matchar true eller false. Case-insensitive |
datetime |
{dob:datetime} |
2016-12-31, 2016-12-31 7:32pm |
Matchar ett giltigt DateTime värde i den invarianta kulturen. Se föregående varning. |
decimal |
{price:decimal} |
49.99, -1,000.01 |
Matchar ett giltigt decimal värde i den invarianta kulturen. Se föregående varning. |
double |
{weight:double} |
1.234, -1,001.01e8 |
Matchar ett giltigt double värde i den invarianta kulturen. Se föregående varning. |
float |
{weight:float} |
1.234, -1,001.01e8 |
Matchar ett giltigt float värde i den invarianta kulturen. Se föregående varning. |
guid |
{id:guid} |
CD2C1638-1638-72D5-1638-DEADBEEF1638 |
Matchar ett giltigt Guid värde |
long |
{ticks:long} |
123456789, -123456789 |
Matchar ett giltigt long värde |
minlength(value) |
{username:minlength(4)} |
Rick |
Strängen måste innehålla minst 4 tecken |
maxlength(value) |
{filename:maxlength(8)} |
MyFile |
Strängen får inte innehålla fler än 8 tecken |
length(length) |
{filename:length(12)} |
somefile.txt |
Strängen måste vara exakt 12 tecken lång |
length(min,max) |
{filename:length(8,16)} |
somefile.txt |
Strängen får vara minst 8 och högst 16 tecken lång |
min(value) |
{age:min(18)} |
19 |
Heltalsvärdet måste vara minst 18 |
max(value) |
{age:max(120)} |
91 |
Heltalsvärdet får inte vara mer än 120 |
range(min,max) |
{age:range(18,120)} |
91 |
Heltalsvärdet måste vara minst 18 men högst 120 |
alpha |
{name:alpha} |
Rick |
Strängen måste bestå av ett eller flera alfabetiska tecken, och vara skiftlägesokänslig, a-z. |
regex(expression) |
{ssn:regex(^\\d{{3}}-\\d{{2}}-\\d{{4}}$)} |
123-45-6789 |
Strängen måste matcha det reguljära uttrycket. Se tips om hur du definierar ett reguljärt uttryck. |
required |
{name:required} |
Rick |
Används för att framtvinga att ett icke-parametervärde finns under URL-generering |
Warning
När du använder System.Text.RegularExpressions för att bearbeta ej betrodda indata skickar du en timeout. En obehörig användare kan ange indata för att RegularExpressions orsaka en Denial-of-Service-attack. ASP.NET Core Frameworks API som använder RegularExpressions har en timeout.
Flera, kolonavgränsade begränsningar kan tillämpas på en enskild parameter. Följande villkor begränsar till exempel en parameter till ett heltalsvärde på 1 eller högre:
[Route("users/{id:int:min(1)}")]
public User GetUserById(int id) { }
Warning
Routningsbegränsningar som verifierar URL:en och konverteras till en CLR-typ använder alltid den invarianta kulturen. Till exempel konvertering till CLR-typen int eller DateTime. Dessa begränsningar förutsätter att URL:en inte kan lokaliseras. De ramverksbaserade vägbegränsningarna ändrar inte de värden som lagras i vägvärden. Alla vägvärden som parsas från URL:en lagras som strängar. Villkoret float försöker till exempel konvertera vägvärdet till en flyttal, men det konverterade värdet används bara för att verifiera att det kan konverteras till en flyttal.
Reguljära uttryck i begränsningar
Warning
När du använder System.Text.RegularExpressions för att bearbeta ej betrodda indata skickar du en timeout. En obehörig användare kan ange indata för att RegularExpressions orsaka en Denial-of-Service-attack. ASP.NET Core Frameworks API som använder RegularExpressions har en timeout.
Reguljära uttryck kan anges som infogade begränsningar med hjälp av routningsbegränsningen regex(...) . Metoder i MapControllerRoute familjen accepterar också en objektliteral av begränsningar. Om formuläret används tolkas strängvärden som reguljära uttryck.
Följande kod använder en infogad regex-begränsning:
app.UseEndpoints(endpoints =>
{
endpoints.MapGet("{message:regex(^\\d{{3}}-\\d{{2}}-\\d{{4}}$)}",
context =>
{
return context.Response.WriteAsync("inline-constraint match");
});
});
Följande kod använder en objektliteral för att ange en regex-begränsning:
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", });
});
Ramverket ASP.NET Core lägger RegexOptions.IgnoreCase | RegexOptions.Compiled | RegexOptions.CultureInvariant till konstruktorn för reguljära uttryck. Se RegexOptions en beskrivning av dessa medlemmar.
Reguljära uttryck använder avgränsare och token som liknar dem som används vid routning och C#-språket. Token för reguljära uttryck måste vara undantagna. Om du vill använda reguljära uttryck ^\d{3}-\d{2}-\d{4}$ i en infogad begränsning använder du något av följande:
- Ersätt
\tecken som anges i strängen som\\tecken i C#-källfilen för att undvika strängens\escape-tecken. - Verbatim strängliteraler.
Om du vill undvika dirigeringsparametertecken {, }, [, ], dubblar du tecknen i uttrycket, {{till exempel , }}, [[, . ]] I följande tabell visas ett reguljärt uttryck och dess undantagna version:
| Reguljärt uttryck | Undantagna reguljära uttryck |
|---|---|
^\d{3}-\d{2}-\d{4}$ |
^\\d{{3}}-\\d{{2}}-\\d{{4}}$ |
^[a-z]{2}$ |
^[[a-z]]{{2}}$ |
Reguljära uttryck som används i routning börjar ofta med ^ tecknet och matchar strängens startposition. Uttrycken slutar ofta med $ tecknet och matchar slutet av strängen. Tecknen ^ och $ ser till att det reguljära uttrycket matchar värdet för hela routningsparametern. Utan ^- och $-tecknen matchar det reguljära uttrycket vilken delsträng som helst i strängen, vilket ofta är oönskat. Följande tabell innehåller exempel och förklarar varför de matchar eller inte matchar:
| Expression | String | Match | Comment |
|---|---|---|---|
[a-z]{2} |
hello | Yes | Matchningar för delsträngar |
[a-z]{2} |
123abc456 | Yes | Matchningar för delsträngar |
[a-z]{2} |
mz | Yes | Matchar uttryck |
[a-z]{2} |
MZ | Yes | Inte skiftlägeskänslig |
^[a-z]{2}$ |
hello | No | Se ^ och $ ovan |
^[a-z]{2}$ |
123abc456 | No | Se ^ och $ ovan |
Mer information om syntax för reguljära uttryck finns i Reguljära .NET Framework-uttryck.
Om du vill begränsa en parameter till en känd uppsättning möjliga värden använder du ett reguljärt uttryck. Till exempel {action:regex(^(list|get|create)$)} matchar endast routningsvärdet action till list, geteller create. Om den skickas in i begränsningsordboken, så är strängen ^(list|get|create)$ likvärdig. Begränsningar som skickas i villkorsordlistan som inte matchar någon av de kända begränsningarna behandlas också som reguljära uttryck. Begränsningar som skickas i en mall som inte matchar någon av de kända begränsningarna behandlas inte som reguljära uttryck.
Begränsningar för anpassad rutt
Anpassade routningsbegränsningar kan skapas genom att implementera IRouteConstraint gränssnittet. Gränssnittet IRouteConstraint innehåller Match, som returnerar true om villkoret är uppfyllt och false på annat sätt.
Anpassade routningsbegränsningar behövs sällan. Innan du implementerar en anpassad vägbegränsning bör du överväga alternativ, till exempel modellbindning.
Mappen ASP.NET Core Constraints innehåller bra exempel på hur du skapar begränsningar. Till exempel GuidRouteConstraint.
Om du vill använda en anpassad IRouteConstraintmåste routningsbegränsningstypen registreras med appens ConstraintMap i tjänstcontainern. A ConstraintMap är en ordlista som mappar routningsbegränsningsnycklar till IRouteConstraint implementeringar som validerar dessa begränsningar. En apps ConstraintMap kan uppdateras i Startup.ConfigureServices antingen som en del av en services.AddRouting-anrop eller genom att konfigurera RouteOptions direkt med services.Configure<RouteOptions>. Till exempel:
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers();
services.AddRouting(options =>
{
options.ConstraintMap.Add("customName", typeof(MyCustomConstraint));
});
}
Föregående villkor tillämpas i följande kod:
[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 tillhandahålls av Rick.Docs.Samples.RouteInfo NuGet-paketet och visar väginformation.
Implementeringen av MyCustomConstraint förhindrar 0 att en routningsparameter tillämpas:
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;
}
}
Warning
När du använder System.Text.RegularExpressions för att bearbeta ej betrodda indata skickar du en timeout. En obehörig användare kan ange indata för att RegularExpressions orsaka en Denial-of-Service-attack. ASP.NET Core Frameworks API som använder RegularExpressions har en timeout.
Föregående kod:
- Förhindrar
0i{id}segmentet av rutten. - Visas som ett grundläggande exempel på hur du implementerar en anpassad begränsning. Den bör inte användas i en produktionsapp.
Följande kod är en bättre metod för att förhindra att en id innehållande en 0 bearbetas:
[HttpGet("{id}")]
public IActionResult Get(string id)
{
if (id.Contains('0'))
{
return StatusCode(StatusCodes.Status406NotAcceptable);
}
return ControllerContext.MyDisplayRouteInfo(id);
}
Föregående kod har följande fördelar jämfört med MyCustomConstraint metoden:
- Det kräver ingen anpassad begränsning.
- Det returnerar ett mer beskrivande fel när vägparametern innehåller
0.
Referens för parametertransformator
Parametertransformatorer:
- Utför vid generering av en länk med LinkGenerator.
- Implementera Microsoft.AspNetCore.Routing.IOutboundParameterTransformer.
- Konfigureras med ConstraintMap.
- Ta parameterns vägvärde och omvandla det till ett nytt strängvärde.
- Resulterar i att du använder det transformerade värdet i den genererade länken.
Till exempel, en anpassad slugify-parametertransformator i vägmönster blog\{article:slugify} med Url.Action(new { article = "MyTestArticle" }) genererar blog\my-test-article.
Överväg följande IOutboundParameterTransformer implementering:
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();
}
}
Om du vill använda en parametertransformator i ett vägmönster konfigurerar du den med hjälp av ConstraintMap i Startup.ConfigureServices:
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers();
services.AddRouting(options =>
{
options.ConstraintMap["slugify"] = typeof(SlugifyParameterTransformer);
});
}
ASP.NET Core-ramverket använder parametertransformatorer för att transformera den URI där en slutpunkt löser problemet. Till exempel transformerar parametertransformatorer de vägvärden som används för att matcha en area, controller, actionoch page.
routes.MapControllerRoute(
name: "default",
template: "{controller:slugify=Home}/{action:slugify=Index}/{id?}");
Med föregående vägmall matchas åtgärden SubscriptionManagementController.GetAll med URI /subscription-management/get-all:n . En parametertransformator ändrar inte de vägvärden som används för att generera en länk. Till exempel Url.Action("GetAll", "SubscriptionManagement") ger /subscription-management/get-all.
ASP.NET Core tillhandahåller API-konventioner för användning av parametertransformatorer med genererade vägar:
- Microsoft.AspNetCore.Mvc.ApplicationModels.RouteTokenTransformerConvention MVC-konventionen tillämpar en angiven parametertransformator på alla attributvägar i appen. Parametertransformatorn transformerar attributvägstokens eftersom de ersätts. Mer information finns i Använda en parametertransformator för att anpassa tokenbyte.
- Razor Pages använder API-konventionen PageRouteTransformerConvention . Den här konventionen tillämpar en angiven parametertransformator på alla automatiskt identifierade Razor sidor. Parametertransformatoren transformerar mapp- och filnamnssegmenten Razor för Sidvägar. Mer information finns i Använda en parametertransformator för att anpassa sidvägar.
Referens för URL-generering
Det här avsnittet innehåller en referens för algoritmen som implementeras av URL-generering. I praktiken använder de flesta komplexa exempel på URL-generering styrenheter eller Razor sidor. Mer information finns i routning i kontrollanter .
URL-genereringsprocessen börjar med ett anrop till LinkGenerator.GetPathByAddress eller en liknande metod. Metoden tillhandahålls med en adress, en uppsättning vägvärden och eventuellt information om den aktuella begäran från HttpContext.
Det första steget är att använda adressen för att lösa en uppsättning kandidatslutpunkter med hjälp av en IEndpointAddressScheme<TAddress> som matchar adressens typ.
När uppsättningen kandidater hittas av adressschemat sorteras slutpunkterna och bearbetas iterativt tills en URL-genereringsåtgärd lyckas. URL-genereringen söker inte efter tvetydigheter. Det första resultatet som returneras är slutresultatet.
Felsöka URL-generering med loggning
Det första steget i felsökning av URL-generering för Microsoft.AspNetCore.Routing är att ställa in loggningsnivån till TRACE.
LinkGenerator loggar många detaljer om bearbetningen som kan vara användbar för att felsöka problem.
Mer information om URL-generering finns i REFERENS för URL-generering .
Addresses
Adresser är det begrepp i URL-generering som används för att binda ett anrop till länkgeneratorn till en uppsättning kandidatslutpunkter.
Adresser är ett utökningsbart begrepp som levereras med två implementeringar som standard:
- Använda slutpunktsnamnet (
string) som adress:- Tillhandahåller liknande funktioner som MVC:s routningsnamn.
- IEndpointNameMetadata Använder metadatatypen.
- Löser den angivna strängen mot metadata för alla registrerade slutpunkter.
- Utlöser ett undantag vid start om flera slutpunkter använder samma namn.
- Rekommenderas för generell användning utanför kontrollanter och Razor sidor.
- Använda vägvärden (RouteValuesAddress) som adress:
- Ger liknande funktioner som kontroller och äldre URL-generering för sidor.
- Mycket komplext att utöka och felsöka.
- Tillhandahåller implementeringen som används av
IUrlHelper, Tag Helpers, HTML-hjälpare, åtgärdsresultat osv.
Adressschemats roll är att göra associationen mellan adressen och matchande slutpunkter enligt godtyckliga kriterier:
- Slutpunktsnamnschemat utför en grundläggande ordlistesökning.
- Routningsvärdena har en komplex bästa delmängd av set-algoritmen.
Omgivande värden och explicita värden
Från den aktuella begäran får routning åtkomst till routningsvärdena för den aktuella begäran HttpContext.Request.RouteValues. De värden som är associerade med den aktuella begäran kallas för omgivande värden. För tydlighetens skull refererar dokumentationen till de vägvärden som skickas in till metoder som explicita värden.
I följande exempel visas omgivande värden och explicita värden. Den innehåller omgivande värden från den aktuella begäran och explicita värden: : { 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);
}
Föregående kod:
- Returnerar
/Widget/Index/17 - Hämtar LinkGenerator via DI.
Följande kod innehåller inga omgivande värden och explicita värden: : { controller = "Home", action = "Subscribe", id = 17, }
public IActionResult Index2()
{
var url = _linkGenerator.GetPathByAction("Subscribe", "Home",
new { id = 17, });
return Content(url);
}
Föregående metod returnerar /Home/Subscribe/17
Följande kod i WidgetController returnerar /Widget/Subscribe/17:
var url = _linkGenerator.GetPathByAction("Subscribe", null,
new { id = 17, });
Följande kod tillhandahåller kontrollen från omgivande värden i den pågående begäran och explicita värden: { action = "Edit", id = 17, }
public class GadgetController : Controller
{
public IActionResult Index()
{
var url = Url.Action("Edit", new { id = 17, });
return Content(url);
}
I koden ovan:
-
/Gadget/Edit/17returneras. - Url hämtar IUrlHelper.
-
Action genererar en URL med en absolut sökväg för en åtgärdsmetod. URL:en innehåller det angivna
actionnamnet ochroutevärdena.
Följande kod innehåller omgivande värden från den aktuella begäran och explicita värden: : { page = "./Edit, id = 17, }
public class IndexModel : PageModel
{
public void OnGet()
{
var url = Url.Page("./Edit", new { id = 17, });
ViewData["URL"] = url;
}
}
Den föregående koden sätter url till /Edit/17 när Redigera Razor Sida innehåller följande siddirektiv:
@page "{id:int}"
Om sidan Redigera inte innehåller "{id:int}"-routemallen, är url/Edit?id=17.
Beteendet för MVC lägger IUrlHelper till ett lager av komplexitet utöver de regler som beskrivs här:
-
IUrlHelpertillhandahåller alltid vägvärdena från den aktuella begäran som omgivande värden. -
IUrlHelper.Action kopierar alltid aktuella
actionvärden ochcontrollervägvärden som explicita värden om de inte åsidosätts av utvecklaren. -
IUrlHelper.Page kopierar alltid det aktuella
pagevägvärdet som ett explicit värde om det inte åsidosätts. -
IUrlHelper.Pageåsidosätter alltid det aktuellahandlerruttvärdet mednullsom ett explicit värde såvida det inte åsidosätts.
Användarna blir ofta förvånade över beteendeinformationen för omgivande värden, eftersom MVC inte verkar följa sina egna regler. Av historiska och kompatibilitetsskäl har vissa routningsvärden som action, controller, pageoch handler ett eget specialfallsbeteende.
Motsvarande funktionalitet som tillhandahålls av LinkGenerator.GetPathByAction och LinkGenerator.GetPathByPage duplicerar dessa avvikelser i IUrlHelper för kompatibilitet.
Process för URL-generering
När uppsättningen kandidatslutpunkter hittas, algoritmen för URL-generering:
- Bearbetar slutpunkterna iterativt.
- Returnerar det första lyckade resultatet.
Det första steget i den här processen kallas ogiltigförklarande av routningsvärden. Ogiltigförklaring av routningsvärden är den process genom vilken routning avgör vilka routningsvärden från bakgrundsvärden som ska användas och vilka som ska ignoreras. Varje omgivande värde beaktas och kombineras antingen med explicita värden eller ignoreras.
Det bästa sättet att förstå rollen av omgivande värden är att de försöker spara skrivande för programutvecklare i vissa vanliga situationer. Traditionellt är scenarier där omgivande värden är användbara relaterade till MVC:
- När du länkar till en annan åtgärd i samma kontrollant behöver inte kontrollantnamnet anges.
- När du länkar till en annan kontrollant i samma område behöver du inte ange områdesnamnet.
- När du länkar till samma åtgärdsmetod behöver du inte ange vägvärden.
- När du länkar till en annan del av appen vill du inte överföra routningsvärden som inte har någon betydelse i den delen av appen.
Anrop till LinkGenerator eller IUrlHelper som returnerar null orsakas vanligtvis av bristande förståelse av ogiltigförklaring av routningsvärden. Felsöka routningsvärdets ogiltighet genom att uttryckligen ange fler av vägvärdena för att se om det löser problemet.
Ogiltigförklaring av routvärden bygger på antagandet att appens URL-schema är hierarkiskt, med en hierarki som bildas från vänster till höger. Överväg den grundläggande mallen för styrenhetsroutning {controller}/{action}/{id?} för att få en intuitiv uppfattning om hur detta fungerar i praktiken. En ändring av ett värde ogiltigförklarar alla vägvärden som visas till höger. Detta återspeglar antagandet om hierarki. Om appen har ett omgivande värde för id, och åtgärden anger ett annat värde för controller:
-
idåteranvänds inte eftersom{controller}är till vänster om{id?}.
Några exempel som visar den här principen:
- Om de explicita värdena innehåller ett värde för
idignoreras det omgivande värdet förid. Omgivande värden förcontrollerochactionkan användas. - Om de explicita värdena innehåller ett värde för
actionignoreras alla omgivande värden föraction. Omgivningsvärdena förcontrollerkan användas. Om det explicita värdet föractionskiljer sig från det omgivande värdet föractionidanvänds inte värdet. Om det tydliga värdet föractionär detsamma som det omgivande värdet föraction, kanidvärdet användas. - Om de explicita värdena innehåller ett värde för
controllerignoreras alla omgivande värden förcontroller. Om det explicita värdet förcontrollerskiljer sig från det omgivande värdet förcontrolleractionanvänds inte värdena ochid. Om det explicita värdet förcontrollerär detsamma som det omgivande värdet förcontrolleractionkan värdena ochidanvändas.
Den här processen kompliceras ytterligare av förekomsten av attributvägar och dedikerade konventionella vägar. Styrenheters konventionella vägar som {controller}/{action}/{id?} specificerar en hierarki med hjälp av ruttparametrar. För dedikerade konventionella vägar och attributvägar till styrningar och Razor sidor:
- Det finns en hierarki med vägvärden.
- De visas inte i mallen.
I dessa fall definierar URL-generering det nödvändiga värdekonceptet . Slutpunkter som skapats av kontrollanter och Razor sidor har angivna värden som gör att vägvärdets ogiltighet kan fungera.
Ruttvärdets ogiltighetsalgoritm förklarad:
- De nödvändiga värdenamnen kombineras med vägparametrarna och bearbetas sedan från vänster till höger.
- För varje parameter jämförs det omgivande värdet och det explicita värdet:
- Om det omgivande värdet och det explicita värdet är samma fortsätter processen.
- Om det omgivande värdet finns och det explicita värdet inte är det används det omgivande värdet när URL:en genereras.
- Om det omgivande värdet inte finns och det explicita värdet är avvisar du det omgivande värdet och alla efterföljande omgivande värden.
- Om det omgivande värdet och det explicita värdet finns, och de två värdena är olika, avvisar du det omgivande värdet och alla efterföljande omgivande värden.
I det här läget är URL-genereringsåtgärden redo att utvärdera routningsbegränsningar. Uppsättningen godkända värden kombineras med parameterns standardvärden, vilka tillhandahålls för begränsningar. Om alla begränsningar uppfylls fortsätter operationen.
Därefter kan de godkända värdena användas för att expandera routningsmallen. Vägmallen bearbetas:
- Från vänster till höger.
- Varje parameter har sitt godkända värde ersatt.
- Med följande specialfall:
- Om de godkända värdena saknar ett värde och parametern har ett standardvärde används standardvärdet.
- Om de godkända värdena saknar ett värde och parametern är valfri fortsätter bearbetningen.
- Om en routningsparameter till höger om en valfri parameter som saknas har ett värde misslyckas åtgärden.
- Sammanhängande standardvärdeparametrar och valfria parametrar komprimeras där det är möjligt.
Värden som uttryckligen anges som inte matchar ett segment av vägen läggs till i frågesträngen. Följande tabell visar resultatet när du använder routningsmallen {controller}/{action}/{id?}.
| Omgivande värden | Explicita värden | Result |
|---|---|---|
| controller = "Home" | action = "Om" | /Home/About |
| controller = "Home" | controller = "Beställning", action = "Om" | /Order/About |
| controller = "Home", color = "Röd" | action = "Om" | /Home/About |
| controller = "Home" | action = "Om", color = "Röd" | /Home/About?color=Red |
Problem med att routningsvärdet är ogiltigt
Från och med ASP.NET Core 3.0 fungerar vissa URL-generationsscheman som används i tidigare ASP.NET Core-versioner inte bra med URL-generering. ASP.NET Core-teamet planerar att lägga till funktioner för att hantera dessa behov i en framtida version. För tillfället är den bästa lösningen att använda äldre routning.
Följande kod visar ett exempel på ett URL-genereringsschema som inte stöds av routning.
app.UseEndpoints(endpoints =>
{
endpoints.MapControllerRoute("default",
"{culture}/{controller=Home}/{action=Index}/{id?}");
endpoints.MapControllerRoute("blog", "{culture}/{**slug}",
new { controller = "Blog", action = "ReadPost", });
});
I föregående kod culture används routningsparametern för lokalisering. Önskan är att parametern culture alltid ska accepteras som ett omgivande värde. Parametern culture accepteras dock inte som ett omgivande värde på grund av hur nödvändiga värden fungerar:
- I routningsmallen
"default"är routningsparameternculturetill vänster omcontroller, så ändringar i kommer inte attcontrollerogiltigförklaraculture. -
"blog"I vägmallencultureanses vägparametern vara till höger omcontroller, som visas i de obligatoriska värdena.
Konfigurera slutpunktsmetadata
Följande länkar innehåller information om hur du konfigurerar slutpunktsmetadata:
- Aktivera Cors med slutpunktsroutning
-
Exempel på IAuthorizationPolicyProvider med ett anpassat
[MinimumAgeAuthorize]attribut - Testa autentisering med attributet [Auktorisera]
- RequireAuthorization
- Välja schemat med attributet [Auktorisera]
- Tillämpa principer med attributet [Auktorisera]
- Rollbaserad auktorisering i ASP.NET Core
Värdmatchning i rutter med RequireHost
RequireHost tillämpar en begränsning på den rutt som kräver den angivna värden. Parametern RequireHost eller [Värd] kan vara:
- Värd:
www.domain.com, matcharwww.domain.commed valfri port. - Värd med jokertecken:
*.domain.com, matcharwww.domain.com,subdomain.domain.com, ellerwww.subdomain.domain.compå valfri port. - Port:
*:5000, matchar port 5000 med valfri värd. - Värd och port:
www.domain.com:5000eller*.domain.com:5000, matchar värd och port.
Flera parametrar kan anges med RequireHost eller [Host]. Villkoret matchar värdar som är giltiga för någon av parametrarna. Matchar till exempel [Host("domain.com", "*.domain.com")], domain.com, www.domain.com, och subdomain.domain.com.
Följande kod använder RequireHost för att kräva den angivna värden på rutten:
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");
});
}
Följande kod använder [Host] attributet på kontrollanten för att kräva någon av de angivna värdarna:
[Host("contoso.com", "adventure-works.com")]
public class ProductController : Controller
{
public IActionResult Index()
{
return ControllerContext.MyDisplayRouteInfo();
}
[Host("example.com:8080")]
public IActionResult Privacy()
{
return ControllerContext.MyDisplayRouteInfo();
}
}
[Host] När attributet tillämpas på både kontrollanten och åtgärdsmetoden:
- Attributet för åtgärden används.
- Kontrollantattributet ignoreras.
Prestandavägledning för routning
Merparten av routningen uppdaterades i ASP.NET Core 3.0 för att öka prestandan.
När en app har prestandaproblem misstänks routning ofta vara problemet. Anledningen till att routning misstänks är att ramverk som kontrollers och Razor Pages rapporterar hur lång tid som spenderas inom ramverket i sina loggningsmeddelanden. När det finns en betydande skillnad mellan den tid som rapporteras av kontrollanter och den totala tiden för begäran:
- Utvecklare eliminerar sin appkod som källa till problemet.
- Det är vanligt att anta att routning är orsaken.
Routning är prestandatestad med tusentals slutpunkter. Det är osannolikt att en typisk app kommer att stöta på ett prestandaproblem bara genom att vara för stor. Den vanligaste grundorsaken till långsamma routningsprestanda är vanligtvis ett dåligt fungerande anpassad middleware.
Följande kodexempel visar en grundläggande teknik för att begränsa fördröjningskällan:
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.");
});
});
}
För att schemalägga dirigeringen:
- Alternativt infoga mellanprogrammen med en kopia av tidsmellanprogrammet som visas i föregående kod.
- Lägg till en unik identifierare för att korrelera tidsdata med koden.
Det här är ett grundläggande sätt att begränsa fördröjningen när den är betydande, till exempel mer än 10ms. Subtrahera Time 2 från Time 1 rapporterar tiden som spenderats i UseRouting mellanprogrammet.
Följande kod använder en mer kompakt metod för föregående tidskod:
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.");
});
});
}
Potentiellt dyra routningsfunktioner
Följande lista ger en inblick i routningsfunktioner som är relativt dyra jämfört med grundläggande routningsmallar:
- Reguljära uttryck: Det går att skriva reguljära uttryck som är komplexa eller har lång körningstid med en liten mängd indata.
- Komplicerade segment (
{x}-{y}-{z}):- Är betydligt dyrare än att parsa ett vanligt URL-sökvägssegment.
- Resulterar i att många fler delsträngar kommer att allokeras.
- Logiken för komplext segment uppdaterades inte i ASP.NET Core 3.0-routningsprestandauppdatering.
- Synkron dataåtkomst: Många komplexa appar har databasåtkomst som en del av routningen. ASP.NET Core 2.2 eller tidigare routning kanske inte ger rätt utökningspunkter som stöd för routning av databasåtkomst. Till exempel IRouteConstraint, och IActionConstraint är synkrona. Utökningspunkter som MatcherPolicy och EndpointSelectorContext är asynkrona.
Vägledning för biblioteksförfattare
Det här avsnittet innehåller vägledning för biblioteksförfattare som bygger ovanpå routning. Den här informationen är avsedd att säkerställa att apputvecklare har en bra upplevelse med hjälp av bibliotek och ramverk som utökar routningen.
Definiera slutpunkter
Om du vill skapa ett ramverk som använder routning för URL-matchning börjar du med att definiera en användarupplevelse som bygger ovanpå UseEndpoints.
BYGG ovanpå IEndpointRouteBuilder. På så sätt kan användarna skapa ditt ramverk med andra ASP.NET Core-funktioner utan förväxling. Varje ASP.NET Core-mall innehåller routning. Anta att routning är närvarande och bekant för användare.
app.UseEndpoints(endpoints =>
{
// Your framework
endpoints.MapMyFramework(...);
endpoints.MapHealthChecks("/healthz");
});
Returnera en förseglad betongtyp från ett anrop till MapMyFramework(...) som implementerar IEndpointConventionBuilder. De flesta ramverksmetoder Map... följer det här mönstret. Gränssnittet IEndpointConventionBuilder :
- Tillåter sammansättning av metadata.
- Är mål för en mängd olika tilläggsmetoder.
Om du deklarerar din egen typ kan du lägga till dina egna ramverksspecifika funktioner i byggaren. Det är okej att omsluta ett ramverksdeklarerat byggobjekt och vidarebefordra anrop till det.
app.UseEndpoints(endpoints =>
{
// Your framework
endpoints.MapMyFramework(...).RequireAuthorization()
.WithMyFrameworkFeature(awesome: true);
endpoints.MapHealthChecks("/healthz");
});
ÖVERVÄG att skriva din egen EndpointDataSource.
EndpointDataSource är en grundläggande konstruktion för att deklarera och uppdatera en samling slutpunkter.
EndpointDataSource är ett kraftfullt API som används av kontrollanter och Razor sidor.
Routningstesterna har ett grundläggande exempel på en datakälla som inte uppdateras.
Försök INTE att registrera en EndpointDataSource som standard. Kräv att användare registrerar ditt ramverk i UseEndpoints. Routningsfilosofin är att ingenting ingår som standard, och det UseEndpoints är platsen där slutpunkter ska registreras.
Skapa routningsintegrerade mellanprogram
ÖVERVÄG att definiera metadatatyper som ett gränssnitt.
Gör det möjligt att använda metadatatyper som ett attribut för klasser och metoder.
public interface ICoolMetadata
{
bool IsCool { get; }
}
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
public class CoolMetadataAttribute : Attribute, ICoolMetadata
{
public bool IsCool => true;
}
Ramverk som kontrollanter och Razor sidor stöder tillämpning av metadataattribut på typer och metoder. Om du deklarerar metadatatyper:
- Gör dem tillgängliga som attribut.
- De flesta användare är bekanta med att tillämpa attribut.
Om du deklarerar en metadatatyp som ett gränssnitt läggs ett annat flexibelt lager till:
- Gränssnitt är sammansättningsbara.
- Utvecklare kan deklarera sina egna typer som kombinerar flera principer.
Gör det möjligt att åsidosätta metadata, som du ser i följande exempel:
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() { }
}
Det bästa sättet att följa dessa riktlinjer är att undvika att definiera markörmetadata:
- Leta inte bara efter förekomsten av en metadatatyp.
- Definiera en egenskap för metadata och kontrollera egenskapen.
Metadatasamlingen är ordnad och möjliggör att överskrida efter prioritet. När det gäller kontrollanter är metadata för åtgärdsmetoden mest specifika.
Gör mellanprogram användbara med och utan routning.
app.UseRouting();
app.UseAuthorization(new AuthorizationPolicy() { ... });
app.UseEndpoints(endpoints =>
{
// Your framework
endpoints.MapMyFramework(...).RequireAuthorization();
});
Som ett exempel på den här riktlinjen bör du överväga UseAuthorization mellanprogrammet. Med mellanprogrammet för auktorisering kan du ange en reservpolicy.
Om den anges, gäller återställningsprincipen för båda:
- Slutpunkter utan en angiven policy.
- Begäranden som inte överensstämmer med en slutpunkt.
Detta gör auktoriseringsmellanprogrammet användbart utanför routningskontexten. Mellanprogrammet för auktorisering kan användas för traditionell mellanprogramprogrammering.
Felsökningsdiagnostik
För detaljerade routningsdiagnostikutdata anger du Logging:LogLevel:Microsoft till Debug. I utvecklingsmiljön anger du loggnivån i appsettings.Development.json:
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Debug",
"Microsoft.Hosting.Lifetime": "Information"
}
}
}
ASP.NET Core