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 .NET och .NET Core Support Policy. 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 .
ASP.NET Core-styrenheter använder routningsmellanprogrammet för att matcha URL:erna för inkommande begäranden och mappa dem till åtgärder. Routningsmallar:
- Definieras vid start i Program.cseller i attribut.
- Beskriv hur URL-sökvägar matchas med åtgärder.
- Används för att generera URL:er för länkar. De genererade länkarna returneras vanligtvis i svar.
Åtgärder är antingen konventionellt dirigerade eller attributroutade. Att placera en rutt på kontrollern eller åtgärden gör den attributbaserad. Mer information finns i Blandad routning .
Det här dokumentet:
- Förklarar interaktionerna mellan MVC och routning: - Hur vanliga MVC-appar använder routningsfunktioner.
- Omfattar båda: - Konventionell routning används vanligtvis med styrenheter och vyer.
- Attributroutning som används med REST API:er. Om du främst är intresserad av routning för REST API:er går du till avsnittet Attributroutning för REST API:er .
 
- Mer information om routning finns i Routning .
 
- Refererar till standarddirigeringssystemet som kallas slutpunktsroutning. Det är möjligt att använda styrenheter med den tidigare versionen av routning i kompatibilitetssyfte. Anvisningar finns i migreringsguiden 2.2-3.0 .
Konfigurera konventionell väg
Mallen ASP.NET Core MVC genererar konventionell routningskod som liknar följande:
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllersWithViews();
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Home/Error");
    app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthorization();
app.MapControllerRoute(
    name: "default",
    pattern: "{controller=Home}/{action=Index}/{id?}");
app.Run();
              MapControllerRoute används för att skapa en enda väg. Den enda vägen heter default route. De flesta appar med kontrollanter och vyer använder en routningsmall som liknar default vägen. 
              REST API:er bör använda attributroutning.
app.MapControllerRoute(
    name: "default",
    pattern: "{controller=Home}/{action=Index}/{id?}");
Routningsmallen "{controller=Home}/{action=Index}/{id?}":
- Matchar en URL-sökväg som - /Products/Details/5
- Extraherar vägvärdena - { controller = Products, action = Details, id = 5 }genom att tokenisera sökvägen. Extrahering av vägvärden resulterar i en matchning om appen har en styrenhet med namnet- ProductsControlleroch en- Detailsåtgärd:- public class ProductsController : Controller { public IActionResult Details(int id) { return ControllerContext.MyDisplayRouteInfo(id); } }- MyDisplayRouteInfo tillhandahålls av Rick.Docs.Samples.RouteInfo NuGet-paketet och visar väginformation. 
- /Products/Details/5modellen binder värdet- id = 5för att ange parametern- idtill- 5. Mer information finns i Modellbindning .
- {controller=Home}definierar- Homesom standard- controller.
- {action=Index}definierar- Indexsom standard- action.
- Tecknet - ?i- {id?}definierar- idsom valfritt.- Standard- och valfria vägparametrar behöver inte finnas i URL-sökvägen för en matchning. En detaljerad beskrivning av routningsmallssyntaxen finns i Referens för routningsmall .
 
- Matchar URL-sökvägen - /.
- Genererar vägvärdena - { controller = Home, action = Index }.
Värdena för controller och action använder standardvärdena. 
              id ger inget värde eftersom det inte finns något motsvarande segment i URL-sökvägen. 
              / matchar endast om det finns en HomeController-åtgärd och Index.
public class HomeController : Controller
{
    public IActionResult Index() { ... }
}
Med hjälp av föregående kontrollantdefinition och vägmall HomeController.Index körs åtgärden för följande URL-sökvägar:
- /Home/Index/17
- /Home/Index
- /Home
- /
URL-sökvägen / använder standardkontrollanterna Home och Index åtgärden för routningsmallen. URL-sökvägen /Home använder standardåtgärden Index för routningsmallen.
Bekvämlighetsmetoden MapDefaultControllerRoute:
app.MapDefaultControllerRoute();
Replaces:
app.MapControllerRoute(
    name: "default",
    pattern: "{controller=Home}/{action=Index}/{id?}");
Important
Routning konfigureras med hjälp av UseRouting och UseEndpoints middleware. Så här använder du kontroller:
- Anropa MapControllers för att mappa kontroller via attributruttning.
- Anropa MapControllerRoute eller MapAreaControllerRouteför att mappa både konventionellt dirigerade kontrollanter och attributroutade kontrollanter.
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. Mer information finns i Routning i ASP.NET Core.
Konventionell routning
Konventionell routning används med styrenheter och vyer. Vägen default :
app.MapControllerRoute(
    name: "default",
    pattern: "{controller=Home}/{action=Index}/{id?}");
Föregående är ett exempel på en konventionell väg. Den kallas för konventionell routning eftersom den upprättar en konvention för URL-sökvägar:
- Det första sökvägssegmentet, {controller=Home}, mappar till kontrollantnamnet.
- Det andra segmentet, {action=Index}, mappar till åtgärdsnamnet .
- Det tredje segmentet {id?}används för en valfriid.?i{id?}gör det valfritt.idanvänds för att mappa till en modellentitet.
Med hjälp av den här default rutten, URL-sökvägen:
- 
              /Products/Listmappar till åtgärdenProductsController.List.
- 
              /Blog/Article/17mappar tillBlogController.Articleoch binder oftast parameternidtill 17.
Den här mappningen:
- Baseras endast på kontrollanten och åtgärdsnamnen.
- Baseras inte på namnrymder, källfilplatser eller metodparametrar.
Med konventionell routning med standardvägen kan du skapa appen utan att behöva komma med ett nytt URL-mönster för varje åtgärd. För en app med CRUD-formatåtgärder , med konsekvens för URL:er mellan kontrollanter:
- Hjälper till att förenkla koden.
- Gör användargränssnittet mer förutsägbart.
Warning
I id föregående kod definieras som valfri av routningsmallen. Åtgärder kan köras utan det valfria ID som anges som en del av URL:en. Vanligtvis när id utelämnas från URL:en:
- 
              idsätts till0av modellbindning.
- Ingen entitet hittades i databasen som matchar id == 0.
              Attributroutning ger detaljerad kontroll för att göra ID obligatoriskt för vissa åtgärder men inte för andra. Enligt konventionen innehåller dokumentationen valfria parametrar som id när de sannolikt kommer att visas i korrekt användning.
De flesta appar bör välja ett grundläggande och beskrivande routningsschema så att URL:er är läsbara och meningsfulla. Standardvägen för konventionell väg {controller=Home}/{action=Index}/{id?}:
- Stöder ett grundläggande och beskrivande routningsschema.
- Är en användbar startpunkt för användargränssnittsbaserade appar.
- Är den enda vägmall som behövs för många webbgränssnittsappar. För större webbgränssnittsappar är en annan väg som använder Områden ofta allt som behövs.
MapControllerRoute och MapAreaRoute :
- Tilldela automatiskt ett ordervärde till sina slutpunkter baserat på den ordning som de anropas.
Slutpunktsroutning i ASP.NET Core:
- Har inget begrepp om vägar.
- Ger inte ordergarantier för körning av utökningsbarhet, alla slutpunkter bearbetas samtidigt.
Aktivera loggning för att se hur de inbyggda routningsimplementeringarna, till exempel Route, matchar begäranden.
Attributroutning förklaras senare i det här dokumentet.
Flera konventionella vägar
Flera konventionella vägar kan konfigureras genom att lägga till fler anrop till MapControllerRoute och MapAreaControllerRoute. På så sätt kan du definiera flera konventioner eller lägga till konventionella vägar som är dedikerade till en specifik åtgärd, till exempel:
app.MapControllerRoute(name: "blog",
                pattern: "blog/{*article}",
                defaults: new { controller = "Blog", action = "Article" });
app.MapControllerRoute(name: "default",
               pattern: "{controller=Home}/{action=Index}/{id?}");
Vägen blog i föregående kod är en dedikerad konventionell väg. Den kallas för en dedikerad konventionell väg eftersom:
- Den använder konventionell routning.
- Den är dedikerad till en specifik åtgärd.
Eftersom controller och action inte visas i routningsmallen "blog/{*article}" som parametrar:
- De kan bara ha standardvärdena { controller = "Blog", action = "Article" }.
- Den här rutten mappar alltid till åtgärden BlogController.Article.
              /Blog, /Blog/Articleoch /Blog/{any-string} är de enda URL-sökvägarna som matchar bloggvägen.
Föregående exempel:
- 
              blog-rutt har högre prioritet för matchningar ändefault-rutt eftersom den läggs till först.
- Är ett exempel på snigelformatsroutning där det är typiskt att ha ett artikelnamn som en del av URL:en.
Warning
I ASP.NET Core gör inte routning:
- Definiera ett begrepp som kallas väg. 
              UseRoutinglägger till routningsmatchning till pipelinen för mellanprogram. MellanprogrammetUseRoutingtittar på den uppsättning slutpunkter som definierats i appen och väljer den bästa slutpunktsmatchningen baserat på begäran.
- Ge garantier om exekveringsordningen för extensibilitet som IRouteConstraint eller IActionConstraint.
Se Routning för referensmaterial om routning.
Konventionell routningsordning
Konventionell routning matchar bara en kombination av åtgärd och kontrollant som definieras av appen. Detta är avsett att förenkla fall där konventionella vägar överlappar varandra.
Lägga till vägar med hjälp av MapControllerRoute, MapDefaultControllerRouteoch MapAreaControllerRoute automatiskt tilldela ett ordervärde till sina slutpunkter baserat på den ordning som de anropas. Matchningar från en rutt som visas tidigare har högre prioritet. Konventionell routning är orderberoende. I allmänhet bör vägar med områden placeras tidigare eftersom de är mer specifika än vägar utan område. 
              Dedikerade konventionella vägar med catch-all-routningsparametrar som {*article} kan göra en väg för girig, vilket innebär att den matchar URL:er som du avsåg att matchas av andra vägar. Placera de giriga rutterna senare i ruttabellen för att förhindra giriga matchningar.
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.
Lösa tvetydiga åtgärder
När två slutpunkter matchar genom routning måste routning göra något av följande:
- Välj den bästa kandidaten.
- Kasta ett undantag.
Till exempel:
public class Products33Controller : Controller
{
    public IActionResult Edit(int id)
    {
        return ControllerContext.MyDisplayRouteInfo(id);
    }
    [HttpPost]
    public IActionResult Edit(int id, Product product)
    {
        return ControllerContext.MyDisplayRouteInfo(id, product.name);
    }
}
Den föregående kontrollanten definierar två åtgärder som matchar:
- URL-sökvägen /Products33/Edit/17
- Ruttdata { controller = Products33, action = Edit, id = 17 }.
Detta är ett typiskt mönster för MVC-styrenheter:
- 
              Edit(int)visar ett formulär för att redigera en produkt.
- 
              Edit(int, Product)bearbetar det publicerade formuläret.
För att fastställa rätt rutt:
- 
              Edit(int, Product)väljs när begäran är en HTTPPOST.
- 
              Edit(int)väljs när HTTP-verbet är något annat.Edit(int)kallas vanligtvis viaGET.
              HttpPostAttribute, [HttpPost], tillhandahålls till routning så att det kan välja baserat på HTTP-metoden för begäran. 
              HttpPostAttribute gör Edit(int, Product) till en bättre matchning än Edit(int).
Det är viktigt att förstå rollen för attribut som HttpPostAttribute. Liknande attribut definieras för andra HTTP-verb. I konventionell routning är det vanligt att åtgärder använder samma åtgärdsnamn när de ingår i ett visningsformulär och skickar formulärarbetsflödet. Se till exempel Granska de två redigeringsmetoderna.
Om routning inte kan välja en bästa kandidat genereras en AmbiguousMatchException lista över de flera matchade slutpunkterna.
Namn på konventionella vägar
Strängarna "blog" och "default" i följande exempel är konventionella vägnamn:
app.MapControllerRoute(name: "blog",
                pattern: "blog/{*article}",
                defaults: new { controller = "Blog", action = "Article" });
app.MapControllerRoute(name: "default",
               pattern: "{controller=Home}/{action=Index}/{id?}");
Routningsnamnen ger vägen ett logiskt namn. Den namngivna vägen kan användas för URL-generering. Med hjälp av en namngiven väg förenklas skapandet av URL när ordningen på vägar kan göra URL-genereringen komplicerad. Routningsnamn måste vara unika för hela programmet.
Routningsnamn:
- Påverka inte URL-matchning eller hantering av begäranden.
- Används endast för URL-generering.
Begreppet routningsnamn representeras i routning som IEndpointNameMetadata. Termen routningsnamn och slutpunktsnamn:
- Är utbytbara.
- Vilken som används i dokumentationen och koden beror på vilket API som beskrivs.
Attributroutning för REST API:er
REST API:er bör använda attributroutning för att modellera appens funktioner som en uppsättning resurser där åtgärder representeras av HTTP-verb.
Attributroutning använder en uppsättning attribut för att mappa åtgärder direkt till routningsmallar. Följande kod är typisk för ett REST API och används i nästa exempel:
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllers();
var app = builder.Build();
app.UseHttpsRedirection();
app.UseAuthorization();
app.MapControllers();
app.Run();
I den föregående koden anropas MapControllers för att kartlägga attributroutade kontrollanter.
I följande exempel:
- 
              HomeControllermatchar en uppsättning URL:er som liknar vad den vanliga standardvägen{controller=Home}/{action=Index}/{id?}matchar.
public class HomeController : Controller
{
    [Route("")]
    [Route("Home")]
    [Route("Home/Index")]
    [Route("Home/Index/{id?}")]
    public IActionResult Index(int? id)
    {
        return ControllerContext.MyDisplayRouteInfo(id);
    }
    [Route("Home/About")]
    [Route("Home/About/{id?}")]
    public IActionResult About(int? id)
    {
        return ControllerContext.MyDisplayRouteInfo(id);
    }
}
Åtgärden HomeController.Index körs för någon av URL-sökvägarna /, /Home, /Home/Indexeller /Home/Index/3.
Det här exemplet visar en viktig programmeringsskillnad mellan attributroutning och konventionell routning. Attributroutning kräver mer indata för att ange en väg. Den konventionella standardvägen hanterar vägar mer kortfattat. Attributroutning tillåter dock och kräver exakt kontroll över vilka routningsmallar som gäller för varje åtgärd.
Med attributroutning spelar kontrollanten och åtgärdsnamnen ingen roll där åtgärden matchas, såvida inte tokenbyte används. Följande exempel matchar samma URL:er som i föregående exempel:
public class MyDemoController : Controller
{
    [Route("")]
    [Route("Home")]
    [Route("Home/Index")]
    [Route("Home/Index/{id?}")]
    public IActionResult MyIndex(int? id)
    {
        return ControllerContext.MyDisplayRouteInfo(id);
    }
    [Route("Home/About")]
    [Route("Home/About/{id?}")]
    public IActionResult MyAbout(int? id)
    {
        return ControllerContext.MyDisplayRouteInfo(id);
    }
}
Följande kod använder tokenersättning för action och controller:
public class HomeController : Controller
{
    [Route("")]
    [Route("Home")]
    [Route("[controller]/[action]")]
    public IActionResult Index()
    {
        return ControllerContext.MyDisplayRouteInfo();
    }
    [Route("[controller]/[action]")]
    public IActionResult About()
    {
        return ControllerContext.MyDisplayRouteInfo();
    }
}
Följande kod gäller [Route("[controller]/[action]")] för kontrollanten:
[Route("[controller]/[action]")]
public class HomeController : Controller
{
    [Route("~/")]
    [Route("/Home")]
    [Route("~/Home/Index")]
    public IActionResult Index()
    {
        return ControllerContext.MyDisplayRouteInfo();
    }
    public IActionResult About()
    {
        return ControllerContext.MyDisplayRouteInfo();
    }
}
I den föregående koden måste Index metodmallarna lägga till / eller ~/ till routemallarna. Routningsmallar som tillämpas på en åtgärd som börjar med / eller ~/ kombineras inte med routningsmallar som tillämpas på kontrollern.
Se Prioritet för routningsmall för information om val av routningsmall.
Namn på reserverad routning
Följande nyckelord är reserverade routningsparameternamn när du använder kontrollanter eller Razor sidor:
- action
- area
- controller
- handler
- page
Att använda page som routningsparameter med attributroutning är ett vanligt fel. Att göra det resulterar i inkonsekvent och förvirrande beteende med URL-generering.
public class MyDemo2Controller : Controller
{
    [Route("/articles/{page}")]
    public IActionResult ListArticles(int page)
    {
        return ControllerContext.MyDisplayRouteInfo(page);
    }
}
De särskilda parameternamnen används av URL-genereringen för att avgöra om en URL-genereringsåtgärd refererar till en Razor sida eller till en kontrollant.
Följande nyckelord är reserverade i kontexten för en Razor vy eller en Razor sida:
- page
- using
- namespace
- inject
- section
- inherits
- model
- addTagHelper
- removeTagHelper
Dessa nyckelord ska inte användas för länkgenerationer, modellbundna parametrar eller egenskaper på toppnivå.
HTTP-verbmallar
ASP.NET Core har följande HTTP-verbmallar:
Routningsmallar
ASP.NET Core har följande routningsmallar:
- Alla HTTP-verbmallar är routningsmallar.
- [Route]
Attributroutning med http-verbattribut
Tänk på följande kontrollant:
[Route("api/[controller]")]
[ApiController]
public class Test2Controller : ControllerBase
{
    [HttpGet]   // GET /api/test2
    public IActionResult ListProducts()
    {
        return ControllerContext.MyDisplayRouteInfo();
    }
    [HttpGet("{id}")]   // GET /api/test2/xyz
    public IActionResult GetProduct(string id)
    {
       return ControllerContext.MyDisplayRouteInfo(id);
    }
    [HttpGet("int/{id:int}")] // GET /api/test2/int/3
    public IActionResult GetIntProduct(int id)
    {
        return ControllerContext.MyDisplayRouteInfo(id);
    }
    [HttpGet("int2/{id}")]  // GET /api/test2/int2/3
    public IActionResult GetInt2Product(int id)
    {
        return ControllerContext.MyDisplayRouteInfo(id);
    }
}
I koden ovan:
- Varje åtgärd innehåller [HttpGet]attributet, som endast begränsar matchning till HTTP GET-begäranden.
- Åtgärden GetProductinnehåller mallen"{id}"och läggs därföridtill i mallen"api/[controller]"på kontrollanten. Mallen för metoder är"api/[controller]/{id}". Därför matchar den här åtgärden endast GET-begäranden för formuläret/api/test2/xyz,/api/test2/123/api/test2/{any string}osv.[HttpGet("{id}")] // GET /api/test2/xyz public IActionResult GetProduct(string id) { return ControllerContext.MyDisplayRouteInfo(id); }
- Åtgärden GetIntProductinnehåller mallen"int/{id:int}". Delen:intav mallen begränsaridvägvärdena till strängar som kan konverteras till ett heltal. En GET-begäran till/api/test2/int/abc:- Matchar inte den här åtgärden.
- Returnerar felet 404 Hittades inte .[HttpGet("int/{id:int}")] // GET /api/test2/int/3 public IActionResult GetIntProduct(int id) { return ControllerContext.MyDisplayRouteInfo(id); }
 
- Åtgärden GetInt2Productinnehåller{id}i mallen, men begränsaridinte till värden som kan konverteras till ett heltal. En GET-begäran till/api/test2/int2/abc:- Passar denna rutt.
- Modellbindningen kan inte konverteras abctill ett heltal. Parameternidför metoden är heltal.
- Returnerar en 400 felaktig begäran eftersom modellbindningen inte kunde konverteras abctill ett heltal.[HttpGet("int2/{id}")] // GET /api/test2/int2/3 public IActionResult GetInt2Product(int id) { return ControllerContext.MyDisplayRouteInfo(id); }
 
Attributroutning kan använda HttpMethodAttribute attribut som HttpPostAttribute, HttpPutAttributeoch HttpDeleteAttribute. Alla HTTP-verbsattribut accepterar en vägmall. I följande exempel visas två åtgärder som matchar samma vägmall:
[ApiController]
public class MyProductsController : ControllerBase
{
    [HttpGet("/products3")]
    public IActionResult ListProducts()
    {
        return ControllerContext.MyDisplayRouteInfo();
    }
    [HttpPost("/products3")]
    public IActionResult CreateProduct(MyProduct myProduct)
    {
        return ControllerContext.MyDisplayRouteInfo(myProduct.Name);
    }
}
Använda URL-sökvägen /products3:
- Åtgärden MyProductsController.ListProductskörs när HTTP-verbet ärGET.
- Åtgärden MyProductsController.CreateProductkörs när HTTP-verbet ärPOST.
När du skapar ett REST API är det ovanligt att du behöver använda [Route(...)] en åtgärdsmetod eftersom åtgärden accepterar alla HTTP-metoder. Det är bättre att använda det mer specifika HTTP-verbattributet för att vara exakt om vad ditt API stöder. Klienter för REST API:er förväntas veta vilka sökvägar och HTTP-verb som mappar till specifika logiska åtgärder.
REST API:er bör använda attributroutning för att modellera appens funktioner som en uppsättning resurser där åtgärder representeras av HTTP-verb. Det innebär att många åtgärder, till exempel GET och POST på samma logiska resurs, använder samma URL. Attributroutning ger en kontrollnivå som krävs för att noggrant utforma ett API:s offentliga slutpunktslayout.
Eftersom en attributväg gäller för en specifik åtgärd är det enkelt att göra parametrar som krävs som en del av definitionen av routningsmallen. I följande exempel id krävs som en del av URL-sökvägen:
[ApiController]
public class Products2ApiController : ControllerBase
{
    [HttpGet("/products2/{id}", Name = "Products_List")]
    public IActionResult GetProduct(int id)
    {
        return ControllerContext.MyDisplayRouteInfo(id);
    }
}
Åtgärden Products2ApiController.GetProduct(int) :
- Körs med URL-sökväg som /products2/3
- Körs inte med URL-sökvägen /products2.
Attributet [Förbrukar] tillåter en åtgärd för att begränsa innehållstyperna för begäranden som stöds. Mer information finns i Definiera innehållstyper för begäranden som stöds med attributet Förbrukar.
Se Routning för en fullständig beskrivning av routningsmallar och relaterade alternativ.
Mer information om [ApiController]finns i ApiController-attribut.
Routningsnamn
Följande kod definierar vägnamnet Products_List:
[ApiController]
public class Products2ApiController : ControllerBase
{
    [HttpGet("/products2/{id}", Name = "Products_List")]
    public IActionResult GetProduct(int id)
    {
        return ControllerContext.MyDisplayRouteInfo(id);
    }
}
Routningsnamn kan användas för att generera en URL baserat på en specifik väg. Routningsnamn:
- Ha ingen inverkan på url-matchningsbeteendet för routning.
- Används endast för URL-generering.
Routningsnamn måste vara unika för hela programmet.
Kontrastera föregående kod med den konventionella standardvägen, som definierar parametern id som valfri ({id?}). Möjligheten att exakt ange API:er har fördelar, till exempel att tillåta /products och /products/5 skickas till olika åtgärder.
Kombinera attributvägar
För att göra attributdirigering mindre repetitiv kombineras routningsattributen på kontrollanten med routningsattribut för de enskilda åtgärderna. Alla vägmallar som definierats på kontrollern läggs till före vägmallarna på åtgärderna. Om du placerar ett routningsattribut på kontrollanten används attributdirigering för alla åtgärder i kontrollanten.
[ApiController]
[Route("products")]
public class ProductsApiController : ControllerBase
{
    [HttpGet]
    public IActionResult ListProducts()
    {
        return ControllerContext.MyDisplayRouteInfo();
    }
    [HttpGet("{id}")]
    public IActionResult GetProduct(int id)
    {
        return ControllerContext.MyDisplayRouteInfo(id);
    }
}
I föregående exempel:
- URL-sökvägen /productskan matchaProductsApi.ListProducts
- URL-sökvägen /products/5kan matchaProductsApi.GetProduct(int).
Båda dessa åtgärder matchar bara HTTP GET eftersom de har markerats med attributet [HttpGet] .
Routningsmallar som tillämpas på en åtgärd som börjar med / eller ~/ kombineras inte med routningsmallar som tillämpas på kontrollern. Följande exempel matchar en uppsättning URL-sökvägar som liknar standardvägen.
[Route("Home")]
public class HomeController : Controller
{
    [Route("")]
    [Route("Index")]
    [Route("/")]
    public IActionResult Index()
    {
        return ControllerContext.MyDisplayRouteInfo();
    }
    [Route("About")]
    public IActionResult About()
    {
        return ControllerContext.MyDisplayRouteInfo();
    }
}
I följande tabell förklaras attributen [Route] i föregående kod:
| Attribute | Kombinerar med [Route("Home")] | Definierar routningsmall | 
|---|---|---|
| [Route("")] | Yes | "Home" | 
| [Route("Index")] | Yes | "Home/Index" | 
| [Route("/")] | No | "" | 
| [Route("About")] | Yes | "Home/About" | 
Ordning för attributrutter
Routning skapar ett träd och matchar alla slutpunkter samtidigt:
- Routningsposterna beter sig som om de vore placerade i en idealisk ordning.
- De mest specifika rutterna har möjlighet att köras före de mer allmänna rutterna.
Till exempel är en attributväg som blog/search/{topic} är mer specifik än en attributväg som blog/{*article}. Vägen blog/search/{topic} har högre prioritet, som standard, eftersom den är mer specifik. Med hjälp av konventionell routning ansvarar utvecklaren för att placera vägar i önskad ordning.
Attributvägar kan konfigurera en ordning med hjälp av egenskapen Order. Alla routningsattribut som tillhandahålls av ramverket är Order . Vägar bearbetas enligt en stigande typ av Order egenskapen. Standardordningen är 0. Ange en rutt med Order = -1 innan rutter som inte anger någon ordning. Ställ in en rutt genom Order = 1 som körs efter standardruttordning.
              Undvik beroende på Order. Om en apps URL-utrymme kräver explicita ordervärden för att dirigeras korrekt är det sannolikt förvirrande även för klienter. I allmänhet väljer attributroutning rätt väg med URL-matchning. Om standardordningen som används för URL-generering inte fungerar är det vanligtvis enklare att använda ett routningsnamn som åsidosättning än att tillämpa Order egenskapen.
Överväg följande två kontrollanter som båda definierar routningsmatchningen /home:
public class HomeController : Controller
{
    [Route("")]
    [Route("Home")]
    [Route("Home/Index")]
    [Route("Home/Index/{id?}")]
    public IActionResult Index(int? id)
    {
        return ControllerContext.MyDisplayRouteInfo(id);
    }
    [Route("Home/About")]
    [Route("Home/About/{id?}")]
    public IActionResult About(int? id)
    {
        return ControllerContext.MyDisplayRouteInfo(id);
    }
}
public class MyDemoController : Controller
{
    [Route("")]
    [Route("Home")]
    [Route("Home/Index")]
    [Route("Home/Index/{id?}")]
    public IActionResult MyIndex(int? id)
    {
        return ControllerContext.MyDisplayRouteInfo(id);
    }
    [Route("Home/About")]
    [Route("Home/About/{id?}")]
    public IActionResult MyAbout(int? id)
    {
        return ControllerContext.MyDisplayRouteInfo(id);
    }
}
Om du begär /home med föregående kod genereras ett undantag som liknar följande:
AmbiguousMatchException: The request matched multiple endpoints. Matches:
 WebMvcRouting.Controllers.HomeController.Index
 WebMvcRouting.Controllers.MyDemoController.MyIndex
Om du lägger Order till något av routningsattributen löses tvetydigheten:
[Route("")]
[Route("Home", Order = 2)]
[Route("Home/MyIndex")]
public IActionResult MyIndex()
{
    return ControllerContext.MyDisplayRouteInfo();
}
Med den föregående koden kör /home slutpunkten HomeController.Index. För att komma till MyDemoController.MyIndex, begär /home/MyIndex. 
              Note:
- Föregående kod är ett exempel eller dålig routningsdesign. Den användes för att illustrera egenskapen Order.
- Egenskapen Orderlöser bara tvetydigheten, den mallen kan inte matchas. Det vore bättre att ta bort mallen[Route("Home")].
Se Razor Sidors routnings- och appkonventioner: Routningsordning för information om routningsordning med Razor Sidor.
I vissa fall returneras ett HTTP 500-fel med tvetydiga vägar. Använd loggning för att se vilka ändpunkter som orsakade AmbiguousMatchException.
Ersättning av tokens i vägmallar [kontroller], [aktion], [område]
För enkelhetens skull stöder attributvägar tokenbyte genom att omsluta en token i hakparenteser ([, ]). Token , [action]och [area] ersätts med värdena för åtgärdsnamnet[controller], områdesnamnet och kontrollantnamnet från åtgärden där vägen definieras:
[Route("[controller]/[action]")]
public class Products0Controller : Controller
{
    [HttpGet]
    public IActionResult List()
    {
        return ControllerContext.MyDisplayRouteInfo();
    }
    [HttpGet("{id}")]
    public IActionResult Edit(int id)
    {
        return ControllerContext.MyDisplayRouteInfo(id);
    }
}
I koden ovan:
[HttpGet]
public IActionResult List()
{
    return ControllerContext.MyDisplayRouteInfo();
}
- Matcher /Products0/List
[HttpGet("{id}")]
public IActionResult Edit(int id)
{
    return ControllerContext.MyDisplayRouteInfo(id);
}
- Matcher /Products0/Edit/{id}
Tokenbyte sker som det sista steget för att skapa attributvägarna. Föregående exempel beter sig på samma sätt som följande kod:
public class Products20Controller : Controller
{
    [HttpGet("[controller]/[action]")]  // Matches '/Products20/List'
    public IActionResult List()
    {
        return ControllerContext.MyDisplayRouteInfo();
    }
    [HttpGet("[controller]/[action]/{id}")]   // Matches '/Products20/Edit/{id}'
    public IActionResult Edit(int id)
    {
        return ControllerContext.MyDisplayRouteInfo(id);
    }
}
Om du läser detta på ett annat språk än engelska kan du meddela oss i det här GitHub-diskussionsproblemet om du vill se kodkommentarna på ditt modersmål.
Attributvägar kan också kombineras med arv. Detta är kraftfullt kombinerat med tokenbyte. Tokenbyte gäller även för routningsnamn som definierats av attributvägar.
              [Route("[controller]/[action]", Name="[controller]_[action]")]genererar ett unikt vägnamn för varje åtgärd:
[ApiController]
[Route("api/[controller]/[action]", Name = "[controller]_[action]")]
public abstract class MyBase2Controller : ControllerBase
{
}
public class Products11Controller : MyBase2Controller
{
    [HttpGet]                      // /api/products11/list
    public IActionResult List()
    {
        return ControllerContext.MyDisplayRouteInfo();
    }
    [HttpGet("{id}")]             //    /api/products11/edit/3
    public IActionResult Edit(int id)
    {
        return ControllerContext.MyDisplayRouteInfo(id);
    }
}
Om du vill matcha den literala tokenbyteslimiten [ eller ], tar du bort den genom att upprepa tecknet ([[ eller ]]).
Använda en parametertransformator för att anpassa tokenbyte
Tokenbyte kan anpassas med hjälp av en parametertransformator. En parametertransformator implementerar IOutboundParameterTransformer och transformerar värdet för parametrar. En anpassad SlugifyParameterTransformer parametertransformator ändrar till exempel routningsvärdet SubscriptionManagement till subscription-management:
using System.Text.RegularExpressions;
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();
    }
}
RouteTokenTransformerConvention Är en konvention för programmodell som:
- Tillämpar en parametertransformator på alla attributvägar i ett program.
- Anpassar attributvägens tokenvärden när de ersätts.
public class SubscriptionManagementController : Controller
{
    [HttpGet("[controller]/[action]")]
    public IActionResult ListAll()
    {
        return ControllerContext.MyDisplayRouteInfo();
    }
}
              ListAll Föregående metod matchar /subscription-management/list-all.
              RouteTokenTransformerConvention Är registrerad som ett alternativ:
using Microsoft.AspNetCore.Mvc.ApplicationModels;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllersWithViews(options =>
{
    options.Conventions.Add(new RouteTokenTransformerConvention(
                                 new SlugifyParameterTransformer()));
});
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Home/Error");
    app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthorization();
app.MapControllerRoute(name: "default",
               pattern: "{controller=Home}/{action=Index}/{id?}");
app.Run();
Se MDN-webbdokument på Slug för definitionen av Slug.
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 attributvägar
Attributroutning stöder definition av flera vägar som når samma åtgärd. Den vanligaste användningen av detta är att efterlikna beteendet för den vanliga konventionella vägen enligt följande exempel:
[Route("[controller]")]
public class Products13Controller : Controller
{
    [Route("")]     // Matches 'Products13'
    [Route("Index")] // Matches 'Products13/Index'
    public IActionResult Index()
    {
        return ControllerContext.MyDisplayRouteInfo();
    }
Om du placerar flera routningsattribut på kontrollanten innebär det att var och en kombineras med vart och ett av routningsattributen på åtgärdsmetoderna:
[Route("Store")]
[Route("[controller]")]
public class Products6Controller : Controller
{
    [HttpPost("Buy")]       // Matches 'Products6/Buy' and 'Store/Buy'
    [HttpPost("Checkout")]  // Matches 'Products6/Checkout' and 'Store/Checkout'
    public IActionResult Buy()
    {
        return ControllerContext.MyDisplayRouteInfo();
    }
}
Alla villkor för HTTP-verbvägen implementerar IActionConstraint.
När flera routattribut som implementerar IActionConstraint placeras till en åtgärd:
- Varje åtgärdsbegränsning kombineras med routningsmallen som tillämpas på kontrollanten.
[Route("api/[controller]")]
public class Products7Controller : ControllerBase
{
    [HttpPut("Buy")]        // Matches PUT 'api/Products7/Buy'
    [HttpPost("Checkout")]  // Matches POST 'api/Products7/Checkout'
    public IActionResult Buy()
    {
        return ControllerContext.MyDisplayRouteInfo();
    }
}
Om du använder flera vägar för åtgärder kan det verka användbart och kraftfullt. Det är bättre att hålla appens URL-utrymme grundläggande och väldefinierat. Använd flera vägar för åtgärder endast där det behövs, till exempel för att stödja befintliga kunder.
Ange valfria parametrar för attributväg, standardvärden och begränsningar
Attributvägar stöder samma infogade syntax som konventionella vägar för att ange valfria parametrar, standardvärden och begränsningar.
public class Products14Controller : Controller
{
    [HttpPost("product14/{id:int}")]
    public IActionResult ShowProduct(int id)
    {
        return ControllerContext.MyDisplayRouteInfo(id);
    }
}
I föregående kod [HttpPost("product14/{id:int}")] tillämpar du en routningsbegränsning. Åtgärden Products14Controller.ShowProduct matchas endast av URL-sökvägar som /product14/3. Routningsmalldelen {id:int} begränsar segmentet till enbart heltal.
En detaljerad beskrivning av routningsmallssyntaxen finns i Referens för routningsmall .
Anpassade routningsattribut med IRouteTemplateProvider
Alla routningsattribut implementerar IRouteTemplateProvider. ASP.NET Core körmiljö:
- Söker efter attribut på kontrollantklasser och åtgärdsmetoder när appen startar.
- Använder attributen som implementerar IRouteTemplateProviderför att skapa den initiala uppsättningen rutter.
Implementera IRouteTemplateProvider för att definiera anpassade routningsattribut. Varje IRouteTemplateProvider gör att du kan definiera en enskild rutt med en anpassad ruttmall, ordning och namn:
public class MyApiControllerAttribute : Attribute, IRouteTemplateProvider
{
    public string Template => "api/[controller]";
    public int? Order => 2;
    public string Name { get; set; } = string.Empty;
}
[MyApiController]
[ApiController]
public class MyTestApiController : ControllerBase
{
    // GET /api/MyTestApi
    [HttpGet]
    public IActionResult Get()
    {
        return ControllerContext.MyDisplayRouteInfo();
    }
}
              Get Föregående metod returnerar Order = 2, Template = api/MyTestApi.
Använda programmodell för att anpassa attributvägar
Programmodellen:
- En objektmodell skapas vid start i Program.cs.
- Innehåller alla metadata som används av ASP.NET Core för att dirigera och köra åtgärderna i en app.
Programmodellen innehåller alla data som samlas in från routningsattribut. Data från routningsattribut tillhandahålls av implementeringen IRouteTemplateProvider . Conventions:
- Kan skrivas för att ändra programmodellen för att anpassa hur routning fungerar.
- När appen startar läses de.
Det här avsnittet visar ett grundläggande exempel på hur du anpassar routning med hjälp av programmodellen. Följande kod gör vägarna ungefär i linje med projektets mappstruktur.
public class NamespaceRoutingConvention : Attribute, IControllerModelConvention
{
    private readonly string _baseNamespace;
    public NamespaceRoutingConvention(string baseNamespace)
    {
        _baseNamespace = baseNamespace;
    }
    public void Apply(ControllerModel controller)
    {
        var hasRouteAttributes = controller.Selectors.Any(selector =>
                                                selector.AttributeRouteModel != null);
        if (hasRouteAttributes)
        {
            return;
        }
        var namespc = controller.ControllerType.Namespace;
        if (namespc == null)
            return;
        var template = new StringBuilder();
        template.Append(namespc, _baseNamespace.Length + 1,
                        namespc.Length - _baseNamespace.Length - 1);
        template.Replace('.', '/');
        template.Append("/[controller]/[action]/{id?}");
        foreach (var selector in controller.Selectors)
        {
            selector.AttributeRouteModel = new AttributeRouteModel()
            {
                Template = template.ToString()
            };
        }
    }
}
Följande kod förhindrar att konventionen namespace tillämpas på kontroller som är attributroutade:
public void Apply(ControllerModel controller)
{
    var hasRouteAttributes = controller.Selectors.Any(selector =>
                                            selector.AttributeRouteModel != null);
    if (hasRouteAttributes)
    {
        return;
    }
Följande styrenhet använder NamespaceRoutingConventiontill exempel inte :
[Route("[controller]/[action]/{id?}")]
public class ManagersController : Controller
{
    // /managers/index
    public IActionResult Index()
    {
        var template = ControllerContext.ActionDescriptor.AttributeRouteInfo?.Template;
        return Content($"Index- template:{template}");
    }
    public IActionResult List(int? id)
    {
        var path = Request.Path.Value;
        return Content($"List- Path:{path}");
    }
}
              NamespaceRoutingConvention.Apply-metoden:
- Gör ingenting om kontrollen är attribut-routerad.
- Anger kontrollantmallen baserat på namespace, med basennamespaceborttagen.
              NamespaceRoutingConvention Kan användas i Program.cs:
using My.Application.Controllers;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllersWithViews(options =>
{
    options.Conventions.Add(
     new NamespaceRoutingConvention(typeof(HomeController).Namespace!));
});
var app = builder.Build();
Tänk till exempel på följande kontrollant:
using Microsoft.AspNetCore.Mvc;
namespace My.Application.Admin.Controllers
{
    public class UsersController : Controller
    {
        // GET /admin/controllers/users/index
        public IActionResult Index()
        {
            var fullname = typeof(UsersController).FullName;
            var template = 
                ControllerContext.ActionDescriptor.AttributeRouteInfo?.Template;
            var path = Request.Path.Value;
            return Content($"Path: {path} fullname: {fullname}  template:{template}");
        }
        public IActionResult List(int? id)
        {
            var path = Request.Path.Value;
            return Content($"Path: {path} ID:{id}");
        }
    }
}
I koden ovan:
- Basen namespaceärMy.Application.
- Det fullständiga namnet på den föregående kontrollanten är My.Application.Admin.Controllers.UsersController.
- Anger NamespaceRoutingConventionkontrollantmallen tillAdmin/Controllers/Users/[action]/{id?.
              NamespaceRoutingConvention Kan också användas som ett attribut på en kontrollant:
[NamespaceRoutingConvention("My.Application")]
public class TestController : Controller
{
    // /admin/controllers/test/index
    public IActionResult Index()
    {
        var template = ControllerContext.ActionDescriptor.AttributeRouteInfo?.Template;
        var actionname = ControllerContext.ActionDescriptor.ActionName;
        return Content($"Action- {actionname} template:{template}");
    }
    public IActionResult List(int? id)
    {
        var path = Request.Path.Value;
        return Content($"List- Path:{path}");
    }
}
Blandad routning: Attributroutning jämfört med konventionell routning
ASP.NET Core-appar kan blanda användningen av konventionell routning och attributroutning. Det är vanligt att använda konventionella vägar för kontrollanter som betjänar HTML-sidor för webbläsare och attributroutning för kontrollanter som betjänar REST API:er.
Åtgärder dirigeras antingen konventionellt eller dirigeras med attribut. Om du placerar en väg på kontrollanten eller åtgärden dirigeras attributet. Åtgärder som definierar attributvägar kan inte nås via konventionella vägar och vice versa. Några routningsattribut på kontrollern gör att alla åtgärder i kontrollern blir dirigerade genom attributet.
Attributroutning och konventionell routning använder samma routningsmotor.
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;
URL-generering och omgivande värden
Appar kan använda genereringsfunktioner för routnings-URL för att generera URL-länkar till åtgärder. Att generera URL:er eliminerar hårdkodande URL:er, vilket gör koden mer robust och underhållsbar. Det här avsnittet fokuserar på url-genereringsfunktionerna som tillhandahålls av MVC och omfattar endast grunderna för hur URL-generering fungerar. Se Routning för en detaljerad beskrivning av URL-generering.
Gränssnittet IUrlHelper är det underliggande elementet i infrastrukturen mellan MVC och routning för URL-generering. En instans av IUrlHelper är tillgänglig via Url egenskapen i kontrollanter, vyer och visningskomponenter.
I följande exempel IUrlHelper används gränssnittet via egenskapen Controller.Url för att generera en URL till en annan åtgärd.
public class UrlGenerationController : Controller
{
    public IActionResult Source()
    {
        // Generates /UrlGeneration/Destination
        var url = Url.Action("Destination");
        return ControllerContext.MyDisplayRouteInfo("", $" URL = {url}");
    }
    public IActionResult Destination()
    {
        return ControllerContext.MyDisplayRouteInfo();
    }
}
Om appen använder den vanliga standardvägen är värdet för variabeln url URL-sökvägssträngen /UrlGeneration/Destination. Den här URL-sökvägen skapas genom routning genom att kombinera:
- Routningsvärdena från den aktuella begäran, som kallas för omgivande värden.
- Värdena som skickas till Url.Actionoch de värden som ersätter dessa i routmallen:
ambient values: { controller = "UrlGeneration", action = "Source" }
values passed to Url.Action: { controller = "UrlGeneration", action = "Destination" }
route template: {controller}/{action}/{id?}
result: /UrlGeneration/Destination
Varje ruttparameter i vägmallen får sitt värde ersatt av att matcha namn med värden och omgivande värden. En vägparameter som inte har något värde kan:
- Använd ett standardvärde om det har ett.
- Hoppas över om det är valfritt. Till exempel idfrån vägmallen{controller}/{action}/{id?}.
URL-genereringen misslyckas om någon obligatorisk vägparameter inte har något motsvarande värde. Om URL-genereringen misslyckas för en väg provas nästa väg tills alla vägar har provats eller en matchning hittas.
Föregående exempel på Url.Action förutsätter konventionell routning. URL-generering fungerar på samma sätt med attributroutning, även om begreppen skiljer sig. Med konventionell routning:
- Vägvärdena används för att expandera en mall.
- Vägvärdena för controllerochactionvisas vanligtvis i mallen. Detta fungerar eftersom URL:erna som matchas av routning följer en konvention.
I följande exempel används attributroutning:
public class UrlGenerationAttrController : Controller
{
    [HttpGet("custom")]
    public IActionResult Source()
    {
        var url = Url.Action("Destination");
        return ControllerContext.MyDisplayRouteInfo("", $" URL = {url}");
    }
    [HttpGet("custom/url/to/destination")]
    public IActionResult Destination()
    {
       return ControllerContext.MyDisplayRouteInfo();
    }
}
Åtgärden Source i föregående kod genererar custom/url/to/destination.
              LinkGenerator lades till i ASP.NET Core 3.0 som ett alternativ till IUrlHelper. 
              LinkGenerator erbjuder liknande men mer flexibla funktioner. Varje metod på IUrlHelper har också en motsvarande uppsättning metoder LinkGenerator .
Generera URL:er efter åtgärdsnamn
Url.Action, LinkGenerator.GetPathByAction och alla relaterade överlagringar är alla utformade för att generera målslutpunkten genom att ange ett kontrollantnamn och åtgärdsnamn.
När du använder Url.Action, tillhandahålls de aktuella ruttvärdena för controller och action av körningstiden.
- Värdet för controllerochactionär en del av både omgivande värden och värden. MetodenUrl.Actionanvänder alltid de aktuella värdenaactionför ochcontrolleroch genererar en URL-sökväg som dirigerar till den aktuella åtgärden.
Routning försöker använda värdena i omgivande värden för att fylla i information som inte angavs när en URL genererades. Överväg en väg som {a}/{b}/{c}/{d} med omgivande värden { a = Alice, b = Bob, c = Carol, d = David }:
- Routning har tillräckligt med information för att generera en URL utan ytterligare värden.
- Routning har tillräckligt med information eftersom alla vägparametrar har ett värde.
Om värdet { d = Donovan } läggs till:
- Värdet { d = David }ignoreras.
- Den genererade URL-sökvägen är Alice/Bob/Carol/Donovan.
              Varning! URL-sökvägar är hierarkiska. Om värdet { c = Cheryl } läggs till i föregående exempel:
- Båda värdena { c = Carol, d = David }ignoreras.
- Det finns inte längre något värde för doch URL-genereringen misslyckas.
- Önskade värden för cochdmåste anges för att generera en URL.
Du kan förvänta dig att stöta på det här problemet med standardvägen {controller}/{action}/{id?}. Det här problemet är sällsynt i praktiken eftersom Url.Action alltid uttryckligen anger ett controller och action -värde.
Flera överlagringar av URL.Action använder ett vägvärdesobjekt för att ange värden för andra vägparametrar än controller och action. Objektet för vägvärden används ofta med id. Till exempel Url.Action("Buy", "Products", new { id = 17 }). Objektet för ruttvärden
- Enligt konvention är det vanligtvis ett objekt av anonym typ.
- Kan vara en IDictionary<>eller en POCO).
Eventuella ytterligare vägvärden som inte matchar routningsparametrar placeras i frågesträngen.
public IActionResult Index()
{
    var url = Url.Action("Buy", "Products", new { id = 17, color = "red" });
    return Content(url!);
}
Föregående kod genererar /Products/Buy/17?color=red.
Följande kod genererar en absolut URL:
public IActionResult Index2()
{
    var url = Url.Action("Buy", "Products", new { id = 17 }, protocol: Request.Scheme);
    // Returns https://localhost:5001/Products/Buy/17
    return Content(url!);
}
Om du vill skapa en absolut URL använder du något av följande:
- En överbelastning som accepterar en protocol. Till exempel föregående kod.
- LinkGenerator.GetUriByAction, som genererar absoluta URI:er som standard.
Generera URL:er efter väg
Föregående kod visade hur du genererade en URL genom att skicka in kontrollanten och åtgärdsnamnet. 
              IUrlHelper innehåller också url.RouteUrl-serien med metoder. Dessa metoder liknar Url.Action, men de kopierar inte de aktuella värdena action för och controller till vägvärdena. Den vanligaste användningen av Url.RouteUrl:
- Anger ett vägnamn för att generera URL:en.
- I allmänhet anger inte en kontrollant eller åtgärdsnamn.
public class UrlGeneration2Controller : Controller
{
    [HttpGet("")]
    public IActionResult Source()
    {
        var url = Url.RouteUrl("Destination_Route");
        return ControllerContext.MyDisplayRouteInfo("", $" URL = {url}");
    }
    [HttpGet("custom/url/to/destination2", Name = "Destination_Route")]
    public IActionResult Destination()
    {
        return ControllerContext.MyDisplayRouteInfo();
    }
Följande Razor fil genererar en HTML-länk till Destination_Route:
<h1>Test Links</h1>
<ul>
    <li><a href="@Url.RouteUrl("Destination_Route")">Test Destination_Route</a></li>
</ul>
Generera URL:er i HTML och Razor
              IHtmlHelper
              HtmlHelper innehåller metoderna Html.BeginForm och Html.ActionLink för att generera <form><a> respektive element. Dessa metoder använder metoden Url.Action för att generera en URL och de accepterar liknande argument. Följeslagare Url.RouteUrl för HtmlHelper är Html.BeginRouteForm och Html.RouteLink som har liknande funktioner.
TagHelpers genererar URL:er via form TagHelper och <a> TagHelper. Båda dessa använder IUrlHelper för deras implementering. För mer information, se Tag Helpers i formulär.
I vyer, IUrlHelper finns tillgänglig via Url den egenskapen för alla ad hoc-URL-genereringar som inte omfattas av ovanstående.
URL-generering i åtgärdsresultat
De föregående exemplen visade hur man använder IUrlHelper i en kontroller. Det vanligaste syftet med en kontroller är att generera en URL som en del av ett åtgärdsresultat.
Basklasserna ControllerBase och Controller tillhandahåller bekvämlighetsmetoder för åtgärdsresultat som refererar till en annan åtgärd. En vanlig användning är att omdirigera efter att ha accepterat användarindata:
[HttpPost]
[ValidateAntiForgeryToken]
public IActionResult Edit(int id, Customer customer)
{
    if (ModelState.IsValid)
    {
        // Update DB with new details.
        ViewData["Message"] = $"Successful edit of customer {id}";
        return RedirectToAction("Index");
    }
    return View(customer);
}
Metoder för åtgärdsresultat som RedirectToAction och CreatedAtAction följer ett liknande mönster som metoderna hos IUrlHelper.
Specialfall för dedikerade konventionella vägar
              Konventionell routning kan använda en särskild typ av vägdefinition som kallas en dedikerad konventionell väg. I följande exempel är den väg som heter blog en dedikerad konventionell väg:
app.MapControllerRoute(name: "blog",
                pattern: "blog/{*article}",
                defaults: new { controller = "Blog", action = "Article" });
app.MapControllerRoute(name: "default",
               pattern: "{controller=Home}/{action=Index}/{id?}");
Med hjälp av de föregående ruttdefinitionerna genererar Url.Action("Index", "Home") URL-sökvägen / med rutt default, men varför? Du kan gissa att vägvärdena { controller = Home, action = Index } räcker för att generera en URL med , blogoch resultatet blir /blog?action=Index&controller=Home.
              Dedikerade konventionella vägar förlitar sig på ett särskilt beteende med standardvärden som inte har en motsvarande vägparameter som förhindrar att vägen blir för girig med URL-generering. I det här fallet är { controller = Blog, action = Article }standardvärdena , och varken controller eller action visas som en vägparameter. När routningen utför URL-generering måste de angivna värdena matcha standardvärdena. URL-genereringen med hjälp av blog misslyckas eftersom värdena { controller = Home, action = Index } inte matchar { controller = Blog, action = Article }. Routning faller sedan tillbaka för att prova default, vilket lyckas.
Areas
Områden är en MVC-funktion som används för att organisera relaterade funktioner i en grupp som en separat:
- Routningsnamnområde för kontrollantåtgärder.
- Mappstruktur för vyer.
Med hjälp av områden kan en app ha flera kontrollanter med samma namn, så länge de har olika områden. Med hjälp av områden skapas en hierarki för routning genom att lägga till en annan routningsparameter, area till controller och action. I det här avsnittet beskrivs hur routning interagerar med områden. Mer information om hur områden används med vyer finns i Områden .
I följande exempel konfigureras MVC att använda standardrutt för konventionell väg och en area rutt för en area som heter Blog.
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllersWithViews();
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{    
    app.UseExceptionHandler("/Home/Error");
    app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthorization();
app.MapAreaControllerRoute("blog_route", "Blog",
        "Manage/{controller}/{action}/{id?}");
app.MapControllerRoute("default_route", "{controller}/{action}/{id?}");
app.Run();
I föregående kod MapAreaControllerRoute anropas för att skapa "blog_route". Den andra parametern, "Blog", är områdesnamnet.
När du matchar en URL-sökväg som /Manage/Users/AddUser"blog_route" genererar vägen vägvärdena { area = Blog, controller = Users, action = AddUser }. Routningsvärdet area genereras av ett standardvärde för area. Den väg som skapas av MapAreaControllerRoute motsvarar följande:
app.MapControllerRoute("blog_route", "Manage/{controller}/{action}/{id?}",
        defaults: new { area = "Blog" }, constraints: new { area = "Blog" });
app.MapControllerRoute("default_route", "{controller}/{action}/{id?}");
              MapAreaControllerRoute skapar en väg med både ett standardvärde och en begränsning för area att använda det angivna områdesnamnet, i det här fallet Blog. Standardvärdet säkerställer att vägen alltid genererar { area = Blog, ... }, villkoret kräver värdet { area = Blog, ... } för URL-generering.
Konventionell routning är orderberoende. I allmänhet bör vägar med områden placeras tidigare eftersom de är mer specifika än vägar utan område.
Med hjälp av föregående exempel matchar vägvärdena { area = Blog, controller = Users, action = AddUser } följande åtgärd:
using Microsoft.AspNetCore.Mvc;
namespace MyApp.Namespace1
{
    [Area("Blog")]
    public class UsersController : Controller
    {
        // GET /manage/users/adduser
        public IActionResult AddUser()
        {
            var area = ControllerContext.ActionDescriptor.RouteValues["area"];
            var actionName = ControllerContext.ActionDescriptor.ActionName;
            var controllerName = ControllerContext.ActionDescriptor.ControllerName;
            return Content($"area name:{area}" +
                $" controller:{controllerName}  action name: {actionName}");
        }        
    }
}
Attributet [Area] är det som anger en kontrollant som en del av ett område. Den här styrenheten finns i området Blog . Kontrollanter utan attribut [Area] är inte medlemmar i något område och matchar inte när area routningsvärdet tillhandahålls av routning. I följande exempel kan endast den första kontrollanten i listan matcha vägvärdena { area = Blog, controller = Users, action = AddUser }.
using Microsoft.AspNetCore.Mvc;
namespace MyApp.Namespace1
{
    [Area("Blog")]
    public class UsersController : Controller
    {
        // GET /manage/users/adduser
        public IActionResult AddUser()
        {
            var area = ControllerContext.ActionDescriptor.RouteValues["area"];
            var actionName = ControllerContext.ActionDescriptor.ActionName;
            var controllerName = ControllerContext.ActionDescriptor.ControllerName;
            return Content($"area name:{area}" +
                $" controller:{controllerName}  action name: {actionName}");
        }        
    }
}
using Microsoft.AspNetCore.Mvc;
namespace MyApp.Namespace2
{
    // Matches { area = Zebra, controller = Users, action = AddUser }
    [Area("Zebra")]
    public class UsersController : Controller
    {
        // GET /zebra/users/adduser
        public IActionResult AddUser()
        {
            var area = ControllerContext.ActionDescriptor.RouteValues["area"];
            var actionName = ControllerContext.ActionDescriptor.ActionName;
            var controllerName = ControllerContext.ActionDescriptor.ControllerName;
            return Content($"area name:{area}" +
                $" controller:{controllerName}  action name: {actionName}");
        }        
    }
}
using Microsoft.AspNetCore.Mvc;
namespace MyApp.Namespace3
{
    // Matches { area = string.Empty, controller = Users, action = AddUser }
    // Matches { area = null, controller = Users, action = AddUser }
    // Matches { controller = Users, action = AddUser }
    public class UsersController : Controller
    {
        // GET /users/adduser
        public IActionResult AddUser()
        {
            var area = ControllerContext.ActionDescriptor.RouteValues["area"];
            var actionName = ControllerContext.ActionDescriptor.ActionName;
            var controllerName = ControllerContext.ActionDescriptor.ControllerName;
            return Content($"area name:{area}" +
                $" controller:{controllerName}  action name: {actionName}");
        }
    }
}
Namnområdet för varje kontrollant visas här för fullständighet. Om de föregående kontrollanterna använde samma namnområde genereras ett kompilatorfel. Klassnamnområden har ingen effekt på MVC:s routning.
De två första kontrollanterna är medlemmar i områden och matchar bara när deras respektive områdesnamn anges av area vägvärdet. Den tredje styrenheten är inte medlem i något område och kan bara matcha när inget värde för area tillhandahålls av routning.
När det gäller att matcha inget värde är frånvaron av area värdet densamma som om värdet för area var null eller den tomma strängen.
När du kör en åtgärd i ett område är routningsvärdet för area tillgängligt som ett omgivande värde för routning som ska användas för URL-generering. Det innebär att som standard fungerar områden som är klibbiga för URL-generering, vilket visas i följande exempel.
app.MapAreaControllerRoute(name: "duck_route",
                                     areaName: "Duck",
                                     pattern: "Manage/{controller}/{action}/{id?}");
app.MapControllerRoute(name: "default",
                             pattern: "Manage/{controller=Home}/{action=Index}/{id?}");
using Microsoft.AspNetCore.Mvc;
namespace MyApp.Namespace4
{
    [Area("Duck")]
    public class UsersController : Controller
    {
        // GET /Manage/users/GenerateURLInArea
        public IActionResult GenerateURLInArea()
        {
            // Uses the 'ambient' value of area.
            var url = Url.Action("Index", "Home");
            // Returns /Manage/Home/Index
            return Content(url);
        }
        // GET /Manage/users/GenerateURLOutsideOfArea
        public IActionResult GenerateURLOutsideOfArea()
        {
            // Uses the empty value for area.
            var url = Url.Action("Index", "Home", new { area = "" });
            // Returns /Manage
            return Content(url);
        }
    }
}
Följande kod genererar en URL till /Zebra/Users/AddUser:
public class HomeController : Controller
{
    public IActionResult About()
    {
        var url = Url.Action("AddUser", "Users", new { Area = "Zebra" });
        return Content($"URL: {url}");
    }
Åtgärdsdefinition
Offentliga metoder på en kontrollant, förutom de med attributet NonAction , är åtgärder.
Exempelkod
- MyDisplayRouteInfo tillhandahålls av Rick.Docs.Samples.RouteInfo NuGet-paketet och visar väginformation.
- Visa eller ladda ned exempelkod (hur du laddar ned)
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-styrenheter använder routningsmellanprogrammet för att matcha URL:erna för inkommande begäranden och mappa dem till åtgärder. Routningsmallar:
- Definieras i startkod eller attribut.
- Beskriv hur URL-sökvägar matchas med åtgärder.
- Används för att generera URL:er för länkar. De genererade länkarna returneras vanligtvis i svar.
Åtgärder är antingen konventionellt dirigerade eller attributroutade. Att placera en rutt på kontrollern eller åtgärden gör den attributbaserad. Mer information finns i Blandad routning .
Det här dokumentet:
- Förklarar interaktionerna mellan MVC och routning: - Hur vanliga MVC-appar använder routningsfunktioner.
- Omfattar båda: - Konventionell routning används vanligtvis med styrenheter och vyer.
- Attributroutning som används med REST API:er. Om du främst är intresserad av routning för REST API:er går du till avsnittet Attributroutning för REST API:er .
 
- Mer information om routning finns i Routning .
 
- Refererar till standarddirigeringssystemet som lagts till i ASP.NET Core 3.0, som kallas slutpunktsroutning. Det är möjligt att använda styrenheter med den tidigare versionen av routning i kompatibilitetssyfte. Anvisningar finns i migreringsguiden 2.2-3.0 . Se 2.2-versionen av det här dokumentet för referensmaterial i det äldre routningssystemet.
Konfigurera konventionell väg
              Startup.Configure har vanligtvis kod som liknar följande när du använder konventionell routning:
app.UseEndpoints(endpoints =>
{
    endpoints.MapControllerRoute(
        name: "default",
        pattern: "{controller=Home}/{action=Index}/{id?}");
});
Inuti anropet till UseEndpoints, MapControllerRoute används för att skapa en enda rutt. Den enda vägen heter default route. De flesta appar med kontrollanter och vyer använder en routningsmall som liknar default vägen. 
              REST API:er bör använda attributroutning.
Routningsmallen "{controller=Home}/{action=Index}/{id?}":
- Matchar en URL-sökväg som - /Products/Details/5
- Extraherar vägvärdena - { controller = Products, action = Details, id = 5 }genom att tokenisera sökvägen. Extrahering av vägvärden resulterar i en matchning om appen har en styrenhet med namnet- ProductsControlleroch en- Detailsåtgärd:- public class ProductsController : Controller { public IActionResult Details(int id) { return ControllerContext.MyDisplayRouteInfo(id); } }- MyDisplayRouteInfo tillhandahålls av Rick.Docs.Samples.RouteInfo NuGet-paketet och visar väginformation. 
- /Products/Details/5modellen binder värdet- id = 5för att ange parametern- idtill- 5. Mer information finns i Modellbindning .
- {controller=Home}definierar- Homesom standard- controller.
- {action=Index}definierar- Indexsom standard- action.
- Tecknet - ?i- {id?}definierar- idsom valfritt.
- Standard- och valfria vägparametrar behöver inte finnas i URL-sökvägen för en matchning. En detaljerad beskrivning av routningsmallssyntaxen finns i Referens för routningsmall . 
- Matchar URL-sökvägen - /.
- Genererar vägvärdena - { controller = Home, action = Index }.
Värdena för controller och action använder standardvärdena. 
              id ger inget värde eftersom det inte finns något motsvarande segment i URL-sökvägen. 
              / matchar endast om det finns en HomeController-åtgärd och Index.
public class HomeController : Controller
{
  public IActionResult Index() { ... }
}
Med hjälp av föregående kontrollantdefinition och vägmall HomeController.Index körs åtgärden för följande URL-sökvägar:
- /Home/Index/17
- /Home/Index
- /Home
- /
URL-sökvägen / använder standardkontrollanterna Home och Index åtgärden för routningsmallen. URL-sökvägen /Home använder standardåtgärden Index för routningsmallen.
Bekvämlighetsmetoden MapDefaultControllerRoute:
endpoints.MapDefaultControllerRoute();
Replaces:
endpoints.MapControllerRoute("default", "{controller=Home}/{action=Index}/{id?}");
Important
Routning konfigureras med hjälp av UseRoutingmellanprogrammet , MapControllerRouteoch MapAreaControllerRoute . Så här använder du kontroller:
- Anropa MapControllers inuti UseEndpointsför att mappa kontrollanter som använder attributbaserad ruttning.
- Anropa MapControllerRoute eller MapAreaControllerRouteför att mappa både konventionellt dirigerade kontrollanter och attributroutade kontrollanter.
Konventionell routning
Konventionell routning används med styrenheter och vyer. Vägen default :
endpoints.MapControllerRoute(
    name: "default",
    pattern: "{controller=Home}/{action=Index}/{id?}");
Föregående är ett exempel på en konventionell väg. Den kallas för konventionell routning eftersom den upprättar en konvention för URL-sökvägar:
- Det första sökvägssegmentet, {controller=Home}, mappar till kontrollantnamnet.
- Det andra segmentet, {action=Index}, mappar till åtgärdsnamnet .
- Det tredje segmentet {id?}används för en valfriid.?i{id?}gör det valfritt.idanvänds för att mappa till en modellentitet.
Med hjälp av den här default rutten, URL-sökvägen:
- 
              /Products/Listmappar till åtgärdenProductsController.List.
- 
              /Blog/Article/17mappar tillBlogController.Articleoch binder oftast parameternidtill 17.
Den här mappningen:
- Baseras endast på kontrollanten och åtgärdsnamnen.
- Baseras inte på namnrymder, källfilplatser eller metodparametrar.
Med konventionell routning med standardvägen kan du skapa appen utan att behöva komma med ett nytt URL-mönster för varje åtgärd. För en app med CRUD-formatåtgärder , med konsekvens för URL:er mellan kontrollanter:
- Hjälper till att förenkla koden.
- Gör användargränssnittet mer förutsägbart.
Warning
I id föregående kod definieras som valfri av routningsmallen. Åtgärder kan köras utan det valfria ID som anges som en del av URL:en. Vanligtvis när id utelämnas från URL:en:
- 
              idsätts till0av modellbindning.
- Ingen entitet hittades i databasen som matchar id == 0.
              Attributroutning ger detaljerad kontroll för att göra ID obligatoriskt för vissa åtgärder men inte för andra. Enligt konventionen innehåller dokumentationen valfria parametrar som id när de sannolikt kommer att visas i korrekt användning.
De flesta appar bör välja ett grundläggande och beskrivande routningsschema så att URL:er är läsbara och meningsfulla. Standardvägen för konventionell väg {controller=Home}/{action=Index}/{id?}:
- Stöder ett grundläggande och beskrivande routningsschema.
- Är en användbar startpunkt för användargränssnittsbaserade appar.
- Är den enda vägmall som behövs för många webbgränssnittsappar. För större webbgränssnittsappar är en annan väg som använder Områden ofta allt som behövs.
MapControllerRoute och MapAreaRoute :
- Tilldela automatiskt ett ordervärde till sina slutpunkter baserat på den ordning som de anropas.
Slutpunktsroutning i ASP.NET Core 3.0 eller senare:
- Har inget begrepp om vägar.
- Ger inte ordergarantier för körning av utökningsbarhet, alla slutpunkter bearbetas samtidigt.
Aktivera loggning för att se hur de inbyggda routningsimplementeringarna, till exempel Route, matchar begäranden.
Attributroutning förklaras senare i det här dokumentet.
Flera konventionella vägar
Flera konventionella vägar kan läggas till inuti UseEndpoints genom att lägga till fler anrop till MapControllerRoute och MapAreaControllerRoute. På så sätt kan du definiera flera konventioner eller lägga till konventionella vägar som är dedikerade till en specifik åtgärd, till exempel:
app.UseEndpoints(endpoints =>
{
    endpoints.MapControllerRoute(name: "blog",
                pattern: "blog/{*article}",
                defaults: new { controller = "Blog", action = "Article" });
    endpoints.MapControllerRoute(name: "default",
                pattern: "{controller=Home}/{action=Index}/{id?}");
});
Vägen blog i föregående kod är en dedikerad konventionell väg. Den kallas för en dedikerad konventionell väg eftersom:
- Den använder konventionell routning.
- Den är dedikerad till en specifik åtgärd.
Eftersom controller och action inte visas i routningsmallen "blog/{*article}" som parametrar:
- De kan bara ha standardvärdena { controller = "Blog", action = "Article" }.
- Den här rutten mappar alltid till åtgärden BlogController.Article.
              /Blog, /Blog/Articleoch /Blog/{any-string} är de enda URL-sökvägarna som matchar bloggvägen.
Föregående exempel:
- 
              blog-rutt har högre prioritet för matchningar ändefault-rutt eftersom den läggs till först.
- Är ett exempel på snigelformatsroutning där det är typiskt att ha ett artikelnamn som en del av URL:en.
Warning
I ASP.NET Core 3.0 eller senare gör routning inte följande:
- Definiera ett begrepp som kallas väg. 
              UseRoutinglägger till routningsmatchning till pipelinen för mellanprogram. MellanprogrammetUseRoutingtittar på den uppsättning slutpunkter som definierats i appen och väljer den bästa slutpunktsmatchningen baserat på begäran.
- Ge garantier om exekveringsordningen för extensibilitet som IRouteConstraint eller IActionConstraint.
Se Routning för referensmaterial om routning.
Konventionell routningsordning
Konventionell routning matchar bara en kombination av åtgärd och kontrollant som definieras av appen. Detta är avsett att förenkla fall där konventionella vägar överlappar varandra.
Lägga till vägar med hjälp av MapControllerRoute, MapDefaultControllerRouteoch MapAreaControllerRoute automatiskt tilldela ett ordervärde till sina slutpunkter baserat på den ordning som de anropas. Matchningar från en rutt som visas tidigare har högre prioritet. Konventionell routning är orderberoende. I allmänhet bör vägar med områden placeras tidigare eftersom de är mer specifika än vägar utan område. 
              Dedikerade konventionella vägar med catch-all-routningsparametrar som {*article} kan göra en väg för girig, vilket innebär att den matchar URL:er som du avsåg att matchas av andra vägar. Placera de giriga rutterna senare i ruttabellen för att förhindra giriga matchningar.
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.
Lösa tvetydiga åtgärder
När två slutpunkter matchar genom routning måste routning göra något av följande:
- Välj den bästa kandidaten.
- Kasta ett undantag.
Till exempel:
    public class Products33Controller : Controller
    {
        public IActionResult Edit(int id)
        {
            return ControllerContext.MyDisplayRouteInfo(id);
        }
        [HttpPost]
        public IActionResult Edit(int id, Product product)
        {
            return ControllerContext.MyDisplayRouteInfo(id, product.name);
        }
    }
}
Den föregående kontrollanten definierar två åtgärder som matchar:
- URL-sökvägen /Products33/Edit/17
- Ruttdata { controller = Products33, action = Edit, id = 17 }.
Detta är ett typiskt mönster för MVC-styrenheter:
- 
              Edit(int)visar ett formulär för att redigera en produkt.
- 
              Edit(int, Product)bearbetar det publicerade formuläret.
För att fastställa rätt rutt:
- 
              Edit(int, Product)väljs när begäran är en HTTPPOST.
- 
              Edit(int)väljs när HTTP-verbet är något annat.Edit(int)kallas vanligtvis viaGET.
              HttpPostAttribute, [HttpPost], tillhandahålls till routning så att det kan välja baserat på HTTP-metoden för begäran. 
              HttpPostAttribute gör Edit(int, Product) till en bättre matchning än Edit(int).
Det är viktigt att förstå rollen för attribut som HttpPostAttribute. Liknande attribut definieras för andra HTTP-verb. I konventionell routning är det vanligt att åtgärder använder samma åtgärdsnamn när de ingår i ett visningsformulär och skickar formulärarbetsflödet. Se till exempel Granska de två redigeringsmetoderna.
Om routning inte kan välja en bästa kandidat genereras en AmbiguousMatchException lista över de flera matchade slutpunkterna.
Namn på konventionella vägar
Strängarna "blog" och "default" i följande exempel är konventionella vägnamn:
app.UseEndpoints(endpoints =>
{
    endpoints.MapControllerRoute(name: "blog",
                pattern: "blog/{*article}",
                defaults: new { controller = "Blog", action = "Article" });
    endpoints.MapControllerRoute(name: "default",
                pattern: "{controller=Home}/{action=Index}/{id?}");
});
Routningsnamnen ger vägen ett logiskt namn. Den namngivna vägen kan användas för URL-generering. Med hjälp av en namngiven väg förenklas skapandet av URL när ordningen på vägar kan göra URL-genereringen komplicerad. Routningsnamn måste vara unika för hela programmet.
Routningsnamn:
- Påverka inte URL-matchning eller hantering av begäranden.
- Används endast för URL-generering.
Begreppet routningsnamn representeras i routning som IEndpointNameMetadata. Termen routningsnamn och slutpunktsnamn:
- Är utbytbara.
- Vilken som används i dokumentationen och koden beror på vilket API som beskrivs.
Attributroutning för REST API:er
REST API:er bör använda attributroutning för att modellera appens funktioner som en uppsättning resurser där åtgärder representeras av HTTP-verb.
Attributroutning använder en uppsättning attribut för att mappa åtgärder direkt till routningsmallar. Följande StartUp.Configure kod är typisk för ett REST API och används i nästa exempel:
public void ConfigureServices(IServiceCollection services)
{
    services.AddControllers();
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }
    app.UseHttpsRedirection();
    app.UseRouting();
    app.UseAuthorization();
    app.UseEndpoints(endpoints =>
    {
        endpoints.MapControllers();
    });
}
I föregående kod MapControllers anropas inuti UseEndpoints för att mappa attributroutade kontrollanter.
I följande exempel:
- 
              HomeControllermatchar en uppsättning URL:er som liknar vad den vanliga standardvägen{controller=Home}/{action=Index}/{id?}matchar.
public class HomeController : Controller
{
    [Route("")]
    [Route("Home")]
    [Route("Home/Index")]
    [Route("Home/Index/{id?}")]
    public IActionResult Index(int? id)
    {
        return ControllerContext.MyDisplayRouteInfo(id);
    }
    [Route("Home/About")]
    [Route("Home/About/{id?}")]
    public IActionResult About(int? id)
    {
        return ControllerContext.MyDisplayRouteInfo(id);
    }
}
Åtgärden HomeController.Index körs för någon av URL-sökvägarna /, /Home, /Home/Indexeller /Home/Index/3.
Det här exemplet visar en viktig programmeringsskillnad mellan attributroutning och konventionell routning. Attributroutning kräver mer indata för att ange en väg. Den konventionella standardvägen hanterar vägar mer kortfattat. Attributroutning tillåter dock och kräver exakt kontroll över vilka routningsmallar som gäller för varje åtgärd.
Med attributroutning spelar kontrollanten och åtgärdsnamnen ingen roll där åtgärden matchas, såvida inte tokenbyte används. Följande exempel matchar samma URL:er som i föregående exempel:
public class MyDemoController : Controller
{
    [Route("")]
    [Route("Home")]
    [Route("Home/Index")]
    [Route("Home/Index/{id?}")]
    public IActionResult MyIndex(int? id)
    {
        return ControllerContext.MyDisplayRouteInfo(id);
    }
    [Route("Home/About")]
    [Route("Home/About/{id?}")]
    public IActionResult MyAbout(int? id)
    {
        return ControllerContext.MyDisplayRouteInfo(id);
    }
}
Följande kod använder tokenersättning för action och controller:
public class HomeController : Controller
{
    [Route("")]
    [Route("Home")]
    [Route("[controller]/[action]")]
    public IActionResult Index()
    {
        return ControllerContext.MyDisplayRouteInfo();
    }
    [Route("[controller]/[action]")]
    public IActionResult About()
    {
        return ControllerContext.MyDisplayRouteInfo();
    }
}
Följande kod gäller [Route("[controller]/[action]")] för kontrollanten:
[Route("[controller]/[action]")]
public class HomeController : Controller
{
    [Route("~/")]
    [Route("/Home")]
    [Route("~/Home/Index")]
    public IActionResult Index()
    {
        return ControllerContext.MyDisplayRouteInfo();
    }
    public IActionResult About()
    {
        return ControllerContext.MyDisplayRouteInfo();
    }
}
I den föregående koden måste Index metodmallarna lägga till / eller ~/ till routemallarna. Routningsmallar som tillämpas på en åtgärd som börjar med / eller ~/ kombineras inte med routningsmallar som tillämpas på kontrollern.
Se Prioritet för routningsmall för information om val av routningsmall.
Namn på reserverad routning
Följande nyckelord är reserverade routningsparameternamn när du använder kontrollanter eller Razor sidor:
- action
- area
- controller
- handler
- page
Att använda page som routningsparameter med attributroutning är ett vanligt fel. Att göra det resulterar i inkonsekvent och förvirrande beteende med URL-generering.
public class MyDemo2Controller : Controller
{
    [Route("/articles/{page}")]
    public IActionResult ListArticles(int page)
    {
        return ControllerContext.MyDisplayRouteInfo(page);
    }
}
De särskilda parameternamnen används av URL-genereringen för att avgöra om en URL-genereringsåtgärd refererar till en Razor sida eller till en kontrollant.
Följande nyckelord är reserverade i kontexten för en Razor vy eller en Razor sida:
- page
- using
- namespace
- inject
- section
- inherits
- model
- addTagHelper
- removeTagHelper
Dessa nyckelord ska inte användas för länkgenerationer, modellbundna parametrar eller egenskaper på toppnivå.
HTTP-verbmallar
ASP.NET Core har följande HTTP-verbmallar:
Routningsmallar
ASP.NET Core har följande routningsmallar:
- Alla HTTP-verbmallar är routningsmallar.
- [Route]
Attributroutning med http-verbattribut
Tänk på följande kontrollant:
[Route("api/[controller]")]
[ApiController]
public class Test2Controller : ControllerBase
{
    [HttpGet]   // GET /api/test2
    public IActionResult ListProducts()
    {
        return ControllerContext.MyDisplayRouteInfo();
    }
    [HttpGet("{id}")]   // GET /api/test2/xyz
    public IActionResult GetProduct(string id)
    {
       return ControllerContext.MyDisplayRouteInfo(id);
    }
    [HttpGet("int/{id:int}")] // GET /api/test2/int/3
    public IActionResult GetIntProduct(int id)
    {
        return ControllerContext.MyDisplayRouteInfo(id);
    }
    [HttpGet("int2/{id}")]  // GET /api/test2/int2/3
    public IActionResult GetInt2Product(int id)
    {
        return ControllerContext.MyDisplayRouteInfo(id);
    }
}
I koden ovan:
- Varje åtgärd innehåller [HttpGet]attributet, som endast begränsar matchning till HTTP GET-begäranden.
- Åtgärden GetProductinnehåller mallen"{id}"och läggs därföridtill i mallen"api/[controller]"på kontrollanten. Mallen för metoder är"api/[controller]/{id}". Därför matchar den här åtgärden endast GET-begäranden för formuläret/api/test2/xyz,/api/test2/123/api/test2/{any string}osv.[HttpGet("{id}")] // GET /api/test2/xyz public IActionResult GetProduct(string id) { return ControllerContext.MyDisplayRouteInfo(id); }
- Åtgärden GetIntProductinnehåller mallen"int/{id:int}". Delen:intav mallen begränsaridvägvärdena till strängar som kan konverteras till ett heltal. En GET-begäran till/api/test2/int/abc:- Matchar inte den här åtgärden.
- Returnerar felet 404 Hittades inte .[HttpGet("int/{id:int}")] // GET /api/test2/int/3 public IActionResult GetIntProduct(int id) { return ControllerContext.MyDisplayRouteInfo(id); }
 
- Åtgärden GetInt2Productinnehåller{id}i mallen, men begränsaridinte till värden som kan konverteras till ett heltal. En GET-begäran till/api/test2/int2/abc:- Passar denna rutt.
- Modellbindningen kan inte konverteras abctill ett heltal. Parameternidför metoden är heltal.
- Returnerar en 400 felaktig begäran eftersom modellbindningen inte kunde konverteras abctill ett heltal.[HttpGet("int2/{id}")] // GET /api/test2/int2/3 public IActionResult GetInt2Product(int id) { return ControllerContext.MyDisplayRouteInfo(id); }
 
Attributroutning kan använda HttpMethodAttribute attribut som HttpPostAttribute, HttpPutAttributeoch HttpDeleteAttribute. Alla HTTP-verbsattribut accepterar en vägmall. I följande exempel visas två åtgärder som matchar samma vägmall:
[ApiController]
public class MyProductsController : ControllerBase
{
    [HttpGet("/products3")]
    public IActionResult ListProducts()
    {
        return ControllerContext.MyDisplayRouteInfo();
    }
    [HttpPost("/products3")]
    public IActionResult CreateProduct(MyProduct myProduct)
    {
        return ControllerContext.MyDisplayRouteInfo(myProduct.Name);
    }
}
Använda URL-sökvägen /products3:
- Åtgärden MyProductsController.ListProductskörs när HTTP-verbet ärGET.
- Åtgärden MyProductsController.CreateProductkörs när HTTP-verbet ärPOST.
När du skapar ett REST API är det ovanligt att du behöver använda [Route(...)] en åtgärdsmetod eftersom åtgärden accepterar alla HTTP-metoder. Det är bättre att använda det mer specifika HTTP-verbattributet för att vara exakt om vad ditt API stöder. Klienter för REST API:er förväntas veta vilka sökvägar och HTTP-verb som mappar till specifika logiska åtgärder.
REST API:er bör använda attributroutning för att modellera appens funktioner som en uppsättning resurser där åtgärder representeras av HTTP-verb. Det innebär att många åtgärder, till exempel GET och POST på samma logiska resurs, använder samma URL. Attributroutning ger en kontrollnivå som krävs för att noggrant utforma ett API:s offentliga slutpunktslayout.
Eftersom en attributväg gäller för en specifik åtgärd är det enkelt att göra parametrar som krävs som en del av definitionen av routningsmallen. I följande exempel id krävs som en del av URL-sökvägen:
[ApiController]
public class Products2ApiController : ControllerBase
{
    [HttpGet("/products2/{id}", Name = "Products_List")]
    public IActionResult GetProduct(int id)
    {
        return ControllerContext.MyDisplayRouteInfo(id);
    }
}
Åtgärden Products2ApiController.GetProduct(int) :
- Körs med URL-sökväg som /products2/3
- Körs inte med URL-sökvägen /products2.
Attributet [Förbrukar] tillåter en åtgärd för att begränsa innehållstyperna för begäranden som stöds. Mer information finns i Definiera innehållstyper för begäranden som stöds med attributet Förbrukar.
Se Routning för en fullständig beskrivning av routningsmallar och relaterade alternativ.
Mer information om [ApiController]finns i ApiController-attribut.
Routningsnamn
Följande kod definierar vägnamnet Products_List:
[ApiController]
public class Products2ApiController : ControllerBase
{
    [HttpGet("/products2/{id}", Name = "Products_List")]
    public IActionResult GetProduct(int id)
    {
        return ControllerContext.MyDisplayRouteInfo(id);
    }
}
Routningsnamn kan användas för att generera en URL baserat på en specifik väg. Routningsnamn:
- Ha ingen inverkan på url-matchningsbeteendet för routning.
- Används endast för URL-generering.
Routningsnamn måste vara unika för hela programmet.
Kontrastera föregående kod med den konventionella standardvägen, som definierar parametern id som valfri ({id?}). Möjligheten att exakt ange API:er har fördelar, till exempel att tillåta /products och /products/5 skickas till olika åtgärder.
Kombinera attributvägar
För att göra attributdirigering mindre repetitiv kombineras routningsattributen på kontrollanten med routningsattribut för de enskilda åtgärderna. Alla vägmallar som definierats på kontrollern läggs till före vägmallarna på åtgärderna. Om du placerar ett routningsattribut på kontrollanten används attributdirigering för alla åtgärder i kontrollanten.
[ApiController]
[Route("products")]
public class ProductsApiController : ControllerBase
{
    [HttpGet]
    public IActionResult ListProducts()
    {
        return ControllerContext.MyDisplayRouteInfo();
    }
    [HttpGet("{id}")]
    public IActionResult GetProduct(int id)
    {
        return ControllerContext.MyDisplayRouteInfo(id);
    }
}
I föregående exempel:
- URL-sökvägen /productskan matchaProductsApi.ListProducts
- URL-sökvägen /products/5kan matchaProductsApi.GetProduct(int).
Båda dessa åtgärder matchar bara HTTP GET eftersom de har markerats med attributet [HttpGet] .
Routningsmallar som tillämpas på en åtgärd som börjar med / eller ~/ kombineras inte med routningsmallar som tillämpas på kontrollern. Följande exempel matchar en uppsättning URL-sökvägar som liknar standardvägen.
[Route("Home")]
public class HomeController : Controller
{
    [Route("")]
    [Route("Index")]
    [Route("/")]
    public IActionResult Index()
    {
        return ControllerContext.MyDisplayRouteInfo();
    }
    [Route("About")]
    public IActionResult About()
    {
        return ControllerContext.MyDisplayRouteInfo();
    }
}
I följande tabell förklaras attributen [Route] i föregående kod:
| Attribute | Kombinerar med [Route("Home")] | Definierar routningsmall | 
|---|---|---|
| [Route("")] | Yes | "Home" | 
| [Route("Index")] | Yes | "Home/Index" | 
| [Route("/")] | No | "" | 
| [Route("About")] | Yes | "Home/About" | 
Ordning för attributrutter
Routning skapar ett träd och matchar alla slutpunkter samtidigt:
- Routningsposterna beter sig som om de vore placerade i en idealisk ordning.
- De mest specifika rutterna har möjlighet att köras före de mer allmänna rutterna.
Till exempel är en attributväg som blog/search/{topic} är mer specifik än en attributväg som blog/{*article}. Vägen blog/search/{topic} har högre prioritet, som standard, eftersom den är mer specifik. Med hjälp av konventionell routning ansvarar utvecklaren för att placera vägar i önskad ordning.
Attributvägar kan konfigurera en ordning med hjälp av egenskapen Order. Alla routningsattribut som tillhandahålls av ramverket är Order . Vägar bearbetas enligt en stigande typ av Order egenskapen. Standardordningen är 0. Ange en rutt med Order = -1 innan rutter som inte anger någon ordning. Ställ in en rutt genom Order = 1 som körs efter standardruttordning.
              Undvik beroende på Order. Om en apps URL-utrymme kräver explicita ordervärden för att dirigeras korrekt är det sannolikt förvirrande även för klienter. I allmänhet väljer attributroutning rätt väg med URL-matchning. Om standardordningen som används för URL-generering inte fungerar är det vanligtvis enklare att använda ett routningsnamn som åsidosättning än att tillämpa Order egenskapen.
Överväg följande två kontrollanter som båda definierar routningsmatchningen /home:
public class HomeController : Controller
{
    [Route("")]
    [Route("Home")]
    [Route("Home/Index")]
    [Route("Home/Index/{id?}")]
    public IActionResult Index(int? id)
    {
        return ControllerContext.MyDisplayRouteInfo(id);
    }
    [Route("Home/About")]
    [Route("Home/About/{id?}")]
    public IActionResult About(int? id)
    {
        return ControllerContext.MyDisplayRouteInfo(id);
    }
}
public class MyDemoController : Controller
{
    [Route("")]
    [Route("Home")]
    [Route("Home/Index")]
    [Route("Home/Index/{id?}")]
    public IActionResult MyIndex(int? id)
    {
        return ControllerContext.MyDisplayRouteInfo(id);
    }
    [Route("Home/About")]
    [Route("Home/About/{id?}")]
    public IActionResult MyAbout(int? id)
    {
        return ControllerContext.MyDisplayRouteInfo(id);
    }
}
Om du begär /home med föregående kod genereras ett undantag som liknar följande:
AmbiguousMatchException: The request matched multiple endpoints. Matches:
 WebMvcRouting.Controllers.HomeController.Index
 WebMvcRouting.Controllers.MyDemoController.MyIndex
Om du lägger Order till något av routningsattributen löses tvetydigheten:
[Route("")]
[Route("Home", Order = 2)]
[Route("Home/MyIndex")]
public IActionResult MyIndex()
{
    return ControllerContext.MyDisplayRouteInfo();
}
Med den föregående koden kör /home slutpunkten HomeController.Index. För att komma till MyDemoController.MyIndex, begär /home/MyIndex. 
              Note:
- Föregående kod är ett exempel eller dålig routningsdesign. Den användes för att illustrera egenskapen Order.
- Egenskapen Orderlöser bara tvetydigheten, den mallen kan inte matchas. Det vore bättre att ta bort mallen[Route("Home")].
Se Razor Sidors routnings- och appkonventioner: Routningsordning för information om routningsordning med Razor Sidor.
I vissa fall returneras ett HTTP 500-fel med tvetydiga vägar. Använd loggning för att se vilka ändpunkter som orsakade AmbiguousMatchException.
Ersättning av tokens i vägmallar [kontroller], [aktion], [område]
För enkelhetens skull stöder attributvägar tokenbyte genom att omsluta en token i hakparenteser ([, ]). Token , [action]och [area] ersätts med värdena för åtgärdsnamnet[controller], områdesnamnet och kontrollantnamnet från åtgärden där vägen definieras:
[Route("[controller]/[action]")]
public class Products0Controller : Controller
{
    [HttpGet]
    public IActionResult List()
    {
        return ControllerContext.MyDisplayRouteInfo();
    }
    [HttpGet("{id}")]
    public IActionResult Edit(int id)
    {
        return ControllerContext.MyDisplayRouteInfo(id);
    }
}
I koden ovan:
[HttpGet]
public IActionResult List()
{
    return ControllerContext.MyDisplayRouteInfo();
}
- Matcher /Products0/List
[HttpGet("{id}")]
public IActionResult Edit(int id)
{
    return ControllerContext.MyDisplayRouteInfo(id);
}
- Matcher /Products0/Edit/{id}
Tokenbyte sker som det sista steget för att skapa attributvägarna. Föregående exempel beter sig på samma sätt som följande kod:
public class Products20Controller : Controller
{
    [HttpGet("[controller]/[action]")]  // Matches '/Products20/List'
    public IActionResult List()
    {
        return ControllerContext.MyDisplayRouteInfo();
    }
    [HttpGet("[controller]/[action]/{id}")]   // Matches '/Products20/Edit/{id}'
    public IActionResult Edit(int id)
    {
        return ControllerContext.MyDisplayRouteInfo(id);
    }
}
Om du läser detta på ett annat språk än engelska kan du meddela oss i det här GitHub-diskussionsproblemet om du vill se kodkommentarna på ditt modersmål.
Attributvägar kan också kombineras med arv. Detta är kraftfullt kombinerat med tokenbyte. Tokenbyte gäller även för routningsnamn som definierats av attributvägar.
              [Route("[controller]/[action]", Name="[controller]_[action]")]genererar ett unikt vägnamn för varje åtgärd:
[ApiController]
[Route("api/[controller]/[action]", Name = "[controller]_[action]")]
public abstract class MyBase2Controller : ControllerBase
{
}
public class Products11Controller : MyBase2Controller
{
    [HttpGet]                      // /api/products11/list
    public IActionResult List()
    {
        return ControllerContext.MyDisplayRouteInfo();
    }
    [HttpGet("{id}")]             //    /api/products11/edit/3
    public IActionResult Edit(int id)
    {
        return ControllerContext.MyDisplayRouteInfo(id);
    }
}
Om du vill matcha den literala tokenbyteslimiten [ eller ], tar du bort den genom att upprepa tecknet ([[ eller ]]).
Använda en parametertransformator för att anpassa tokenbyte
Tokenbyte kan anpassas med hjälp av en parametertransformator. En parametertransformator implementerar IOutboundParameterTransformer och transformerar värdet för parametrar. En anpassad SlugifyParameterTransformer parametertransformator ändrar till exempel routningsvärdet SubscriptionManagement till subscription-management:
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();
    }
}
RouteTokenTransformerConvention Är en konvention för programmodell som:
- Tillämpar en parametertransformator på alla attributvägar i ett program.
- Anpassar attributvägens tokenvärden när de ersätts.
public class SubscriptionManagementController : Controller
{
    [HttpGet("[controller]/[action]")]
    public IActionResult ListAll()
    {
        return ControllerContext.MyDisplayRouteInfo();
    }
}
              ListAll Föregående metod matchar /subscription-management/list-all.
              RouteTokenTransformerConvention är registrerat som ett alternativ i ConfigureServices.
public void ConfigureServices(IServiceCollection services)
{
    services.AddControllersWithViews(options =>
    {
        options.Conventions.Add(new RouteTokenTransformerConvention(
                                     new SlugifyParameterTransformer()));
    });
}
Se MDN-webbdokument på Slug för definitionen av Slug.
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 attributvägar
Attributroutning stöder definition av flera vägar som når samma åtgärd. Den vanligaste användningen av detta är att efterlikna beteendet för den vanliga konventionella vägen enligt följande exempel:
[Route("[controller]")]
public class Products13Controller : Controller
{
    [Route("")]     // Matches 'Products13'
    [Route("Index")] // Matches 'Products13/Index'
    public IActionResult Index()
    {
        return ControllerContext.MyDisplayRouteInfo();
    }
Om du placerar flera routningsattribut på kontrollanten innebär det att var och en kombineras med vart och ett av routningsattributen på åtgärdsmetoderna:
[Route("Store")]
[Route("[controller]")]
public class Products6Controller : Controller
{
    [HttpPost("Buy")]       // Matches 'Products6/Buy' and 'Store/Buy'
    [HttpPost("Checkout")]  // Matches 'Products6/Checkout' and 'Store/Checkout'
    public IActionResult Buy()
    {
        return ControllerContext.MyDisplayRouteInfo();
    }
}
Alla villkor för HTTP-verbvägen implementerar IActionConstraint.
När flera routattribut som implementerar IActionConstraint placeras till en åtgärd:
- Varje åtgärdsbegränsning kombineras med routningsmallen som tillämpas på kontrollanten.
[Route("api/[controller]")]
public class Products7Controller : ControllerBase
{
    [HttpPut("Buy")]        // Matches PUT 'api/Products7/Buy'
    [HttpPost("Checkout")]  // Matches POST 'api/Products7/Checkout'
    public IActionResult Buy()
    {
        return ControllerContext.MyDisplayRouteInfo();
    }
}
Om du använder flera vägar för åtgärder kan det verka användbart och kraftfullt. Det är bättre att hålla appens URL-utrymme grundläggande och väldefinierat. Använd flera vägar för åtgärder endast där det behövs, till exempel för att stödja befintliga kunder.
Ange valfria parametrar för attributväg, standardvärden och begränsningar
Attributvägar stöder samma infogade syntax som konventionella vägar för att ange valfria parametrar, standardvärden och begränsningar.
public class Products14Controller : Controller
{
    [HttpPost("product14/{id:int}")]
    public IActionResult ShowProduct(int id)
    {
        return ControllerContext.MyDisplayRouteInfo(id);
    }
}
I föregående kod [HttpPost("product14/{id:int}")] tillämpar du en routningsbegränsning. Åtgärden Products14Controller.ShowProduct matchas endast av URL-sökvägar som /product14/3. Routningsmalldelen {id:int} begränsar segmentet till enbart heltal.
En detaljerad beskrivning av routningsmallssyntaxen finns i Referens för routningsmall .
Anpassade routningsattribut med IRouteTemplateProvider
Alla routningsattribut implementerar IRouteTemplateProvider. ASP.NET Core körmiljö:
- Söker efter attribut på kontrollantklasser och åtgärdsmetoder när appen startar.
- Använder attributen som implementerar IRouteTemplateProviderför att skapa den initiala uppsättningen rutter.
Implementera IRouteTemplateProvider för att definiera anpassade routningsattribut. Varje IRouteTemplateProvider gör att du kan definiera en enskild rutt med en anpassad ruttmall, ordning och namn:
public class MyApiControllerAttribute : Attribute, IRouteTemplateProvider
{
    public string Template => "api/[controller]";
    public int? Order => 2;
    public string Name { get; set; }
}
[MyApiController]
[ApiController]
public class MyTestApiController : ControllerBase
{
    // GET /api/MyTestApi
    [HttpGet]
    public IActionResult Get()
    {
        return ControllerContext.MyDisplayRouteInfo();
    }
}
              Get Föregående metod returnerar Order = 2, Template = api/MyTestApi.
Använda programmodell för att anpassa attributvägar
Programmodellen:
- En objektmodell skapas vid start.
- Innehåller alla metadata som används av ASP.NET Core för att dirigera och köra åtgärderna i en app.
Programmodellen innehåller alla data som samlas in från routningsattribut. Data från routningsattribut tillhandahålls av implementeringen IRouteTemplateProvider . Conventions:
- Kan skrivas för att ändra programmodellen för att anpassa hur routning fungerar.
- När appen startar läses de.
Det här avsnittet visar ett grundläggande exempel på hur du anpassar routning med hjälp av programmodellen. Följande kod gör vägarna ungefär i linje med projektets mappstruktur.
public class NamespaceRoutingConvention : Attribute, IControllerModelConvention
{
    private readonly string _baseNamespace;
    public NamespaceRoutingConvention(string baseNamespace)
    {
        _baseNamespace = baseNamespace;
    }
    public void Apply(ControllerModel controller)
    {
        var hasRouteAttributes = controller.Selectors.Any(selector =>
                                                selector.AttributeRouteModel != null);
        if (hasRouteAttributes)
        {
            return;
        }
        var namespc = controller.ControllerType.Namespace;
        if (namespc == null)
            return;
        var template = new StringBuilder();
        template.Append(namespc, _baseNamespace.Length + 1,
                        namespc.Length - _baseNamespace.Length - 1);
        template.Replace('.', '/');
        template.Append("/[controller]/[action]/{id?}");
        foreach (var selector in controller.Selectors)
        {
            selector.AttributeRouteModel = new AttributeRouteModel()
            {
                Template = template.ToString()
            };
        }
    }
}
Följande kod förhindrar att konventionen namespace tillämpas på kontroller som är attributroutade:
public void Apply(ControllerModel controller)
{
    var hasRouteAttributes = controller.Selectors.Any(selector =>
                                            selector.AttributeRouteModel != null);
    if (hasRouteAttributes)
    {
        return;
    }
Följande styrenhet använder NamespaceRoutingConventiontill exempel inte :
[Route("[controller]/[action]/{id?}")]
public class ManagersController : Controller
{
    // /managers/index
    public IActionResult Index()
    {
        var template = ControllerContext.ActionDescriptor.AttributeRouteInfo?.Template;
        return Content($"Index- template:{template}");
    }
    public IActionResult List(int? id)
    {
        var path = Request.Path.Value;
        return Content($"List- Path:{path}");
    }
}
              NamespaceRoutingConvention.Apply-metoden:
- Gör ingenting om kontrollen är attribut-routerad.
- Anger kontrollantmallen baserat på namespace, med basennamespaceborttagen.
              NamespaceRoutingConvention Kan användas i Startup.ConfigureServices:
namespace My.Application
{
    public class Startup
    {
        public Startup(IConfiguration configuration)
        {
            Configuration = configuration;
        }
        public IConfiguration Configuration { get; }
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddControllersWithViews(options =>
            {
                options.Conventions.Add(
                    new NamespaceRoutingConvention(typeof(Startup).Namespace));
            });
        }
        // Remaining code ommitted for brevity.
Tänk till exempel på följande kontrollant:
using Microsoft.AspNetCore.Mvc;
namespace My.Application.Admin.Controllers
{
    public class UsersController : Controller
    {
        // GET /admin/controllers/users/index
        public IActionResult Index()
        {
            var fullname = typeof(UsersController).FullName;
            var template = 
                ControllerContext.ActionDescriptor.AttributeRouteInfo?.Template;
            var path = Request.Path.Value;
            return Content($"Path: {path} fullname: {fullname}  template:{template}");
        }
        public IActionResult List(int? id)
        {
            var path = Request.Path.Value;
            return Content($"Path: {path} ID:{id}");
        }
    }
}
I koden ovan:
- Basen namespaceärMy.Application.
- Det fullständiga namnet på den föregående kontrollanten är My.Application.Admin.Controllers.UsersController.
- Anger NamespaceRoutingConventionkontrollantmallen tillAdmin/Controllers/Users/[action]/{id?.
              NamespaceRoutingConvention Kan också användas som ett attribut på en kontrollant:
[NamespaceRoutingConvention("My.Application")]
public class TestController : Controller
{
    // /admin/controllers/test/index
    public IActionResult Index()
    {
        var template = ControllerContext.ActionDescriptor.AttributeRouteInfo?.Template;
        var actionname = ControllerContext.ActionDescriptor.ActionName;
        return Content($"Action- {actionname} template:{template}");
    }
    public IActionResult List(int? id)
    {
        var path = Request.Path.Value;
        return Content($"List- Path:{path}");
    }
}
Blandad routning: Attributroutning jämfört med konventionell routning
ASP.NET Core-appar kan blanda användningen av konventionell routning och attributroutning. Det är vanligt att använda konventionella vägar för kontrollanter som betjänar HTML-sidor för webbläsare och attributroutning för kontrollanter som betjänar REST API:er.
Åtgärder dirigeras antingen konventionellt eller dirigeras med attribut. Om du placerar en väg på kontrollanten eller åtgärden dirigeras attributet. Åtgärder som definierar attributvägar kan inte nås via konventionella vägar och vice versa. Varje routningsattribut på kontrollern gör alla åtgärder i kontrollern dirigerade.
Attributroutning och konventionell routning använder samma routningsmotor.
URL-generering och omgivande värden
Appar kan använda genereringsfunktioner för routnings-URL för att generera URL-länkar till åtgärder. Att generera URL:er eliminerar hårdkodnings-URL:er, vilket gör koden mer robust och underhållsbar. Det här avsnittet fokuserar på url-genereringsfunktionerna som tillhandahålls av MVC och omfattar endast grunderna för hur URL-generering fungerar. Se Routning för en detaljerad beskrivning av URL-generering.
Gränssnittet IUrlHelper är det underliggande elementet i infrastrukturen mellan MVC och routning för URL-generering. En instans av IUrlHelper är tillgänglig via Url egenskapen i kontrollanter, vyer och visningskomponenter.
I följande exempel IUrlHelper används gränssnittet via egenskapen Controller.Url för att generera en URL till en annan åtgärd.
public class UrlGenerationController : Controller
{
    public IActionResult Source()
    {
        // Generates /UrlGeneration/Destination
        var url = Url.Action("Destination");
        return ControllerContext.MyDisplayRouteInfo("", $" URL = {url}");
    }
    public IActionResult Destination()
    {
        return ControllerContext.MyDisplayRouteInfo();
    }
}
Om appen använder den vanliga standardvägen är värdet för variabeln url URL-sökvägssträngen /UrlGeneration/Destination. Den här URL-sökvägen skapas genom routning genom att kombinera:
- Routningsvärdena från den aktuella begäran, som kallas för omgivande värden.
- Värdena som skickas till Url.Actionoch de värden som ersätter dessa i routmallen:
ambient values: { controller = "UrlGeneration", action = "Source" }
values passed to Url.Action: { controller = "UrlGeneration", action = "Destination" }
route template: {controller}/{action}/{id?}
result: /UrlGeneration/Destination
Varje ruttparameter i vägmallen får sitt värde ersatt av att matcha namn med värden och omgivande värden. En vägparameter som inte har något värde kan:
- Använd ett standardvärde om det har ett.
- Hoppas över om det är valfritt. Till exempel idfrån vägmallen{controller}/{action}/{id?}.
URL-genereringen misslyckas om någon obligatorisk vägparameter inte har något motsvarande värde. Om URL-genereringen misslyckas för en väg provas nästa väg tills alla vägar har provats eller en matchning hittas.
Föregående exempel på Url.Action förutsätter konventionell routning. URL-generering fungerar på samma sätt med attributroutning, även om begreppen skiljer sig. Med konventionell routning:
- Vägvärdena används för att expandera en mall.
- Vägvärdena för controllerochactionvisas vanligtvis i mallen. Detta fungerar eftersom URL:erna som matchas av routning följer en konvention.
I följande exempel används attributroutning:
public class UrlGenerationAttrController : Controller
{
    [HttpGet("custom")]
    public IActionResult Source()
    {
        var url = Url.Action("Destination");
        return ControllerContext.MyDisplayRouteInfo("", $" URL = {url}");
    }
    [HttpGet("custom/url/to/destination")]
    public IActionResult Destination()
    {
       return ControllerContext.MyDisplayRouteInfo();
    }
}
Åtgärden Source i föregående kod genererar custom/url/to/destination.
              LinkGenerator lades till i ASP.NET Core 3.0 som ett alternativ till IUrlHelper. 
              LinkGenerator erbjuder liknande men mer flexibla funktioner. Varje metod på IUrlHelper har också en motsvarande uppsättning metoder LinkGenerator .
Generera URL:er efter åtgärdsnamn
Url.Action, LinkGenerator.GetPathByAction och alla relaterade överlagringar är alla utformade för att generera målslutpunkten genom att ange ett kontrollantnamn och åtgärdsnamn.
När du använder Url.Action, tillhandahålls de aktuella ruttvärdena för controller och action av körningstiden.
- Värdet för controllerochactionär en del av både omgivande värden och värden. MetodenUrl.Actionanvänder alltid de aktuella värdenaactionför ochcontrolleroch genererar en URL-sökväg som dirigerar till den aktuella åtgärden.
Routning försöker använda värdena i omgivande värden för att fylla i information som inte angavs när en URL genererades. Överväg en väg som {a}/{b}/{c}/{d} med omgivande värden { a = Alice, b = Bob, c = Carol, d = David }:
- Routning har tillräckligt med information för att generera en URL utan ytterligare värden.
- Routning har tillräckligt med information eftersom alla vägparametrar har ett värde.
Om värdet { d = Donovan } läggs till:
- Värdet { d = David }ignoreras.
- Den genererade URL-sökvägen är Alice/Bob/Carol/Donovan.
              Varning! URL-sökvägar är hierarkiska. Om värdet { c = Cheryl } läggs till i föregående exempel:
- Båda värdena { c = Carol, d = David }ignoreras.
- Det finns inte längre något värde för doch URL-genereringen misslyckas.
- Önskade värden för cochdmåste anges för att generera en URL.
Du kan förvänta dig att stöta på det här problemet med standardvägen {controller}/{action}/{id?}. Det här problemet är sällsynt i praktiken eftersom Url.Action alltid uttryckligen anger ett controller och action -värde.
Flera överlagringar av URL.Action använder ett vägvärdesobjekt för att ange värden för andra vägparametrar än controller och action. Objektet för vägvärden används ofta med id. Till exempel Url.Action("Buy", "Products", new { id = 17 }). Objektet för ruttvärden
- Enligt konvention är det vanligtvis ett objekt av anonym typ.
- Kan vara en IDictionary<>eller en POCO).
Eventuella ytterligare vägvärden som inte matchar routningsparametrar placeras i frågesträngen.
public IActionResult Index()
{
    var url = Url.Action("Buy", "Products", new { id = 17, color = "red" });
    return Content(url);
}
Föregående kod genererar /Products/Buy/17?color=red.
Följande kod genererar en absolut URL:
public IActionResult Index2()
{
    var url = Url.Action("Buy", "Products", new { id = 17 }, protocol: Request.Scheme);
    // Returns https://localhost:5001/Products/Buy/17
    return Content(url);
}
Om du vill skapa en absolut URL använder du något av följande:
- En överbelastning som accepterar en protocol. Till exempel föregående kod.
- LinkGenerator.GetUriByAction, som genererar absoluta URI:er som standard.
Generera URL:er efter väg
Föregående kod visade hur du genererade en URL genom att skicka in kontrollanten och åtgärdsnamnet. 
              IUrlHelper innehåller också url.RouteUrl-serien med metoder. Dessa metoder liknar Url.Action, men de kopierar inte de aktuella värdena action för och controller till vägvärdena. Den vanligaste användningen av Url.RouteUrl:
- Anger ett vägnamn för att generera URL:en.
- I allmänhet anger inte en kontrollant eller åtgärdsnamn.
public class UrlGeneration2Controller : Controller
{
    [HttpGet("")]
    public IActionResult Source()
    {
        var url = Url.RouteUrl("Destination_Route");
        return ControllerContext.MyDisplayRouteInfo("", $" URL = {url}");
    }
    [HttpGet("custom/url/to/destination2", Name = "Destination_Route")]
    public IActionResult Destination()
    {
        return ControllerContext.MyDisplayRouteInfo();
    }
Följande Razor fil genererar en HTML-länk till Destination_Route:
<h1>Test Links</h1>
<ul>
    <li><a href="@Url.RouteUrl("Destination_Route")">Test Destination_Route</a></li>
</ul>
Generera URL:er i HTML och Razor
              IHtmlHelper
              HtmlHelper innehåller metoderna Html.BeginForm och Html.ActionLink för att generera <form><a> respektive element. Dessa metoder använder metoden Url.Action för att generera en URL och de accepterar liknande argument. Följeslagare Url.RouteUrl för HtmlHelper är Html.BeginRouteForm och Html.RouteLink som har liknande funktioner.
TagHelpers genererar URL:er via form TagHelper och <a> TagHelper. Båda dessa använder IUrlHelper för deras implementering. För mer information, se Tag Helpers i formulär.
I vyer, IUrlHelper finns tillgänglig via Url den egenskapen för alla ad hoc-URL-genereringar som inte omfattas av ovanstående.
URL-generering i åtgärdsresultat
De föregående exemplen visade hur man använder IUrlHelper i en kontroller. Det vanligaste syftet med en kontroller är att generera en URL som en del av ett åtgärdsresultat.
Basklasserna ControllerBase och Controller tillhandahåller bekvämlighetsmetoder för åtgärdsresultat som refererar till en annan åtgärd. En vanlig användning är att omdirigera efter att ha accepterat användarindata:
[HttpPost]
[ValidateAntiForgeryToken]
public IActionResult Edit(int id, Customer customer)
{
    if (ModelState.IsValid)
    {
        // Update DB with new details.
        ViewData["Message"] = $"Successful edit of customer {id}";
        return RedirectToAction("Index");
    }
    return View(customer);
}
Metoder för åtgärdsresultat som RedirectToAction och CreatedAtAction följer ett liknande mönster som metoderna hos IUrlHelper.
Specialfall för dedikerade konventionella vägar
              Konventionell routning kan använda en särskild typ av vägdefinition som kallas en dedikerad konventionell väg. I följande exempel är den väg som heter blog en dedikerad konventionell väg:
app.UseEndpoints(endpoints =>
{
    endpoints.MapControllerRoute(name: "blog",
                pattern: "blog/{*article}",
                defaults: new { controller = "Blog", action = "Article" });
    endpoints.MapControllerRoute(name: "default",
                pattern: "{controller=Home}/{action=Index}/{id?}");
});
Med hjälp av de föregående ruttdefinitionerna genererar Url.Action("Index", "Home") URL-sökvägen / med rutt default, men varför? Du kan gissa att vägvärdena { controller = Home, action = Index } räcker för att generera en URL med , blogoch resultatet blir /blog?action=Index&controller=Home.
              Dedikerade konventionella vägar förlitar sig på ett särskilt beteende med standardvärden som inte har en motsvarande vägparameter som förhindrar att vägen blir för girig med URL-generering. I det här fallet är { controller = Blog, action = Article }standardvärdena , och varken controller eller action visas som en vägparameter. När routningen utför URL-generering måste de angivna värdena matcha standardvärdena. URL-genereringen med hjälp av blog misslyckas eftersom värdena { controller = Home, action = Index } inte matchar { controller = Blog, action = Article }. Routning faller sedan tillbaka för att prova default, vilket lyckas.
Areas
Områden är en MVC-funktion som används för att organisera relaterade funktioner i en grupp som en separat:
- Routningsnamnområde för kontrollantåtgärder.
- Mappstruktur för vyer.
Med hjälp av områden kan en app ha flera kontrollanter med samma namn, så länge de har olika områden. Med hjälp av områden skapas en hierarki för routning genom att lägga till en annan routningsparameter, area till controller och action. I det här avsnittet beskrivs hur routning interagerar med områden. Mer information om hur områden används med vyer finns i Områden .
I följande exempel konfigureras MVC att använda standardrutt för konventionell väg och en area rutt för en area som heter Blog.
app.UseEndpoints(endpoints =>
{
    endpoints.MapAreaControllerRoute("blog_route", "Blog",
        "Manage/{controller}/{action}/{id?}");
    endpoints.MapControllerRoute("default_route", "{controller}/{action}/{id?}");
});
I föregående kod MapAreaControllerRoute anropas för att skapa "blog_route". Den andra parametern, "Blog", är områdesnamnet.
När du matchar en URL-sökväg som /Manage/Users/AddUser"blog_route" genererar vägen vägvärdena { area = Blog, controller = Users, action = AddUser }. Routningsvärdet area genereras av ett standardvärde för area. Den väg som skapas av MapAreaControllerRoute motsvarar följande:
app.UseEndpoints(endpoints =>
{
    endpoints.MapControllerRoute("blog_route", "Manage/{controller}/{action}/{id?}",
        defaults: new { area = "Blog" }, constraints: new { area = "Blog" });
    endpoints.MapControllerRoute("default_route", "{controller}/{action}/{id?}");
});
              MapAreaControllerRoute skapar en väg med både ett standardvärde och en begränsning för area att använda det angivna områdesnamnet, i det här fallet Blog. Standardvärdet säkerställer att vägen alltid genererar { area = Blog, ... }, villkoret kräver värdet { area = Blog, ... } för URL-generering.
Konventionell routning är orderberoende. I allmänhet bör vägar med områden placeras tidigare eftersom de är mer specifika än vägar utan område.
Med hjälp av föregående exempel matchar vägvärdena { area = Blog, controller = Users, action = AddUser } följande åtgärd:
using Microsoft.AspNetCore.Mvc;
namespace MyApp.Namespace1
{
    [Area("Blog")]
    public class UsersController : Controller
    {
        // GET /manage/users/adduser
        public IActionResult AddUser()
        {
            var area = ControllerContext.ActionDescriptor.RouteValues["area"];
            var actionName = ControllerContext.ActionDescriptor.ActionName;
            var controllerName = ControllerContext.ActionDescriptor.ControllerName;
            return Content($"area name:{area}" +
                $" controller:{controllerName}  action name: {actionName}");
        }        
    }
}
Attributet [Area] är det som anger en kontrollant som en del av ett område. Den här styrenheten finns i området Blog . Kontrollanter utan attribut [Area] är inte medlemmar i något område och matchar inte när area routningsvärdet tillhandahålls av routning. I följande exempel kan endast den första kontrollanten i listan matcha vägvärdena { area = Blog, controller = Users, action = AddUser }.
using Microsoft.AspNetCore.Mvc;
namespace MyApp.Namespace1
{
    [Area("Blog")]
    public class UsersController : Controller
    {
        // GET /manage/users/adduser
        public IActionResult AddUser()
        {
            var area = ControllerContext.ActionDescriptor.RouteValues["area"];
            var actionName = ControllerContext.ActionDescriptor.ActionName;
            var controllerName = ControllerContext.ActionDescriptor.ControllerName;
            return Content($"area name:{area}" +
                $" controller:{controllerName}  action name: {actionName}");
        }        
    }
}
using Microsoft.AspNetCore.Mvc;
namespace MyApp.Namespace2
{
    // Matches { area = Zebra, controller = Users, action = AddUser }
    [Area("Zebra")]
    public class UsersController : Controller
    {
        // GET /zebra/users/adduser
        public IActionResult AddUser()
        {
            var area = ControllerContext.ActionDescriptor.RouteValues["area"];
            var actionName = ControllerContext.ActionDescriptor.ActionName;
            var controllerName = ControllerContext.ActionDescriptor.ControllerName;
            return Content($"area name:{area}" +
                $" controller:{controllerName}  action name: {actionName}");
        }        
    }
}
using Microsoft.AspNetCore.Mvc;
namespace MyApp.Namespace3
{
    // Matches { area = string.Empty, controller = Users, action = AddUser }
    // Matches { area = null, controller = Users, action = AddUser }
    // Matches { controller = Users, action = AddUser }
    public class UsersController : Controller
    {
        // GET /users/adduser
        public IActionResult AddUser()
        {
            var area = ControllerContext.ActionDescriptor.RouteValues["area"];
            var actionName = ControllerContext.ActionDescriptor.ActionName;
            var controllerName = ControllerContext.ActionDescriptor.ControllerName;
            return Content($"area name:{area}" +
                $" controller:{controllerName}  action name: {actionName}");
        }
    }
}
Namnområdet för varje kontrollant visas här för fullständighet. Om de föregående kontrollanterna använde samma namnområde genereras ett kompilatorfel. Klassnamnområden har ingen effekt på MVC:s routning.
De två första kontrollanterna är medlemmar i områden och matchar bara när deras respektive områdesnamn anges av area vägvärdet. Den tredje styrenheten är inte medlem i något område och kan bara matcha när inget värde för area tillhandahålls av routning.
När det gäller att matcha inget värde är frånvaron av area värdet densamma som om värdet för area var null eller den tomma strängen.
När du kör en åtgärd i ett område är routningsvärdet för area tillgängligt som ett omgivande värde för routning som ska användas för URL-generering. Det innebär att som standard fungerar områden som är klibbiga för URL-generering, vilket visas i följande exempel.
app.UseEndpoints(endpoints =>
{
    endpoints.MapAreaControllerRoute(name: "duck_route", 
                                     areaName: "Duck",
                                     pattern: "Manage/{controller}/{action}/{id?}");
    endpoints.MapControllerRoute(name: "default",
                                 pattern: "Manage/{controller=Home}/{action=Index}/{id?}");
});
using Microsoft.AspNetCore.Mvc;
namespace MyApp.Namespace4
{
    [Area("Duck")]
    public class UsersController : Controller
    {
        // GET /Manage/users/GenerateURLInArea
        public IActionResult GenerateURLInArea()
        {
            // Uses the 'ambient' value of area.
            var url = Url.Action("Index", "Home");
            // Returns /Manage/Home/Index
            return Content(url);
        }
        // GET /Manage/users/GenerateURLOutsideOfArea
        public IActionResult GenerateURLOutsideOfArea()
        {
            // Uses the empty value for area.
            var url = Url.Action("Index", "Home", new { area = "" });
            // Returns /Manage
            return Content(url);
        }
    }
}
Följande kod genererar en URL till /Zebra/Users/AddUser:
public class HomeController : Controller
{
    public IActionResult About()
    {
        var url = Url.Action("AddUser", "Users", new { Area = "Zebra" });
        return Content($"URL: {url}");
    }
Åtgärdsdefinition
Offentliga metoder på en kontrollant, förutom de med attributet NonAction , är åtgärder.
Exempelkod
- MyDisplayRouteInfo tillhandahålls av Rick.Docs.Samples.RouteInfo NuGet-paketet och visar väginformation.
- Visa eller ladda ned exempelkod (hur du laddar ned)
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