Notitie
Voor toegang tot deze pagina is autorisatie vereist. U kunt proberen u aan te melden of de directory te wijzigen.
Voor toegang tot deze pagina is autorisatie vereist. U kunt proberen de mappen te wijzigen.
Door Ryan Nowak, Kirk Larkin en Rick Anderson
Note
Dit is niet de nieuwste versie van dit artikel. Zie de .NET 9-versie van dit artikelvoor de huidige release.
Warning
Deze versie van ASP.NET Core wordt niet meer ondersteund. Zie de .NET- en .NET Core-ondersteuningsbeleidvoor meer informatie. Zie de .NET 9-versie van dit artikelvoor de huidige release.
Important
Deze informatie heeft betrekking op een pre-releaseproduct dat aanzienlijk kan worden gewijzigd voordat het commercieel wordt uitgebracht. Microsoft geeft geen garanties, uitdrukkelijk of impliciet, met betrekking tot de informatie die hier wordt verstrekt.
Zie de .NET 9-versie van dit artikelvoor de huidige release.
ASP.NET Core-controllers gebruiken de middleware routering om de URL's van binnenkomende aanvragen te vinden en deze toe te wijzen aan acties. Route templates:
- Zijn gedefinieerd bij het opstarten in
Program.cs
of in kenmerken. - Beschrijven hoe URL-paden worden vergeleken met acties.
- Worden gebruikt voor het genereren van URL's voor koppelingen. De gegenereerde koppelingen worden meestal geretourneerd in antwoorden.
Acties worden conventioneel gerouteerd of door kenmerken gerouteerd. Een route die op de controller of actie wordt geplaatst, is kenmerk-gerouteerd. Zie Gemengde routering voor meer informatie.
This document:
- Hierin worden de interacties tussen MVC en routering uitgelegd:
- Hoe typische MVC-apps gebruikmaken van routeringsfuncties.
- Covers both:
- Conventionele routering die doorgaans wordt gebruikt met controllers en weergaven.
- Kenmerkroutering die wordt gebruikt met REST API's. Als u voornamelijk geïnteresseerd bent in routering voor REST API's, gaat u naar de sectie Kenmerkroutering voor REST API's .
- Zie Routering voor geavanceerde routeringsdetails.
- Verwijst naar het standaardrouteringssysteem met de naam eindpuntroutering. Het is mogelijk om controllers te gebruiken met de vorige versie van routering voor compatibiliteitsdoeleinden. Zie de migratiehandleiding 2.2-3.0 voor instructies.
Conventionele route instellen
De ASP.NET Core MVC-sjabloon genereert conventionele routeringscode die vergelijkbaar is met de volgende:
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 wordt gebruikt om één route te maken. De enkele route heeft de naam default
route. De meeste apps met controllers en weergaven gebruiken een routesjabloon die vergelijkbaar is met de default
route.
REST API's moeten kenmerkroutering gebruiken.
app.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
De routesjabloon "{controller=Home}/{action=Index}/{id?}"
:
Komt overeen met een URL-pad, zoals
/Products/Details/5
Extraheert de routewaarden
{ controller = Products, action = Details, id = 5 }
door het pad te tokeniseren. De extractie van routewaarden resulteert in een overeenkomst als de app een controller heeft met de naamProductsController
en eenDetails
actie:public class ProductsController : Controller { public IActionResult Details(int id) { return ControllerContext.MyDisplayRouteInfo(id); } }
MyDisplayRouteInfo wordt geleverd door het Rick.Docs.Samples.RouteInfo NuGet-pakket en toont routegegevens.
/Products/Details/5
model koppelt de waarde vanid = 5
aan deid
parameter om deze in te stellen op5
. Zie Modelbinding voor meer informatie.{controller=Home}
definieertHome
als de standaardwaardecontroller
.{action=Index}
definieertIndex
als de standaardwaardeaction
.Het
?
teken in{id?}
definieertid
als optioneel.- Standaard- en optionele routeparameters hoeven niet aanwezig te zijn in het URL-pad voor een overeenstemming. Zie De naslaginformatie over routesjablonen voor een gedetailleerde beschrijving van de syntaxis van de routesjabloon.
Komt overeen met het URL-pad
/
.Produceert de routewaarden
{ controller = Home, action = Index }
.
De waarden voor controller
en action
maken gebruik van de standaardwaarden.
id
produceert geen waarde omdat er geen corresponderend segment in het URL-pad is.
/
komt alleen overeen als er een HomeController
en Index
actie bestaat:
public class HomeController : Controller
{
public IActionResult Index() { ... }
}
Met behulp van de voorgaande controllerdefinitie en routesjabloon wordt de HomeController.Index
actie uitgevoerd voor de volgende URL-paden:
/Home/Index/17
/Home/Index
/Home
/
Het URL-pad /
maakt gebruik van de routesjabloon met standaardcontrollers Home
en de actie Index
. Het URL-pad /Home
maakt gebruik van de standaardactie Index
voor de routesjabloon.
De gemaksmethode MapDefaultControllerRoute:
app.MapDefaultControllerRoute();
Replaces:
app.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
Important
Routering wordt geconfigureerd met behulp van de UseRouting en UseEndpoints middleware. Controllers gebruiken:
- Bel MapControllers om attribuut-gerouteerde controllers toe te wijzen.
- Roep MapControllerRoute of MapAreaControllerRoute aan om zowel conventioneel gerouteerde controllers als door attributen gerouteerde controllers in kaart te brengen.
Apps hoeven meestal niet UseRouting
of UseEndpoints
aan te roepen.
WebApplicationBuilder configureert een middleware-pijplijn die middleware die is toegevoegd in Program.cs
omhult met UseRouting
en UseEndpoints
. Zie Routering in ASP.NET Corevoor meer informatie.
Conventional routing
Conventionele routering wordt gebruikt met controllers en weergaven. De default
route:
app.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
Het voorgaande is een voorbeeld van een conventionele route. Dit wordt conventionele routering genoemd omdat er een conventie voor URL-paden wordt vastgesteld:
- Het eerste padsegment,
{controller=Home}
wordt toegewezen aan de naam van de controller. - Het tweede segment,
{action=Index}
wordt toegewezen aan de naam van de actie. - Het derde segment
{id?}
wordt gebruikt voor een optioneelid
. De?
in{id?}
maakt het optioneel.id
wordt gebruikt om toe te wijzen aan een modelentiteit.
Met deze default
route wordt het URL-pad gebruikt:
-
/Products/List
wordt toegewezen aan deProductsController.List
actie. -
/Blog/Article/17
komt overeen metBlogController.Article
en meestal wordt deid
-parameter gekoppeld aan 17.
This mapping:
- Gebaseerd op alleen de controller en actienamen.
- Is niet gebaseerd op naamruimten, bronbestandslocaties of methodeparameters.
Met conventionele routering met de standaardroute kunt u de app maken zonder dat u voor elke actie een nieuw URL-patroon hoeft op te stellen. Voor een app met CRUD-stijlacties heeft u consistentie nodig voor de URL's over controllers heen:
- Helpt de code te vereenvoudigen.
- Maakt de gebruikersinterface voorspelbaarder.
Warning
De id
in de voorgaande code wordt gedefinieerd als optioneel door de routesjabloon. Acties kunnen worden uitgevoerd zonder de optionele id die is opgegeven als onderdeel van de URL. Over het algemeen, wanneer id
wordt weggelaten uit de URL:
-
id
wordt door middel van modelbinding ingesteld op0
. - Er is geen entiteit gevonden in de overeenkomende
id == 0
database.
Kenmerkroutering biedt fijnmazige controle om de ID verplicht te stellen voor sommige acties, maar niet voor andere. De documentatie bevat standaard optionele parameters, zoals id
wanneer ze waarschijnlijk in het juiste gebruik worden weergegeven.
De meeste apps moeten een eenvoudig en beschrijvend routeringsschema kiezen, zodat URL's leesbaar en zinvol zijn. De standaard conventionele route {controller=Home}/{action=Index}/{id?}
:
- Ondersteunt een eenvoudig en beschrijvend routeringsschema.
- Is een nuttig startpunt voor apps op basis van de gebruikersinterface.
- Is de enige routesjabloon die nodig is voor veel web-UI-apps. Voor grotere web-UI-apps is een andere route met het gebruik van Areas vaak alles wat nodig is.
MapControllerRoute en MapAreaRoute :
- Wijs automatisch een orderwaarde toe aan hun eindpunten op basis van de volgorde die ze worden aangeroepen.
Eindpuntroutering in ASP.NET Core:
- Heeft geen concept van routes.
- Biedt geen bestelgaranties voor de uitvoering van uitbreidbaarheid, alle eindpunten worden in één keer verwerkt.
Schakel logging in om te zien hoe de ingebouwde routeringimplementaties verzoeken afhandelen, zoals Route.
Kenmerkroutering wordt verderop in dit document uitgelegd.
Meerdere conventionele routes
Meerdere conventionele routes kunnen worden geconfigureerd door meer aanroepen toe te voegen aan MapControllerRoute en MapAreaControllerRoute. Hiermee kunt u meerdere conventies definiëren of conventionele routes toevoegen die zijn toegewezen aan een specifieke actie, zoals:
app.MapControllerRoute(name: "blog",
pattern: "blog/{*article}",
defaults: new { controller = "Blog", action = "Article" });
app.MapControllerRoute(name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
De blog
route in de voorgaande code is een toegewezen conventionele route. Dit wordt een speciale conventionele route genoemd omdat:
- Het maakt gebruik van conventionele routering.
- Het is gewijd aan een specifieke actie.
Omdat controller
en action
niet worden weergegeven in de routesjabloon "blog/{*article}"
als parameters:
- Ze kunnen alleen de standaardwaarden
{ controller = "Blog", action = "Article" }
hebben. - Deze route wordt altijd toegewezen aan de actie
BlogController.Article
.
/Blog
, /Blog/Article
en /Blog/{any-string}
zijn de enige URL-paden die overeenkomen met de blogroute.
Het voorgaande voorbeeld:
- De
blog
route heeft een hogere prioriteit bij het koppelen dan dedefault
route, omdat deze eerst wordt toegevoegd. - Is een voorbeeld van slug-stijlroutering , waarbij het gebruikelijk is om een artikelnaam te hebben als onderdeel van de URL.
Warning
De routering in ASP.NET Core werkt niet als volgt:
- Definieer een concept dat een route wordt genoemd.
UseRouting
voegt routekoppeling toe aan de middleware-pijplijn. DeUseRouting
middleware bekijkt de set eindpunten die in de app zijn gedefinieerd en selecteert de beste eindpuntovereenkomst op basis van de aanvraag. - Garanties bieden over de uitvoeringsvolgorde van uitbreidbaarheid, zoals IRouteConstraint of IActionConstraint.
Zie Routering voor referentiemateriaal over routering.
Conventionele routeringsvolgorde
Conventionele routering komt alleen overeen met een combinatie van actie en controller die door de app worden gedefinieerd. Dit is bedoeld om gevallen waarin conventionele routes elkaar overlappen te vereenvoudigen.
Routes toevoegen met behulp van MapControllerRoute, MapDefaultControllerRoute en MapAreaControllerRoute wijst automatisch een orderwaarde toe aan hun eindpunten op basis van de volgorde waarin ze worden aangeroepen. Overeenkomsten van een route die eerder wordt weergegeven, hebben een hogere prioriteit. Conventionele routering is orderafhankelijk. In het algemeen moeten routes met gebieden eerder worden geplaatst omdat ze specifieker zijn dan routes zonder een gebied.
Toegewezen conventionele routes met catch-all routeparameters, zoals {*article}
kunnen een route te greedy maken, wat betekent dat deze overeenkomt met URL's die u hebt bedoeld om te worden vergeleken met andere routes. Plaats de gretige routes later in de routetabel om gretige overeenkomsten te voorkomen.
Warning
Een catch-all--parameter kan verkeerde routes matchen door een fout in de routering. Apps die door deze fout worden beïnvloed, hebben de volgende kenmerken:
- Een algemene route, bijvoorbeeld
{**slug}"
- De catch-all-route kan niet overeenkomen met aanvragen die moeten overeenkomen.
- Als u andere routes verwijdert, begint de catch-all route te werken.
Zie GitHub-bugs 18677 en 16579 voor voorbeeldgevallen die deze bug ervaren.
Een opt-in-oplossing voor deze fout is opgenomen in .NET Core 3.1.301 of hoger SDK. Met de volgende code wordt een interne switch ingesteld waarmee deze fout wordt opgelost:
public static void Main(string[] args)
{
AppContext.SetSwitch("Microsoft.AspNetCore.Routing.UseCorrectCatchAllBehavior",
true);
CreateHostBuilder(args).Build().Run();
}
// Remaining code removed for brevity.
Ambigu acties oplossen
Wanneer twee eindpunten overeenkomen via routering, moet routering een van de volgende handelingen uitvoeren:
- Kies de beste kandidaat.
- Gooi een uitzondering.
For example:
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);
}
}
De voorgaande controller definieert twee acties die overeenkomen met:
- Het URL-pad
/Products33/Edit/17
- Routegegevens
{ controller = Products33, action = Edit, id = 17 }
.
Dit is een typisch patroon voor MVC-controllers:
-
Edit(int)
geeft een formulier weer om een product te bewerken. -
Edit(int, Product)
verwerkt het geplaatste formulier.
De juiste route oplossen:
-
Edit(int, Product)
is geselecteerd wanneer de aanvraag een HTTPPOST
is. -
Edit(int)
is geselecteerd wanneer het HTTP-werkwoord iets anders is.Edit(int)
wordt over het algemeen viaGET
.
De HttpPostAttribute, [HttpPost]
wordt verstrekt aan routering, zodat deze kan kiezen op basis van de HTTP-methode van de aanvraag. De HttpPostAttribute
maakt Edit(int, Product)
een betere match dan Edit(int)
.
Het is belangrijk om inzicht te hebben in de rol van kenmerken zoals HttpPostAttribute
. Vergelijkbare kenmerken worden gedefinieerd voor andere HTTP-woorden. Bij conventionele routering is het gebruikelijk dat acties dezelfde actienaam gebruiken wanneer ze deel uitmaken van een toonformulier of het indienen van een formulierworkflow. Zie bijvoorbeeld de twee bewerkingsactiemethoden onderzoeken.
Als routering geen beste kandidaat kan kiezen, wordt er een AmbiguousMatchException gegenereerd, waarin de meerdere overeenkomende eindpunten worden vermeld.
Conventionele routenamen
De tekenreeksen "blog"
en "default"
in de volgende voorbeelden zijn conventionele routenamen:
app.MapControllerRoute(name: "blog",
pattern: "blog/{*article}",
defaults: new { controller = "Blog", action = "Article" });
app.MapControllerRoute(name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
De routenamen geven de route een logische naam. De benoemde route kan worden gebruikt voor het genereren van URL's. Het gebruik van een benoemde route vereenvoudigt het maken van URL's wanneer de volgorde van routes ingewikkeld kan maken voor het genereren van URL's. Routenamen moeten uniek zijn voor de hele toepassing.
Route names:
- Geen invloed hebben op URL-matchen of verzoekafhandeling.
- Worden alleen gebruikt voor het genereren van URL's.
Het concept van de routenaam wordt weergegeven in routering als IEndpointNameMetadata. De termen routenaam en eindpuntnaam:
- Are interchangeable.
- Welke wordt gebruikt in documentatie en code, is afhankelijk van de API die wordt beschreven.
Kenmerkroutering voor REST API's
REST API's moeten kenmerkroutering gebruiken om de functionaliteit van de app te modelleren als een set resources waarin bewerkingen worden vertegenwoordigd door HTTP-woorden.
Kenmerkroutering maakt gebruik van een set kenmerken om acties rechtstreeks toe te wijzen aan routesjablonen. De volgende code is typisch voor een REST API en wordt gebruikt in het volgende voorbeeld:
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllers();
var app = builder.Build();
app.UseHttpsRedirection();
app.UseAuthorization();
app.MapControllers();
app.Run();
In de voorgaande code wordt MapControllers aangeroepen om kenmerkgerouteerde controllers toe te wijzen.
In het volgende voorbeeld:
-
HomeController
komt overeen met een set URL's die vergelijkbaar zijn met de standaardconventionele route{controller=Home}/{action=Index}/{id?}
.
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);
}
}
De HomeController.Index
actie wordt uitgevoerd voor een van de URL-paden/
, /Home
of /Home/Index
/Home/Index/3
.
In dit voorbeeld wordt een belangrijk programmeerverschil tussen kenmerkroutering en conventionele routering gemarkeerd. Voor kenmerkroutering is meer invoer vereist om een route op te geven. De conventionele standaardroute verwerkt routes beknopter. Met kenmerkroutering kunt u echter nauwkeurig bepalen welke routesjablonen van toepassing zijn op elke actie.
Bij kenmerkroutering spelen de controller- en actienamen geen rol waarin actie wordt vergeleken, tenzij tokenvervanging wordt gebruikt. Het volgende voorbeeld komt overeen met dezelfde URL's als in het vorige voorbeeld:
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);
}
}
De volgende code maakt gebruik van tokenvervanging voor action
en 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();
}
}
De volgende code is van toepassing op [Route("[controller]/[action]")]
de controller:
[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();
}
}
In de voorgaande code moeten de Index
methodesjablonen voorafgegaan worden door /
of ~/
bij de routesjablonen. Routesjablonen die worden toegepast op een actie die begint met /
of ~/
niet worden gecombineerd met routesjablonen die zijn toegepast op de controller.
Zie de prioriteit van routesjablonen voor informatie over de selectie van routesjablonen.
Gereserveerde routeringsnamen
De volgende trefwoorden zijn gereserveerde routeparameternamen bij het gebruik van Controllers of Razor Pages:
action
area
controller
handler
page
Het gebruik page
als routeparameter met kenmerkroutering is een veelvoorkomende fout. Dit leidt tot inconsistent en verwarrend gedrag met het genereren van URL's.
public class MyDemo2Controller : Controller
{
[Route("/articles/{page}")]
public IActionResult ListArticles(int page)
{
return ControllerContext.MyDisplayRouteInfo(page);
}
}
De speciale parameternamen worden door de URL-generatie gebruikt om te bepalen of een URL-generatiebewerking verwijst naar een Razor pagina of naar een controller.
De volgende trefwoorden zijn gereserveerd in de context van een Razor weergave of een Razor pagina:
page
using
namespace
inject
section
inherits
model
addTagHelper
removeTagHelper
Deze trefwoorden mogen niet worden gebruikt voor koppelingsgeneraties, modelgebonden parameters of eigenschappen op het hoogste niveau.
HTTP-werkwoordsjablonen
ASP.NET Core heeft de volgende HTTP-werkwoordsjablonen:
Route templates
ASP.NET Core heeft de volgende routesjablonen:
- Alle HTTP-werkwoordsjablonen zijn routesjablonen.
- [Route]
Kenmerkroutering met Http-werkwoordkenmerken
Houd rekening met de volgende controller:
[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);
}
}
In de voorgaande code:
- Elke actie bevat het
[HttpGet]
kenmerk, dat alleen overeenkomt met HTTP GET-aanvragen. - De
GetProduct
actie bevat de"{id}"
sjabloon en wordt daaromid
toegevoegd aan de"api/[controller]"
sjabloon op de controller. De sjabloon voor methoden is"api/[controller]/{id}"
. Daarom komt deze actie alleen overeen met GET-aanvragen voor het formulier/api/test2/xyz
/api/test2/123
,/api/test2/{any string}
enzovoort.[HttpGet("{id}")] // GET /api/test2/xyz public IActionResult GetProduct(string id) { return ControllerContext.MyDisplayRouteInfo(id); }
- De
GetIntProduct
actie bevat de"int/{id:int}"
sjabloon. Het:int
gedeelte van de sjabloon beperkt deid
routewaarden tot tekenreeksen die kunnen worden geconverteerd naar een geheel getal. Een GET-aanvraag voor/api/test2/int/abc
:- Komt niet overeen met deze actie.
- Retourneert een fout 404 Niet Gevonden.
[HttpGet("int/{id:int}")] // GET /api/test2/int/3 public IActionResult GetIntProduct(int id) { return ControllerContext.MyDisplayRouteInfo(id); }
- De
GetInt2Product
actie bevat{id}
in de sjabloon, maar legt geen beperkingen op aanid
tot waarden die kunnen worden geconverteerd naar een geheel getal. Een GET-aanvraag voor/api/test2/int2/abc
:- Komt overeen met deze route.
- Modelbinding kan
abc
niet omzetten naar een geheel getal. Deid
parameter van de methode is geheel getal. - Retourneert een 400 Bad Request omdat het niet gelukt is om
abc
naar een geheel getal te converteren.[HttpGet("int2/{id}")] // GET /api/test2/int2/3 public IActionResult GetInt2Product(int id) { return ControllerContext.MyDisplayRouteInfo(id); }
Kenmerkroutering kan gebruikmaken van HttpMethodAttribute kenmerken zoals HttpPostAttribute, HttpPutAttributeen HttpDeleteAttribute. Alle HTTP-werkwoordkenmerken accepteren een routesjabloon. In het volgende voorbeeld ziet u twee acties die overeenkomen met dezelfde routesjabloon:
[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);
}
}
Het URL-pad gebruiken /products3
:
- De
MyProductsController.ListProducts
-actie wordt uitgevoerd wanneer het HTTP-werkwoordGET
is. - De
MyProductsController.CreateProduct
-actie wordt uitgevoerd wanneer het HTTP-werkwoordPOST
is.
Bij het bouwen van een REST API is het zeldzaam dat u moet gebruiken [Route(...)]
voor een actiemethode, omdat de actie alle HTTP-methoden accepteert. Het is beter om het specifiekere HTTP-werkwoordkenmerk te gebruiken om precies te zijn wat uw API ondersteunt. Clients van REST API's zullen naar verwachting weten welke paden en HTTP-werkwoorden zijn toegewezen aan specifieke logische bewerkingen.
REST API's moeten kenmerkroutering gebruiken om de functionaliteit van de app te modelleren als een set resources waarin bewerkingen worden vertegenwoordigd door HTTP-woorden. Dit betekent dat veel bewerkingen, bijvoorbeeld GET en POST op dezelfde logische resource, dezelfde URL gebruiken. Kenmerkroutering biedt een beheerniveau dat nodig is om de indeling van een openbaar eindpunt van een API zorgvuldig te ontwerpen.
Omdat een kenmerkroute van toepassing is op een specifieke actie, is het eenvoudig om parameters vereist te maken als onderdeel van de definitie van de routesjabloon. In het volgende voorbeeld id
is dit vereist als onderdeel van het URL-pad:
[ApiController]
public class Products2ApiController : ControllerBase
{
[HttpGet("/products2/{id}", Name = "Products_List")]
public IActionResult GetProduct(int id)
{
return ControllerContext.MyDisplayRouteInfo(id);
}
}
De Products2ApiController.GetProduct(int)
actie:
- Wordt uitgevoerd met een url-pad zoals
/products2/3
- Wordt niet uitgevoerd met het URL-pad
/products2
.
Met het kenmerk [Verbruiken] kan een actie de ondersteunde inhoudstypen voor aanvragen beperken. Zie Ondersteunde aanvraaginhoudstypen definiëren met het kenmerk Verbruiken voor meer informatie.
Zie Routering voor een volledige beschrijving van routesjablonen en gerelateerde opties.
Zie [ApiController]
voor meer informatie.
Route name
De volgende code definieert een routenaam van Products_List
:
[ApiController]
public class Products2ApiController : ControllerBase
{
[HttpGet("/products2/{id}", Name = "Products_List")]
public IActionResult GetProduct(int id)
{
return ControllerContext.MyDisplayRouteInfo(id);
}
}
Routenamen kunnen worden gebruikt om een URL te genereren op basis van een specifieke route. Route names:
- Dit heeft geen invloed op het URL-overeenkomende gedrag van routering.
- Worden alleen gebruikt voor het genereren van URL's.
Routenamen moeten uniek zijn voor de hele toepassing.
Vergelijk de voorgaande code met de conventionele standaardroute, die de id
parameter definieert als optioneel ({id?}
). De mogelijkheid om API's nauwkeurig op te geven heeft voordelen, zoals het toestaan dat /products
en /products/5
worden uitgevoerd door verschillende acties.
Het combineren van kenmerkroutes
Om kenmerkroutering minder herhalend te maken, worden routekenmerken op de controller gecombineerd met routekenmerken voor de afzonderlijke acties. Routesjablonen die op de controller zijn gedefinieerd, worden toegevoegd aan de routesjablonen van de acties. Als u een routekenmerk op de controller plaatst, worden alle acties in de controller gebruikt om kenmerkroutering te gebruiken.
[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);
}
}
In het voorgaande voorbeeld:
- Het URL-pad
/products
kan overeenkomen metProductsApi.ListProducts
- Het URL-pad
/products/5
kan overeenkomen metProductsApi.GetProduct(int)
.
Beide acties komen alleen overeen met HTTP GET
omdat ze zijn gemarkeerd met het [HttpGet]
kenmerk.
Routesjablonen die worden toegepast op een actie die begint met /
of ~/
niet worden gecombineerd met routesjablonen die zijn toegepast op de controller. Het volgende voorbeeld komt overeen met een set URL-paden die vergelijkbaar zijn met de standaardroute.
[Route("Home")]
public class HomeController : Controller
{
[Route("")]
[Route("Index")]
[Route("/")]
public IActionResult Index()
{
return ControllerContext.MyDisplayRouteInfo();
}
[Route("About")]
public IActionResult About()
{
return ControllerContext.MyDisplayRouteInfo();
}
}
In de volgende tabel worden de [Route]
kenmerken in de voorgaande code uitgelegd:
Attribute | Combineert met [Route("Home")] |
Definieert routesjabloon |
---|---|---|
[Route("")] |
Yes | "Home" |
[Route("Index")] |
Yes | "Home/Index" |
[Route("/")] |
No | "" |
[Route("About")] |
Yes | "Home/About" |
Routevolgorde kenmerk
Routering bouwt een structuur en komt overeen met alle eindpunten tegelijk:
- De routevermeldingen gedragen zich alsof ze in een ideale volgorde worden geplaatst.
- De meest specifieke routes hebben de kans om uit te voeren vóór de meer algemene routes.
Een kenmerkroute zoals blog/search/{topic}
is bijvoorbeeld specifieker dan een kenmerkroute zoals blog/{*article}
. De blog/search/{topic}
route heeft standaard een hogere prioriteit, omdat deze specifieker is. Met conventionele routering is de ontwikkelaar verantwoordelijk voor het plaatsen van routes in de gewenste volgorde.
Kenmerkroutes kunnen een order configureren met behulp van de Order eigenschap. Alle door het framework geleverde routekenmerken omvatten Order
. Routes worden verwerkt op basis van een oplopend type eigenschap Order
. De standaardvolgorde is 0
. Een route instellen met behulp van Order = -1
uitvoeringen voor routes die geen order instellen. Een route instellen met behulp van Order = 1
vindt plaats na de standaard routevolgorde.
Vermijd afhankelijk Order
van . Als de URL-ruimte van een app expliciete volgordewaarden vereist om correct te routeren, is het waarschijnlijk ook verwarrend voor clients. Over het algemeen selecteert kenmerkroutering de juiste route met URL-overeenkomsten. Als de standaardvolgorde die wordt gebruikt voor het genereren van URL's niet werkt, is het gebruik van een routenaam als onderdrukking meestal eenvoudiger dan het toepassen van de Order
eigenschap.
Houd rekening met de volgende twee controllers die beide de routekoppeling /home
definiëren:
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);
}
}
Als u aanvraagt /home
met de voorgaande code, wordt er een uitzondering gegenereerd die vergelijkbaar is met de volgende:
AmbiguousMatchException: The request matched multiple endpoints. Matches:
WebMvcRouting.Controllers.HomeController.Index
WebMvcRouting.Controllers.MyDemoController.MyIndex
Als u een van de routekenmerken toevoegt Order
, wordt de dubbelzinnigheid opgelost:
[Route("")]
[Route("Home", Order = 2)]
[Route("Home/MyIndex")]
public IActionResult MyIndex()
{
return ControllerContext.MyDisplayRouteInfo();
}
Met de voorgaande code /home
wordt het HomeController.Index
eindpunt uitgevoerd. Om naar de MyDemoController.MyIndex
, aanvraag /home/MyIndex
te gaan .
Note:
- De voorgaande code is een voorbeeld of een slecht routeringsontwerp. Deze is gebruikt om de
Order
eigenschap te illustreren. - De
Order
eigenschap lost alleen de dubbelzinnigheid op, die sjabloon kan niet worden vergeleken. Het is beter om de[Route("Home")]
sjabloon te verwijderen.
Zie Razor route- en app-conventies voor pagina's: Routevolgorde voor informatie over routevolgordes met Razor Pagina's.
In sommige gevallen wordt een HTTP 500-fout geretourneerd met ambigu routes. Gebruik loggen om te zien welke eindpunten de AmbiguousMatchException
veroorzaken.
Tokenvervanging in routesjablonen [controller], [actie], [gebied]
Voor het gemak ondersteunen kenmerkroutes tokenvervanging door een token tussen vierkante haken ([
, ]
) te sluiten. De tokens [action]
, [area]
en [controller]
worden vervangen door de waarden van de actienaam, gebiedsnaam en controllernaam uit de actie waarin de route is gedefinieerd:
[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);
}
}
In de voorgaande code:
[HttpGet]
public IActionResult List()
{
return ControllerContext.MyDisplayRouteInfo();
}
- Wedstrijden
/Products0/List
[HttpGet("{id}")]
public IActionResult Edit(int id)
{
return ControllerContext.MyDisplayRouteInfo(id);
}
- Wedstrijden
/Products0/Edit/{id}
Tokenvervanging vindt plaats als de laatste stap van het bouwen van de attribuutroutes. Het voorgaande voorbeeld gedraagt zich hetzelfde als de volgende code:
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);
}
}
Als u dit leest in een andere taal dan Engels, laat het ons dan weten in dit GitHub-discussieprobleem als u de codeopmerkingen in uw eigen taal wilt zien.
Attribuutsroutes kunnen ook worden gecombineerd met overerving. De kracht hiervan komt goed tot uiting wanneer het wordt gecombineerd met tokenvervanging. Tokenvervanging is ook van toepassing op routenamen die zijn gedefinieerd door kenmerkroutes.
[Route("[controller]/[action]", Name="[controller]_[action]")]
genereert een unieke routenaam voor elke actie:
[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);
}
}
Als u het letterlijke scheidingsteken voor tokenvervanging [
wilt vergelijken of ]
, escapet u het door het teken ([[
of ]]
) te herhalen.
Een parametertransformatie gebruiken om tokenvervanging aan te passen
Tokenvervanging kan worden aangepast met behulp van een parametertransformator. Een parametertransformator implementeert IOutboundParameterTransformer en transformeert de waarde van parameters. Een aangepaste SlugifyParameterTransformer
parametertransformator wijzigt bijvoorbeeld de SubscriptionManagement
routewaarde in 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();
}
}
Dit RouteTokenTransformerConvention is een toepassingsmodelconventie die:
- Hiermee past u een parametertransformatie toe op alle kenmerkroutes in een toepassing.
- Hiermee worden de waarden van het kenmerkroutetoken aangepast wanneer ze worden vervangen.
public class SubscriptionManagementController : Controller
{
[HttpGet("[controller]/[action]")]
public IActionResult ListAll()
{
return ControllerContext.MyDisplayRouteInfo();
}
}
De voorgaande ListAll
methode komt overeen /subscription-management/list-all
.
De RouteTokenTransformerConvention
optie is geregistreerd als een optie:
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();
Zie MDN-webdocumenten op Slug voor de definitie van Slug.
Warning
Wanneer u System.Text.RegularExpressions gebruikt om niet-vertrouwde invoer te verwerken, geeft u een time-out door. Een kwaadwillende gebruiker kan invoer opgeven om een RegularExpressions
te veroorzaken. ASP.NET Core framework-API's die gebruikmaken van RegularExpressions
geven een time-out door.
Meerdere kenmerkroutes
Kenmerkroutering ondersteunt het definiëren van meerdere routes die dezelfde actie bereiken. Het meest voorkomende gebruik hiervan is om het gedrag van de standaard conventionele route na te bootsen, zoals wordt weergegeven in het volgende voorbeeld:
[Route("[controller]")]
public class Products13Controller : Controller
{
[Route("")] // Matches 'Products13'
[Route("Index")] // Matches 'Products13/Index'
public IActionResult Index()
{
return ControllerContext.MyDisplayRouteInfo();
}
Als u meerdere routekenmerken op de controller plaatst, betekent dit dat elke eigenschap wordt gecombineerd met elk van de routekenmerken op de actiemethoden:
[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();
}
}
Alle http-bewerkingsroutebeperkingen worden geïmplementeerd IActionConstraint
.
Wanneer meerdere routekenmerken die worden geïmplementeerd IActionConstraint op een actie worden geplaatst:
- Elke actiebeperking combineert met de routesjabloon die is toegepast op de controller.
[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();
}
}
Het gebruik van meerdere routes voor acties kan nuttig en krachtig lijken, het is beter om de URL-ruimte van uw app eenvoudig en goed gedefinieerd te houden. Gebruik meerdere routes voor acties alleen wanneer dat nodig is, bijvoorbeeld om bestaande clients te ondersteunen.
Optionele parameters, standaardwaarden en beperkingen voor kenmerkroute opgeven
Kenmerkroutes ondersteunen dezelfde inlinesyntaxis als conventionele routes om optionele parameters, standaardwaarden en beperkingen op te geven.
public class Products14Controller : Controller
{
[HttpPost("product14/{id:int}")]
public IActionResult ShowProduct(int id)
{
return ControllerContext.MyDisplayRouteInfo(id);
}
}
In de voorgaande code [HttpPost("product14/{id:int}")]
past u een routebeperking toe. De Products14Controller.ShowProduct
-actie komt alleen overeen met URL-paden zoals /product14/3
. Het gedeelte {id:int}
van de routesjabloon beperkt dat segment tot alleen gehele getallen.
Zie De naslaginformatie over routesjablonen voor een gedetailleerde beschrijving van de syntaxis van de routesjabloon.
Aangepaste routekenmerken met IRouteTemplateProvider
Alle routekenmerken worden geïmplementeerd IRouteTemplateProvider. De ASP.NET Core-runtime:
- Zoekt naar kenmerken in controllerklassen en actiemethoden wanneer de app wordt gestart.
- Maakt gebruik van de kenmerken die worden geïmplementeerd
IRouteTemplateProvider
om de eerste set routes te bouwen.
Implementeren IRouteTemplateProvider
om aangepaste routekenmerken te definiëren. Met elke IRouteTemplateProvider
route kunt u één route definiëren met een aangepaste routesjabloon, volgorde en naam:
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();
}
}
De voorgaande Get
methode retourneert Order = 2, Template = api/MyTestApi
.
Toepassingsmodel gebruiken om kenmerkroutes aan te passen
Het toepassingsmodel:
- Is een objectmodel dat is gemaakt bij het opstarten in
Program.cs
. - Bevat alle metagegevens die door ASP.NET Core worden gebruikt om de acties in een app te routeren en uit te voeren.
Het toepassingsmodel bevat alle gegevens die zijn verzameld uit routekenmerken. De gegevens van routekenmerken worden geleverd door de IRouteTemplateProvider
implementatie. Conventions:
- Kan worden geschreven om het toepassingsmodel te wijzigen om aan te passen hoe routering zich gedraagt.
- Worden gelezen bij het opstarten van de app.
In deze sectie ziet u een eenvoudig voorbeeld van het aanpassen van routering met behulp van een toepassingsmodel. Met de volgende code worden routes grofweg afgestemd op de mapstructuur van het project.
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()
};
}
}
}
Met de volgende code voorkomt u dat de namespace
conventie wordt toegepast op controllers die door een kenmerk worden gerouteerd:
public void Apply(ControllerModel controller)
{
var hasRouteAttributes = controller.Selectors.Any(selector =>
selector.AttributeRouteModel != null);
if (hasRouteAttributes)
{
return;
}
De volgende controller gebruikt NamespaceRoutingConvention
bijvoorbeeld niet:
[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}");
}
}
De methode NamespaceRoutingConvention.Apply
:
- Doet niets als de controller wordt gerouteerd.
- Hiermee stelt u de sjabloon controllers in op basis van de
namespace
sjabloon , waarbij de basisnamespace
is verwijderd.
De NamespaceRoutingConvention
kan worden toegepast in 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();
Denk bijvoorbeeld aan de volgende controller:
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}");
}
}
}
In de voorgaande code:
- De basis
namespace
isMy.Application
. - De volledige naam van de voorgaande controller is
My.Application.Admin.Controllers.UsersController
. - Hiermee
NamespaceRoutingConvention
stelt u de controllersjabloon in opAdmin/Controllers/Users/[action]/{id?
.
De NamespaceRoutingConvention
kan ook worden toegepast als een kenmerk op een controller:
[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}");
}
}
Gemengde routering: Kenmerkroutering versus conventionele routering
ASP.NET Core-apps kunnen het gebruik van conventionele routering en kenmerkroutering combineren. Het is gebruikelijk om conventionele routes te gebruiken voor controllers die HTML-pagina's voor browsers bedienen en kenmerkroutering voor controllers die API's bedienen REST .
Acties worden of conventioneel gerouteerd of via attributen gerouteerd. Wanneer je een route op de controller of de actie plaatst, wordt deze met attributen gerouteerd. Acties die kenmerkroutes definiëren, kunnen niet worden bereikt via de conventionele routes en omgekeerd. Elk route-attribuut op de controller zorgt ervoor dat alle acties in de controller worden gerouteerd.
Kenmerkroutering en conventionele routering gebruiken dezelfde routeringsengine.
Routeren met speciale tekens
Routering met speciale tekens kan leiden tot onverwachte resultaten. Denk bijvoorbeeld aan een controller met de volgende actiemethode:
[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;
}
Wanneer string id
deze de volgende gecodeerde waarden bevat, kunnen onverwachte resultaten optreden:
ASCII | Encoded |
---|---|
/ |
%2F |
|
+ |
Routeparameters worden niet altijd gedecodeerd. Dit probleem kan in de toekomst worden opgelost. Zie dit GitHub-probleem voor meer informatie;
URL-generatie en omgevingswaarden
Apps kunnen functies voor het genereren van routerings-URL's gebruiken om URL-koppelingen naar acties te genereren. Het genereren van URL's elimineert hardcoderings-URL's , waardoor code robuuster en onderhoudbaarer wordt. Deze sectie is gericht op de functies voor het genereren van URL's die door MVC worden geboden en beslaan alleen de basisbeginselen van het genereren van URL's. Zie Routering voor een gedetailleerde beschrijving van het genereren van URL's.
De IUrlHelper interface is het onderliggende element van de infrastructuur tussen MVC en routering voor het genereren van URL's. Een exemplaar van IUrlHelper
is beschikbaar via de Url
eigenschap in controllers, weergaven en weergaveonderdelen.
In het volgende voorbeeld wordt de IUrlHelper
interface gebruikt via de Controller.Url
eigenschap om een URL naar een andere actie te genereren.
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();
}
}
Als de app gebruikmaakt van de standaard conventionele route, is de waarde van de url
variabele de URL-padtekenreeks /UrlGeneration/Destination
. Dit URL-pad wordt gemaakt door routering door het volgende te combineren:
- De routewaarden van de huidige aanvraag, die omgevingswaarden worden genoemd.
- De waarden die worden doorgegeven aan
Url.Action
en die waarden invoegen in de routesjabloon:
ambient values: { controller = "UrlGeneration", action = "Source" }
values passed to Url.Action: { controller = "UrlGeneration", action = "Destination" }
route template: {controller}/{action}/{id?}
result: /UrlGeneration/Destination
Elke routeparameter in de routesjabloon wordt vervangen door namen die overeenkomen met de waarden en omgevingswaarden. Een routeparameter die geen waarde heeft, kan:
- Gebruik een standaardwaarde als deze een waarde heeft.
- Overgeslagen als dit optioneel is. Bijvoorbeeld de
id
van de routesjabloon{controller}/{action}/{id?}
.
Het genereren van url's mislukt als een vereiste routeparameter geen bijbehorende waarde heeft. Als het genereren van url's voor een route mislukt, wordt de volgende route geprobeerd totdat alle routes zijn geprobeerd of een overeenkomst wordt gevonden.
In het voorgaande voorbeeld wordt uitgegaan van Url.Action
conventionele routering. Het genereren van URL's werkt op dezelfde manier met kenmerkroutering, hoewel de concepten verschillen. Bij gebruik van conventionele routering:
- De routewaarden worden gebruikt om een sjabloon uit te vouwen.
- De routewaarden voor
controller
enaction
worden meestal weergegeven in die sjabloon. Dit werkt omdat de URL's die overeenkomen met routering voldoen aan een conventie.
In het volgende voorbeeld wordt kenmerkroutering gebruikt:
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();
}
}
De Source
actie in de voorgaande code genereert custom/url/to/destination
.
LinkGenerator is toegevoegd in ASP.NET Core 3.0 als alternatief voor IUrlHelper
.
LinkGenerator
biedt vergelijkbare maar flexibelere functionaliteit. Elke methode op IUrlHelper
heeft ook een bijbehorende reeks methoden LinkGenerator
.
URL's genereren op actienaam
Url.Action, LinkGenerator.GetPathByAction en alle gerelateerde overbelastingen zijn ontworpen om het doeleindpunt te genereren door een controllernaam en actienaam op te geven.
Wanneer u Url.Action
gebruikt, worden de huidige routewaarden voor controller
en action
geleverd door de runtime:
- De waarde van
controller
enaction
maken deel uit van zowel omgevingswaarden als waarden. De methodeUrl.Action
gebruikt altijd de huidige waarden vanaction
encontroller
genereert een URL-pad dat naar de huidige actie routeert.
Routering probeert de waarden in omgevingswaarden te gebruiken om informatie in te vullen die niet is opgegeven bij het genereren van een URL. Overweeg een route zoals {a}/{b}/{c}/{d}
met omgevingswaarden { a = Alice, b = Bob, c = Carol, d = David }
:
- Routering bevat voldoende informatie om een URL te genereren zonder extra waarden.
- Routering heeft voldoende informatie omdat alle routeparameters een waarde hebben.
Als de waarde { d = Donovan }
wordt toegevoegd:
- De waarde
{ d = David }
wordt genegeerd. - Het gegenereerde URL-pad is
Alice/Bob/Carol/Donovan
.
Waarschuwing: URL-paden zijn hiërarchisch. Als in het voorgaande voorbeeld de waarde { c = Cheryl }
wordt toegevoegd:
- Beide waarden
{ c = Carol, d = David }
worden genegeerd. - Er is geen waarde meer voor
d
en het genereren van URL's mislukt. - De gewenste waarden van
c
end
moeten worden opgegeven om een URL te genereren.
U kunt verwachten dat dit probleem zich voordoet met de standaardroute {controller}/{action}/{id?}
. Dit probleem komt zelden voor in de praktijk omdat Url.Action
altijd expliciet een controller
- en action
-waarde specificeert.
Verschillende overbelastingen van URL.Action voeren een routewaardenobject uit om waarden op te geven voor andere routeparameters dan controller
en action
. Het object voor routewaarden wordt vaak gebruikt met id
. Bijvoorbeeld: Url.Action("Buy", "Products", new { id = 17 })
. Het routewaardenobject:
- Volgens conventie is een object meestal van anoniem type.
- Kan een
IDictionary<>
of een POCO zijn).
Eventuele extra routewaarden die niet overeenkomen met routeparameters, worden in de querytekenreeks geplaatst.
public IActionResult Index()
{
var url = Url.Action("Buy", "Products", new { id = 17, color = "red" });
return Content(url!);
}
De voorgaande code genereert /Products/Buy/17?color=red
.
Met de volgende code wordt een absolute URL gegenereerd:
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!);
}
Gebruik een van de volgende manieren om een absolute URL te maken:
- Een overload-functie die een
protocol
accepteert. Bijvoorbeeld de voorgaande code. - LinkGenerator.GetUriByAction, waarmee standaard absolute URI's worden gegenereerd.
URLs per route genereren
In de voorgaande code is het genereren van een URL gedemonstreerd door de controller en de actienaam door te geven.
IUrlHelper
biedt ook de url.RouteUrl-reeks methoden. Deze methoden zijn vergelijkbaar met Url.Action, maar ze kopiëren niet de huidige waarden van action
en controller
naar de routewaarden. Het meest voorkomende gebruik van Url.RouteUrl
:
- Hiermee geeft u een routenaam op voor het genereren van de URL.
- Over het algemeen specificeer je geen controller- of actienaam.
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();
}
In het volgende Razor bestand wordt een HTML-koppeling naar het Destination_Route
volgende bestand gegenereerd:
<h1>Test Links</h1>
<ul>
<li><a href="@Url.RouteUrl("Destination_Route")">Test Destination_Route</a></li>
</ul>
URLs genereren in HTML en Razor
IHtmlHelperbiedt de HtmlHelper methoden Html.BeginForm en Html.ActionLink om respectievelijk elementen te genereren<form>
.<a>
Deze methoden gebruiken de methode Url.Action om een URL te genereren en ze accepteren vergelijkbare argumenten. De metgezellen voor Url.RouteUrl
zijn HtmlHelper
en Html.BeginRouteForm
, die vergelijkbare functionaliteit hebben.
TagHelpers genereren URL's met behulp van de TagHelper form
en de TagHelper <a>
. Beide gebruiken IUrlHelper
voor hun implementatie. Zie Tag Helpers in formulieren voor meer informatie.
In weergaven is de IUrlHelper
functie beschikbaar via de Url
eigenschap voor elke ad-hoc-URL-generatie die niet wordt gedekt door het bovenstaande.
URL-generatie in actieresultaten
In de voorgaande voorbeelden is het gebruik IUrlHelper
in een controller getoond. Het meest voorkomende gebruik in een controller is het genereren van een URL als onderdeel van een actieresultaat.
De ControllerBase en Controller basisklassen bieden handige methoden voor actieresultaten die verwijzen naar een andere actie. Een typisch gebruik is om om te leiden na het accepteren van gebruikersinvoer:
[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);
}
De actie resulteert in factory-methoden zoals RedirectToAction en CreatedAtAction volgen een vergelijkbaar patroon als de methoden op IUrlHelper
.
Speciaal geval voor speciale conventionele routes
Conventionele routering kan een speciaal soort routedefinitie gebruiken, een speciale conventionele route genoemd. In het volgende voorbeeld is de benoemde blog
route een toegewezen conventionele route:
app.MapControllerRoute(name: "blog",
pattern: "blog/{*article}",
defaults: new { controller = "Blog", action = "Article" });
app.MapControllerRoute(name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
Met behulp van de voorgaande routedefinities Url.Action("Index", "Home")
genereert u het URL-pad /
met behulp van de default
route, maar waarom? U kunt raden dat de routewaarden { controller = Home, action = Index }
voldoende zijn om een URL te genereren met behulp van blog
, en het resultaat zou zijn /blog?action=Index&controller=Home
.
Toegewezen conventionele routes zijn afhankelijk van een speciaal gedrag van standaardwaarden die geen bijbehorende routeparameter hebben die voorkomt dat de route te greedy is met het genereren van URL's. In dit geval zijn de standaardwaarden en { controller = Blog, action = Article }
worden ze controller
niet action
weergegeven als routeparameter. Wanneer routering URL-generatie uitvoert, moeten de opgegeven waarden overeenkomen met de standaardwaarden. Het genereren van URL's met behulp van blog
mislukt omdat de waarden { controller = Home, action = Index }
niet overeenkomen { controller = Blog, action = Article }
. Routering valt vervolgens terug om te proberen default
, wat slaagt.
Areas
Gebieden zijn een MVC-functie die wordt gebruikt voor het organiseren van gerelateerde functionaliteit in een groep als afzonderlijke:
- Routeringsnaamruimte voor controlleracties.
- Mapstructuur voor weergaven.
Als u gebieden gebruikt, kan een app meerdere controllers met dezelfde naam hebben, zolang ze verschillende gebieden hebben. Met behulp van gebieden wordt een hiërarchie gemaakt voor routering door een andere routeparameter area
toe te voegen aan controller
en action
. In deze sectie wordt beschreven hoe routering communiceert met gebieden. Zie Gebieden voor meer informatie over hoe gebieden in combinatie met weergaven worden gebruikt.
In het volgende voorbeeld wordt MVC geconfigureerd voor het gebruik van de standaard conventionele route en een area
route voor een area
met de naam 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();
In de voorgaande code MapAreaControllerRoute wordt aangeroepen om de "blog_route"
. De tweede parameter, "Blog"
is de gebiedsnaam.
Wanneer het overeenkomt met een URL-pad zoals /Manage/Users/AddUser
, genereert de "blog_route"
route de routewaarden { area = Blog, controller = Users, action = AddUser }
. De area
routewaarde wordt geproduceerd door een standaardwaarde voor area
. De route die is gemaakt door MapAreaControllerRoute
, is gelijk aan het volgende:
app.MapControllerRoute("blog_route", "Manage/{controller}/{action}/{id?}",
defaults: new { area = "Blog" }, constraints: new { area = "Blog" });
app.MapControllerRoute("default_route", "{controller}/{action}/{id?}");
MapAreaControllerRoute
maakt een route met zowel een standaardwaarde als een beperking voor area
het gebruik van de opgegeven gebiedsnaam, in dit geval Blog
. De standaardwaarde zorgt ervoor dat de route altijd produceert { area = Blog, ... }
. De beperking vereist de waarde { area = Blog, ... }
voor het genereren van URL's.
Conventionele routering is orderafhankelijk. In het algemeen moeten routes met gebieden eerder worden geplaatst omdat ze specifieker zijn dan routes zonder een gebied.
In het voorgaande voorbeeld komen de routewaarden { area = Blog, controller = Users, action = AddUser }
overeen met de volgende actie:
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}");
}
}
}
Het kenmerk [Gebied] geeft een controller aan als onderdeel van een gebied. Deze controller bevindt zich in het Blog
gebied. Controllers zonder kenmerk [Area]
zijn geen lid van een gebied en komen niet overeen wanneer de area
routewaarde wordt geleverd door routering. In het volgende voorbeeld kan alleen de eerste vermelde controller overeenkomen met de routewaarden { 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}");
}
}
}
De naamruimte van elke controller wordt hier weergegeven voor volledigheid. Als de voorgaande controllers dezelfde naamruimte gebruikten, wordt er een compilerfout gegenereerd. Klassenaamruimten hebben geen invloed op de routering van MVC.
De eerste twee controllers zijn leden van gebieden en komen alleen overeen wanneer hun respectieve gebiedsnaam wordt opgegeven door de area
routewaarde. De derde controller is geen lid van een gebied en kan alleen overeenkomen wanneer er geen waarde area
wordt opgegeven door routering.
In termen van de overeenkomende geen waarde betekent het ontbreken van de area
waarde hetzelfde als wanneer de waarde voor area
null of een lege tekenreeks is.
Bij het uitvoeren van een actie binnen een gebied wordt de routewaarde voor area
als een omgevingswaarde beschikbaar, die moet worden gebruikt voor de routering en het genereren van URL's. Dit betekent dat standaard gebieden blijven hangen voor het genereren van URL's, zoals in het volgende voorbeeld wordt gedemonstreerd.
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);
}
}
}
Met de volgende code wordt een URL gegenereerd voor /Zebra/Users/AddUser
:
public class HomeController : Controller
{
public IActionResult About()
{
var url = Url.Action("AddUser", "Users", new { Area = "Zebra" });
return Content($"URL: {url}");
}
Action definition
Openbare methoden op een controller, met uitzondering van methoden met het kenmerk NonAction , zijn acties.
Sample code
- MyDisplayRouteInfo wordt geleverd door het Rick.Docs.Samples.RouteInfo NuGet-pakket en toont routegegevens.
- Voorbeeldcode bekijken of downloaden (hoe download je)
Debug diagnostics
Voor gedetailleerde routeringsdiagnose-uitvoer, stel Logging:LogLevel:Microsoft
in op Debug
. Stel in de ontwikkelomgeving het logboekniveau in:appsettings.Development.json
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Debug",
"Microsoft.Hosting.Lifetime": "Information"
}
}
}
ASP.NET Core-controllers gebruiken de middleware routering om de URL's van binnenkomende aanvragen te vinden en deze toe te wijzen aan acties. Route templates:
- Zijn gedefinieerd in opstartcode of kenmerken.
- Beschrijven hoe URL-paden worden vergeleken met acties.
- Worden gebruikt voor het genereren van URL's voor koppelingen. De gegenereerde koppelingen worden meestal geretourneerd in antwoorden.
Acties worden conventioneel gerouteerd of door kenmerken gerouteerd. Een route die op de controller of actie wordt geplaatst, is kenmerk-gerouteerd. Zie Gemengde routering voor meer informatie.
This document:
- Hierin worden de interacties tussen MVC en routering uitgelegd:
- Hoe typische MVC-apps gebruikmaken van routeringsfuncties.
- Covers both:
- Conventionele routering die doorgaans wordt gebruikt met controllers en weergaven.
- Kenmerkroutering die wordt gebruikt met REST API's. Als u voornamelijk geïnteresseerd bent in routering voor REST API's, gaat u naar de sectie Kenmerkroutering voor REST API's .
- Zie Routering voor geavanceerde routeringsdetails.
- Verwijst naar het standaardrouteringssysteem dat is toegevoegd in ASP.NET Core 3.0, ook wel eindpuntroutering genoemd. Het is mogelijk om controllers te gebruiken met de vorige versie van routering voor compatibiliteitsdoeleinden. Zie de migratiehandleiding 2.2-3.0 voor instructies. Raadpleeg de versie 2.2 van dit document voor referentiemateriaal over het verouderde routeringssysteem.
Conventionele route instellen
Startup.Configure
heeft doorgaans code die vergelijkbaar is met de volgende bij het gebruik van conventionele routering:
app.UseEndpoints(endpoints =>
{
endpoints.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
});
In het aanroepen van UseEndpoints wordt MapControllerRoute gebruikt om één enkele route te maken. De enkele route heeft de naam default
route. De meeste apps met controllers en weergaven gebruiken een routesjabloon die vergelijkbaar is met de default
route.
REST API's moeten kenmerkroutering gebruiken.
De routesjabloon "{controller=Home}/{action=Index}/{id?}"
:
Komt overeen met een URL-pad, zoals
/Products/Details/5
Extraheert de routewaarden
{ controller = Products, action = Details, id = 5 }
door het pad te tokeniseren. De extractie van routewaarden resulteert in een overeenkomst als de app een controller heeft met de naamProductsController
en eenDetails
actie:public class ProductsController : Controller { public IActionResult Details(int id) { return ControllerContext.MyDisplayRouteInfo(id); } }
MyDisplayRouteInfo wordt geleverd door het Rick.Docs.Samples.RouteInfo NuGet-pakket en toont routegegevens.
/Products/Details/5
model koppelt de waarde vanid = 5
aan deid
parameter om deze in te stellen op5
. Zie Modelbinding voor meer informatie.{controller=Home}
definieertHome
als de standaardwaardecontroller
.{action=Index}
definieertIndex
als de standaardwaardeaction
.Het
?
teken in{id?}
definieertid
als optioneel.Standaard- en optionele routeparameters hoeven niet aanwezig te zijn in het URL-pad voor een overeenstemming. Zie De naslaginformatie over routesjablonen voor een gedetailleerde beschrijving van de syntaxis van de routesjabloon.
Komt overeen met het URL-pad
/
.Produceert de routewaarden
{ controller = Home, action = Index }
.
De waarden voor controller
en action
maken gebruik van de standaardwaarden.
id
produceert geen waarde omdat er geen corresponderend segment in het URL-pad is.
/
komt alleen overeen als er een HomeController
en Index
actie bestaat:
public class HomeController : Controller
{
public IActionResult Index() { ... }
}
Met behulp van de voorgaande controllerdefinitie en routesjabloon wordt de HomeController.Index
actie uitgevoerd voor de volgende URL-paden:
/Home/Index/17
/Home/Index
/Home
/
Het URL-pad /
maakt gebruik van de routesjabloon met standaardcontrollers Home
en de actie Index
. Het URL-pad /Home
maakt gebruik van de standaardactie Index
voor de routesjabloon.
De gemaksmethode MapDefaultControllerRoute:
endpoints.MapDefaultControllerRoute();
Replaces:
endpoints.MapControllerRoute("default", "{controller=Home}/{action=Index}/{id?}");
Important
Routering wordt geconfigureerd met behulp van de UseRouting, MapControllerRoute
en MapAreaControllerRoute
middleware . Controllers gebruiken:
- Roep MapControllers binnen
UseEndpoints
aan om kenmerkgerichte controllers te koppelen. - Roep MapControllerRoute of MapAreaControllerRoute aan om zowel conventioneel gerouteerde controllers als door attributen gerouteerde controllers in kaart te brengen.
Conventional routing
Conventionele routering wordt gebruikt met controllers en weergaven. De default
route:
endpoints.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
Het voorgaande is een voorbeeld van een conventionele route. Dit wordt conventionele routering genoemd omdat er een conventie voor URL-paden wordt vastgesteld:
- Het eerste padsegment,
{controller=Home}
wordt toegewezen aan de naam van de controller. - Het tweede segment,
{action=Index}
wordt toegewezen aan de naam van de actie. - Het derde segment
{id?}
wordt gebruikt voor een optioneelid
. De?
in{id?}
maakt het optioneel.id
wordt gebruikt om toe te wijzen aan een modelentiteit.
Met deze default
route wordt het URL-pad gebruikt:
-
/Products/List
wordt toegewezen aan deProductsController.List
actie. -
/Blog/Article/17
komt overeen metBlogController.Article
en meestal wordt deid
-parameter gekoppeld aan 17.
This mapping:
- Gebaseerd op alleen de controller en actienamen.
- Is niet gebaseerd op naamruimten, bronbestandslocaties of methodeparameters.
Met conventionele routering met de standaardroute kunt u de app maken zonder dat u voor elke actie een nieuw URL-patroon hoeft op te stellen. Voor een app met CRUD-stijlacties heeft u consistentie nodig voor de URL's over controllers heen:
- Helpt de code te vereenvoudigen.
- Maakt de gebruikersinterface voorspelbaarder.
Warning
De id
in de voorgaande code wordt gedefinieerd als optioneel door de routesjabloon. Acties kunnen worden uitgevoerd zonder de optionele id die is opgegeven als onderdeel van de URL. Over het algemeen, wanneer id
wordt weggelaten uit de URL:
-
id
wordt door middel van modelbinding ingesteld op0
. - Er is geen entiteit gevonden in de overeenkomende
id == 0
database.
Kenmerkroutering biedt fijnmazige controle om de ID verplicht te stellen voor sommige acties, maar niet voor andere. De documentatie bevat standaard optionele parameters, zoals id
wanneer ze waarschijnlijk in het juiste gebruik worden weergegeven.
De meeste apps moeten een eenvoudig en beschrijvend routeringsschema kiezen, zodat URL's leesbaar en zinvol zijn. De standaard conventionele route {controller=Home}/{action=Index}/{id?}
:
- Ondersteunt een eenvoudig en beschrijvend routeringsschema.
- Is een nuttig startpunt voor apps op basis van de gebruikersinterface.
- Is de enige routesjabloon die nodig is voor veel web-UI-apps. Voor grotere web-UI-apps is een andere route met het gebruik van Areas vaak alles wat nodig is.
MapControllerRoute en MapAreaRoute :
- Wijs automatisch een orderwaarde toe aan hun eindpunten op basis van de volgorde die ze worden aangeroepen.
Eindpuntroutering in ASP.NET Core 3.0 of hoger:
- Heeft geen concept van routes.
- Biedt geen bestelgaranties voor de uitvoering van uitbreidbaarheid, alle eindpunten worden in één keer verwerkt.
Schakel logging in om te zien hoe de ingebouwde routeringimplementaties verzoeken afhandelen, zoals Route.
Kenmerkroutering wordt verderop in dit document uitgelegd.
Meerdere conventionele routes
Meerdere conventionele routes kunnen binnen UseEndpoints
worden toegevoegd door meer aanroepen toe te voegen aan MapControllerRoute en MapAreaControllerRoute. Hiermee kunt u meerdere conventies definiëren of conventionele routes toevoegen die zijn toegewezen aan een specifieke actie, zoals:
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?}");
});
De blog
route in de voorgaande code is een toegewezen conventionele route. Dit wordt een speciale conventionele route genoemd omdat:
- Het maakt gebruik van conventionele routering.
- Het is gewijd aan een specifieke actie.
Omdat controller
en action
niet worden weergegeven in de routesjabloon "blog/{*article}"
als parameters:
- Ze kunnen alleen de standaardwaarden
{ controller = "Blog", action = "Article" }
hebben. - Deze route wordt altijd toegewezen aan de actie
BlogController.Article
.
/Blog
, /Blog/Article
en /Blog/{any-string}
zijn de enige URL-paden die overeenkomen met de blogroute.
Het voorgaande voorbeeld:
- De
blog
route heeft een hogere prioriteit bij het koppelen dan dedefault
route, omdat deze eerst wordt toegevoegd. - Is een voorbeeld van slug-stijlroutering , waarbij het gebruikelijk is om een artikelnaam te hebben als onderdeel van de URL.
Warning
In ASP.NET Core 3.0 of hoger werkt routering niet zoals:
- Definieer een concept dat een route wordt genoemd.
UseRouting
voegt routekoppeling toe aan de middleware-pijplijn. DeUseRouting
middleware bekijkt de set eindpunten die in de app zijn gedefinieerd en selecteert de beste eindpuntovereenkomst op basis van de aanvraag. - Garanties bieden over de uitvoeringsvolgorde van uitbreidbaarheid, zoals IRouteConstraint of IActionConstraint.
Zie Routering voor referentiemateriaal over routering.
Conventionele routeringsvolgorde
Conventionele routering komt alleen overeen met een combinatie van actie en controller die door de app worden gedefinieerd. Dit is bedoeld om gevallen waarin conventionele routes elkaar overlappen te vereenvoudigen.
Routes toevoegen met behulp van MapControllerRoute, MapDefaultControllerRoute en MapAreaControllerRoute wijst automatisch een orderwaarde toe aan hun eindpunten op basis van de volgorde waarin ze worden aangeroepen. Overeenkomsten van een route die eerder wordt weergegeven, hebben een hogere prioriteit. Conventionele routering is orderafhankelijk. In het algemeen moeten routes met gebieden eerder worden geplaatst omdat ze specifieker zijn dan routes zonder een gebied.
Toegewezen conventionele routes met catch-all routeparameters, zoals {*article}
kunnen een route te greedy maken, wat betekent dat deze overeenkomt met URL's die u hebt bedoeld om te worden vergeleken met andere routes. Plaats de gretige routes later in de routetabel om gretige overeenkomsten te voorkomen.
Warning
Een catch-all--parameter kan verkeerde routes matchen door een fout in de routering. Apps die door deze fout worden beïnvloed, hebben de volgende kenmerken:
- Een algemene route, bijvoorbeeld
{**slug}"
- De catch-all-route kan niet overeenkomen met aanvragen die moeten overeenkomen.
- Als u andere routes verwijdert, begint de catch-all route te werken.
Zie GitHub-bugs 18677 en 16579 voor voorbeeldgevallen die deze bug ervaren.
Een opt-in-oplossing voor deze fout is opgenomen in .NET Core 3.1.301 of hoger SDK. Met de volgende code wordt een interne switch ingesteld waarmee deze fout wordt opgelost:
public static void Main(string[] args)
{
AppContext.SetSwitch("Microsoft.AspNetCore.Routing.UseCorrectCatchAllBehavior",
true);
CreateHostBuilder(args).Build().Run();
}
// Remaining code removed for brevity.
Ambigu acties oplossen
Wanneer twee eindpunten overeenkomen via routering, moet routering een van de volgende handelingen uitvoeren:
- Kies de beste kandidaat.
- Gooi een uitzondering.
For example:
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);
}
}
}
De voorgaande controller definieert twee acties die overeenkomen met:
- Het URL-pad
/Products33/Edit/17
- Routegegevens
{ controller = Products33, action = Edit, id = 17 }
.
Dit is een typisch patroon voor MVC-controllers:
-
Edit(int)
geeft een formulier weer om een product te bewerken. -
Edit(int, Product)
verwerkt het geplaatste formulier.
De juiste route oplossen:
-
Edit(int, Product)
is geselecteerd wanneer de aanvraag een HTTPPOST
is. -
Edit(int)
is geselecteerd wanneer het HTTP-werkwoord iets anders is.Edit(int)
wordt over het algemeen viaGET
.
De HttpPostAttribute, [HttpPost]
wordt verstrekt aan routering, zodat deze kan kiezen op basis van de HTTP-methode van de aanvraag. De HttpPostAttribute
maakt Edit(int, Product)
een betere match dan Edit(int)
.
Het is belangrijk om inzicht te hebben in de rol van kenmerken zoals HttpPostAttribute
. Vergelijkbare kenmerken worden gedefinieerd voor andere HTTP-woorden. Bij conventionele routering is het gebruikelijk dat acties dezelfde actienaam gebruiken wanneer ze deel uitmaken van een toonformulier of het indienen van een formulierworkflow. Zie bijvoorbeeld de twee bewerkingsactiemethoden onderzoeken.
Als routering geen beste kandidaat kan kiezen, wordt er een AmbiguousMatchException gegenereerd, waarin de meerdere overeenkomende eindpunten worden vermeld.
Conventionele routenamen
De tekenreeksen "blog"
en "default"
in de volgende voorbeelden zijn conventionele routenamen:
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?}");
});
De routenamen geven de route een logische naam. De benoemde route kan worden gebruikt voor het genereren van URL's. Het gebruik van een benoemde route vereenvoudigt het maken van URL's wanneer de volgorde van routes ingewikkeld kan maken voor het genereren van URL's. Routenamen moeten uniek zijn voor de hele toepassing.
Route names:
- Geen invloed hebben op URL-matchen of verzoekafhandeling.
- Worden alleen gebruikt voor het genereren van URL's.
Het concept van de routenaam wordt weergegeven in routering als IEndpointNameMetadata. De termen routenaam en eindpuntnaam:
- Are interchangeable.
- Welke wordt gebruikt in documentatie en code, is afhankelijk van de API die wordt beschreven.
Kenmerkroutering voor REST API's
REST API's moeten kenmerkroutering gebruiken om de functionaliteit van de app te modelleren als een set resources waarin bewerkingen worden vertegenwoordigd door HTTP-woorden.
Kenmerkroutering maakt gebruik van een set kenmerken om acties rechtstreeks toe te wijzen aan routesjablonen. De volgende StartUp.Configure
code is typisch voor een REST API en wordt gebruikt in het volgende voorbeeld:
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();
});
}
In de voorgaande code wordt MapControllers binnen UseEndpoints
aangeroepen om controllers met eigenschapsrouting in kaart te brengen.
In het volgende voorbeeld:
-
HomeController
komt overeen met een set URL's die vergelijkbaar zijn met de standaardconventionele route{controller=Home}/{action=Index}/{id?}
.
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);
}
}
De HomeController.Index
actie wordt uitgevoerd voor een van de URL-paden/
, /Home
of /Home/Index
/Home/Index/3
.
In dit voorbeeld wordt een belangrijk programmeerverschil tussen kenmerkroutering en conventionele routering gemarkeerd. Voor kenmerkroutering is meer invoer vereist om een route op te geven. De conventionele standaardroute verwerkt routes beknopter. Met kenmerkroutering kunt u echter nauwkeurig bepalen welke routesjablonen van toepassing zijn op elke actie.
Bij kenmerkroutering spelen de controller- en actienamen geen rol waarin actie wordt vergeleken, tenzij tokenvervanging wordt gebruikt. Het volgende voorbeeld komt overeen met dezelfde URL's als in het vorige voorbeeld:
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);
}
}
De volgende code maakt gebruik van tokenvervanging voor action
en 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();
}
}
De volgende code is van toepassing op [Route("[controller]/[action]")]
de controller:
[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();
}
}
In de voorgaande code moeten de Index
methodesjablonen voorafgegaan worden door /
of ~/
bij de routesjablonen. Routesjablonen die worden toegepast op een actie die begint met /
of ~/
niet worden gecombineerd met routesjablonen die zijn toegepast op de controller.
Zie de prioriteit van routesjablonen voor informatie over de selectie van routesjablonen.
Gereserveerde routeringsnamen
De volgende trefwoorden zijn gereserveerde routeparameternamen bij het gebruik van Controllers of Razor Pages:
action
area
controller
handler
page
Het gebruik page
als routeparameter met kenmerkroutering is een veelvoorkomende fout. Dit leidt tot inconsistent en verwarrend gedrag met het genereren van URL's.
public class MyDemo2Controller : Controller
{
[Route("/articles/{page}")]
public IActionResult ListArticles(int page)
{
return ControllerContext.MyDisplayRouteInfo(page);
}
}
De speciale parameternamen worden door de URL-generatie gebruikt om te bepalen of een URL-generatiebewerking verwijst naar een Razor pagina of naar een controller.
De volgende trefwoorden zijn gereserveerd in de context van een Razor weergave of een Razor pagina:
page
using
namespace
inject
section
inherits
model
addTagHelper
removeTagHelper
Deze trefwoorden mogen niet worden gebruikt voor koppelingsgeneraties, modelgebonden parameters of eigenschappen op het hoogste niveau.
HTTP-werkwoordsjablonen
ASP.NET Core heeft de volgende HTTP-werkwoordsjablonen:
Route templates
ASP.NET Core heeft de volgende routesjablonen:
- Alle HTTP-werkwoordsjablonen zijn routesjablonen.
- [Route]
Kenmerkroutering met Http-werkwoordkenmerken
Houd rekening met de volgende controller:
[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);
}
}
In de voorgaande code:
- Elke actie bevat het
[HttpGet]
kenmerk, dat alleen overeenkomt met HTTP GET-aanvragen. - De
GetProduct
actie bevat de"{id}"
sjabloon en wordt daaromid
toegevoegd aan de"api/[controller]"
sjabloon op de controller. De sjabloon voor methoden is"api/[controller]/{id}"
. Daarom komt deze actie alleen overeen met GET-aanvragen voor het formulier/api/test2/xyz
/api/test2/123
,/api/test2/{any string}
enzovoort.[HttpGet("{id}")] // GET /api/test2/xyz public IActionResult GetProduct(string id) { return ControllerContext.MyDisplayRouteInfo(id); }
- De
GetIntProduct
actie bevat de"int/{id:int}"
sjabloon. Het:int
gedeelte van de sjabloon beperkt deid
routewaarden tot tekenreeksen die kunnen worden geconverteerd naar een geheel getal. Een GET-aanvraag voor/api/test2/int/abc
:- Komt niet overeen met deze actie.
- Retourneert een fout 404 Niet Gevonden.
[HttpGet("int/{id:int}")] // GET /api/test2/int/3 public IActionResult GetIntProduct(int id) { return ControllerContext.MyDisplayRouteInfo(id); }
- De
GetInt2Product
actie bevat{id}
in de sjabloon, maar legt geen beperkingen op aanid
tot waarden die kunnen worden geconverteerd naar een geheel getal. Een GET-aanvraag voor/api/test2/int2/abc
:- Komt overeen met deze route.
- Modelbinding kan
abc
niet omzetten naar een geheel getal. Deid
parameter van de methode is geheel getal. - Retourneert een 400 Bad Request omdat het niet gelukt is om
abc
naar een geheel getal te converteren.[HttpGet("int2/{id}")] // GET /api/test2/int2/3 public IActionResult GetInt2Product(int id) { return ControllerContext.MyDisplayRouteInfo(id); }
Kenmerkroutering kan gebruikmaken van HttpMethodAttribute kenmerken zoals HttpPostAttribute, HttpPutAttributeen HttpDeleteAttribute. Alle HTTP-werkwoordkenmerken accepteren een routesjabloon. In het volgende voorbeeld ziet u twee acties die overeenkomen met dezelfde routesjabloon:
[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);
}
}
Het URL-pad gebruiken /products3
:
- De
MyProductsController.ListProducts
-actie wordt uitgevoerd wanneer het HTTP-werkwoordGET
is. - De
MyProductsController.CreateProduct
-actie wordt uitgevoerd wanneer het HTTP-werkwoordPOST
is.
Bij het bouwen van een REST API is het zeldzaam dat u moet gebruiken [Route(...)]
voor een actiemethode, omdat de actie alle HTTP-methoden accepteert. Het is beter om het specifiekere HTTP-werkwoordkenmerk te gebruiken om precies te zijn wat uw API ondersteunt. Clients van REST API's zullen naar verwachting weten welke paden en HTTP-werkwoorden zijn toegewezen aan specifieke logische bewerkingen.
REST API's moeten kenmerkroutering gebruiken om de functionaliteit van de app te modelleren als een set resources waarin bewerkingen worden vertegenwoordigd door HTTP-woorden. Dit betekent dat veel bewerkingen, bijvoorbeeld GET en POST op dezelfde logische resource, dezelfde URL gebruiken. Kenmerkroutering biedt een beheerniveau dat nodig is om de indeling van een openbaar eindpunt van een API zorgvuldig te ontwerpen.
Omdat een kenmerkroute van toepassing is op een specifieke actie, is het eenvoudig om parameters vereist te maken als onderdeel van de definitie van de routesjabloon. In het volgende voorbeeld id
is dit vereist als onderdeel van het URL-pad:
[ApiController]
public class Products2ApiController : ControllerBase
{
[HttpGet("/products2/{id}", Name = "Products_List")]
public IActionResult GetProduct(int id)
{
return ControllerContext.MyDisplayRouteInfo(id);
}
}
De Products2ApiController.GetProduct(int)
actie:
- Wordt uitgevoerd met een url-pad zoals
/products2/3
- Wordt niet uitgevoerd met het URL-pad
/products2
.
Met het kenmerk [Verbruiken] kan een actie de ondersteunde inhoudstypen voor aanvragen beperken. Zie Ondersteunde aanvraaginhoudstypen definiëren met het kenmerk Verbruiken voor meer informatie.
Zie Routering voor een volledige beschrijving van routesjablonen en gerelateerde opties.
Zie [ApiController]
voor meer informatie.
Route name
De volgende code definieert een routenaam van Products_List
:
[ApiController]
public class Products2ApiController : ControllerBase
{
[HttpGet("/products2/{id}", Name = "Products_List")]
public IActionResult GetProduct(int id)
{
return ControllerContext.MyDisplayRouteInfo(id);
}
}
Routenamen kunnen worden gebruikt om een URL te genereren op basis van een specifieke route. Route names:
- Dit heeft geen invloed op het URL-overeenkomende gedrag van routering.
- Worden alleen gebruikt voor het genereren van URL's.
Routenamen moeten uniek zijn voor de hele toepassing.
Vergelijk de voorgaande code met de conventionele standaardroute, die de id
parameter definieert als optioneel ({id?}
). De mogelijkheid om API's nauwkeurig op te geven heeft voordelen, zoals het toestaan dat /products
en /products/5
worden uitgevoerd door verschillende acties.
Het combineren van kenmerkroutes
Om kenmerkroutering minder herhalend te maken, worden routekenmerken op de controller gecombineerd met routekenmerken voor de afzonderlijke acties. Routesjablonen die op de controller zijn gedefinieerd, worden toegevoegd aan de routesjablonen van de acties. Als u een routekenmerk op de controller plaatst, worden alle acties in de controller gebruikt om kenmerkroutering te gebruiken.
[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);
}
}
In het voorgaande voorbeeld:
- Het URL-pad
/products
kan overeenkomen metProductsApi.ListProducts
- Het URL-pad
/products/5
kan overeenkomen metProductsApi.GetProduct(int)
.
Beide acties komen alleen overeen met HTTP GET
omdat ze zijn gemarkeerd met het [HttpGet]
kenmerk.
Routesjablonen die worden toegepast op een actie die begint met /
of ~/
niet worden gecombineerd met routesjablonen die zijn toegepast op de controller. Het volgende voorbeeld komt overeen met een set URL-paden die vergelijkbaar zijn met de standaardroute.
[Route("Home")]
public class HomeController : Controller
{
[Route("")]
[Route("Index")]
[Route("/")]
public IActionResult Index()
{
return ControllerContext.MyDisplayRouteInfo();
}
[Route("About")]
public IActionResult About()
{
return ControllerContext.MyDisplayRouteInfo();
}
}
In de volgende tabel worden de [Route]
kenmerken in de voorgaande code uitgelegd:
Attribute | Combineert met [Route("Home")] |
Definieert routesjabloon |
---|---|---|
[Route("")] |
Yes | "Home" |
[Route("Index")] |
Yes | "Home/Index" |
[Route("/")] |
No | "" |
[Route("About")] |
Yes | "Home/About" |
Routevolgorde kenmerk
Routering bouwt een structuur en komt overeen met alle eindpunten tegelijk:
- De routevermeldingen gedragen zich alsof ze in een ideale volgorde worden geplaatst.
- De meest specifieke routes hebben de kans om uit te voeren vóór de meer algemene routes.
Een kenmerkroute zoals blog/search/{topic}
is bijvoorbeeld specifieker dan een kenmerkroute zoals blog/{*article}
. De blog/search/{topic}
route heeft standaard een hogere prioriteit, omdat deze specifieker is. Met conventionele routering is de ontwikkelaar verantwoordelijk voor het plaatsen van routes in de gewenste volgorde.
Kenmerkroutes kunnen een order configureren met behulp van de Order eigenschap. Alle door het framework geleverde routekenmerken omvatten Order
. Routes worden verwerkt op basis van een oplopend type eigenschap Order
. De standaardvolgorde is 0
. Een route instellen met behulp van Order = -1
uitvoeringen voor routes die geen order instellen. Een route instellen met behulp van Order = 1
vindt plaats na de standaard routevolgorde.
Vermijd afhankelijk Order
van . Als de URL-ruimte van een app expliciete volgordewaarden vereist om correct te routeren, is het waarschijnlijk ook verwarrend voor clients. Over het algemeen selecteert kenmerkroutering de juiste route met URL-overeenkomsten. Als de standaardvolgorde die wordt gebruikt voor het genereren van URL's niet werkt, is het gebruik van een routenaam als onderdrukking meestal eenvoudiger dan het toepassen van de Order
eigenschap.
Houd rekening met de volgende twee controllers die beide de routekoppeling /home
definiëren:
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);
}
}
Als u aanvraagt /home
met de voorgaande code, wordt er een uitzondering gegenereerd die vergelijkbaar is met de volgende:
AmbiguousMatchException: The request matched multiple endpoints. Matches:
WebMvcRouting.Controllers.HomeController.Index
WebMvcRouting.Controllers.MyDemoController.MyIndex
Als u een van de routekenmerken toevoegt Order
, wordt de dubbelzinnigheid opgelost:
[Route("")]
[Route("Home", Order = 2)]
[Route("Home/MyIndex")]
public IActionResult MyIndex()
{
return ControllerContext.MyDisplayRouteInfo();
}
Met de voorgaande code /home
wordt het HomeController.Index
eindpunt uitgevoerd. Om naar de MyDemoController.MyIndex
, aanvraag /home/MyIndex
te gaan .
Note:
- De voorgaande code is een voorbeeld of een slecht routeringsontwerp. Deze is gebruikt om de
Order
eigenschap te illustreren. - De
Order
eigenschap lost alleen de dubbelzinnigheid op, die sjabloon kan niet worden vergeleken. Het is beter om de[Route("Home")]
sjabloon te verwijderen.
Zie Razor route- en app-conventies voor pagina's: Routevolgorde voor informatie over routevolgordes met Razor Pagina's.
In sommige gevallen wordt een HTTP 500-fout geretourneerd met ambigu routes. Gebruik loggen om te zien welke eindpunten de AmbiguousMatchException
veroorzaken.
Tokenvervanging in routesjablonen [controller], [actie], [gebied]
Voor het gemak ondersteunen kenmerkroutes tokenvervanging door een token tussen vierkante haken ([
, ]
) te sluiten. De tokens [action]
, [area]
en [controller]
worden vervangen door de waarden van de actienaam, gebiedsnaam en controllernaam uit de actie waarin de route is gedefinieerd:
[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);
}
}
In de voorgaande code:
[HttpGet]
public IActionResult List()
{
return ControllerContext.MyDisplayRouteInfo();
}
- Wedstrijden
/Products0/List
[HttpGet("{id}")]
public IActionResult Edit(int id)
{
return ControllerContext.MyDisplayRouteInfo(id);
}
- Wedstrijden
/Products0/Edit/{id}
Tokenvervanging vindt plaats als de laatste stap van het bouwen van de attribuutroutes. Het voorgaande voorbeeld gedraagt zich hetzelfde als de volgende code:
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);
}
}
Als u dit leest in een andere taal dan Engels, laat het ons dan weten in dit GitHub-discussieprobleem als u de codeopmerkingen in uw eigen taal wilt zien.
Attribuutsroutes kunnen ook worden gecombineerd met overerving. De kracht hiervan komt goed tot uiting wanneer het wordt gecombineerd met tokenvervanging. Tokenvervanging is ook van toepassing op routenamen die zijn gedefinieerd door kenmerkroutes.
[Route("[controller]/[action]", Name="[controller]_[action]")]
genereert een unieke routenaam voor elke actie:
[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);
}
}
Als u het letterlijke scheidingsteken voor tokenvervanging [
wilt vergelijken of ]
, escapet u het door het teken ([[
of ]]
) te herhalen.
Een parametertransformatie gebruiken om tokenvervanging aan te passen
Tokenvervanging kan worden aangepast met behulp van een parametertransformator. Een parametertransformator implementeert IOutboundParameterTransformer en transformeert de waarde van parameters. Een aangepaste SlugifyParameterTransformer
parametertransformator wijzigt bijvoorbeeld de SubscriptionManagement
routewaarde in 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();
}
}
Dit RouteTokenTransformerConvention is een toepassingsmodelconventie die:
- Hiermee past u een parametertransformatie toe op alle kenmerkroutes in een toepassing.
- Hiermee worden de waarden van het kenmerkroutetoken aangepast wanneer ze worden vervangen.
public class SubscriptionManagementController : Controller
{
[HttpGet("[controller]/[action]")]
public IActionResult ListAll()
{
return ControllerContext.MyDisplayRouteInfo();
}
}
De voorgaande ListAll
methode komt overeen /subscription-management/list-all
.
De RouteTokenTransformerConvention
is geregistreerd als een optie in ConfigureServices
.
public void ConfigureServices(IServiceCollection services)
{
services.AddControllersWithViews(options =>
{
options.Conventions.Add(new RouteTokenTransformerConvention(
new SlugifyParameterTransformer()));
});
}
Zie MDN-webdocumenten op Slug voor de definitie van Slug.
Warning
Wanneer u System.Text.RegularExpressions gebruikt om niet-vertrouwde invoer te verwerken, geeft u een time-out door. Een kwaadwillende gebruiker kan invoer opgeven om een RegularExpressions
te veroorzaken. ASP.NET Core framework-API's die gebruikmaken van RegularExpressions
geven een time-out door.
Meerdere kenmerkroutes
Kenmerkroutering ondersteunt het definiëren van meerdere routes die dezelfde actie bereiken. Het meest voorkomende gebruik hiervan is om het gedrag van de standaard conventionele route na te bootsen, zoals wordt weergegeven in het volgende voorbeeld:
[Route("[controller]")]
public class Products13Controller : Controller
{
[Route("")] // Matches 'Products13'
[Route("Index")] // Matches 'Products13/Index'
public IActionResult Index()
{
return ControllerContext.MyDisplayRouteInfo();
}
Als u meerdere routekenmerken op de controller plaatst, betekent dit dat elke eigenschap wordt gecombineerd met elk van de routekenmerken op de actiemethoden:
[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();
}
}
Alle http-bewerkingsroutebeperkingen worden geïmplementeerd IActionConstraint
.
Wanneer meerdere routekenmerken die worden geïmplementeerd IActionConstraint op een actie worden geplaatst:
- Elke actiebeperking combineert met de routesjabloon die is toegepast op de controller.
[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();
}
}
Het gebruik van meerdere routes voor acties kan nuttig en krachtig lijken, het is beter om de URL-ruimte van uw app eenvoudig en goed gedefinieerd te houden. Gebruik meerdere routes voor acties alleen wanneer dat nodig is, bijvoorbeeld om bestaande clients te ondersteunen.
Optionele parameters, standaardwaarden en beperkingen voor kenmerkroute opgeven
Kenmerkroutes ondersteunen dezelfde inlinesyntaxis als conventionele routes om optionele parameters, standaardwaarden en beperkingen op te geven.
public class Products14Controller : Controller
{
[HttpPost("product14/{id:int}")]
public IActionResult ShowProduct(int id)
{
return ControllerContext.MyDisplayRouteInfo(id);
}
}
In de voorgaande code [HttpPost("product14/{id:int}")]
past u een routebeperking toe. De Products14Controller.ShowProduct
-actie komt alleen overeen met URL-paden zoals /product14/3
. Het gedeelte {id:int}
van de routesjabloon beperkt dat segment tot alleen gehele getallen.
Zie De naslaginformatie over routesjablonen voor een gedetailleerde beschrijving van de syntaxis van de routesjabloon.
Aangepaste routekenmerken met IRouteTemplateProvider
Alle routekenmerken worden geïmplementeerd IRouteTemplateProvider. De ASP.NET Core-runtime:
- Zoekt naar kenmerken in controllerklassen en actiemethoden wanneer de app wordt gestart.
- Maakt gebruik van de kenmerken die worden geïmplementeerd
IRouteTemplateProvider
om de eerste set routes te bouwen.
Implementeren IRouteTemplateProvider
om aangepaste routekenmerken te definiëren. Met elke IRouteTemplateProvider
route kunt u één route definiëren met een aangepaste routesjabloon, volgorde en naam:
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();
}
}
De voorgaande Get
methode retourneert Order = 2, Template = api/MyTestApi
.
Toepassingsmodel gebruiken om kenmerkroutes aan te passen
Het toepassingsmodel:
- Is een objectmodel dat bij het opstarten is gemaakt.
- Bevat alle metagegevens die door ASP.NET Core worden gebruikt om de acties in een app te routeren en uit te voeren.
Het toepassingsmodel bevat alle gegevens die zijn verzameld uit routekenmerken. De gegevens van routekenmerken worden geleverd door de IRouteTemplateProvider
implementatie. Conventions:
- Kan worden geschreven om het toepassingsmodel te wijzigen om aan te passen hoe routering zich gedraagt.
- Worden gelezen bij het opstarten van de app.
In deze sectie ziet u een eenvoudig voorbeeld van het aanpassen van routering met behulp van een toepassingsmodel. Met de volgende code worden routes grofweg afgestemd op de mapstructuur van het project.
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()
};
}
}
}
Met de volgende code voorkomt u dat de namespace
conventie wordt toegepast op controllers die door een kenmerk worden gerouteerd:
public void Apply(ControllerModel controller)
{
var hasRouteAttributes = controller.Selectors.Any(selector =>
selector.AttributeRouteModel != null);
if (hasRouteAttributes)
{
return;
}
De volgende controller gebruikt NamespaceRoutingConvention
bijvoorbeeld niet:
[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}");
}
}
De methode NamespaceRoutingConvention.Apply
:
- Doet niets als de controller wordt gerouteerd.
- Hiermee stelt u de sjabloon controllers in op basis van de
namespace
sjabloon , waarbij de basisnamespace
is verwijderd.
De NamespaceRoutingConvention
kan worden toegepast in 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.
Denk bijvoorbeeld aan de volgende controller:
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}");
}
}
}
In de voorgaande code:
- De basis
namespace
isMy.Application
. - De volledige naam van de voorgaande controller is
My.Application.Admin.Controllers.UsersController
. - Hiermee
NamespaceRoutingConvention
stelt u de controllersjabloon in opAdmin/Controllers/Users/[action]/{id?
.
De NamespaceRoutingConvention
kan ook worden toegepast als een kenmerk op een controller:
[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}");
}
}
Gemengde routering: Kenmerkroutering versus conventionele routering
ASP.NET Core-apps kunnen het gebruik van conventionele routering en kenmerkroutering combineren. Het is gebruikelijk om conventionele routes te gebruiken voor controllers die HTML-pagina's voor browsers bedienen en kenmerkroutering voor controllers die API's bedienen REST .
Acties worden of conventioneel gerouteerd of via attributen gerouteerd. Wanneer je een route op de controller of de actie plaatst, wordt deze met attributen gerouteerd. Acties die kenmerkroutes definiëren, kunnen niet worden bereikt via de conventionele routes en omgekeerd. Elk routeattribuut op de controller maakt alle acties in de controller gerouteerd.
Kenmerkroutering en conventionele routering gebruiken dezelfde routeringsengine.
URL-generatie en omgevingswaarden
Apps kunnen functies voor het genereren van routerings-URL's gebruiken om URL-koppelingen naar acties te genereren. Het genereren van URL's elimineert hardcoderings-URL's, waardoor code robuuster en onderhoudbaarer wordt. Deze sectie is gericht op de functies voor het genereren van URL's die door MVC worden geboden en beslaan alleen de basisbeginselen van het genereren van URL's. Zie Routering voor een gedetailleerde beschrijving van het genereren van URL's.
De IUrlHelper interface is het onderliggende element van de infrastructuur tussen MVC en routering voor het genereren van URL's. Een exemplaar van IUrlHelper
is beschikbaar via de Url
eigenschap in controllers, weergaven en weergaveonderdelen.
In het volgende voorbeeld wordt de IUrlHelper
interface gebruikt via de Controller.Url
eigenschap om een URL naar een andere actie te genereren.
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();
}
}
Als de app gebruikmaakt van de standaard conventionele route, is de waarde van de url
variabele de URL-padtekenreeks /UrlGeneration/Destination
. Dit URL-pad wordt gemaakt door routering door het volgende te combineren:
- De routewaarden van de huidige aanvraag, die omgevingswaarden worden genoemd.
- De waarden die worden doorgegeven aan
Url.Action
en die waarden invoegen in de routesjabloon:
ambient values: { controller = "UrlGeneration", action = "Source" }
values passed to Url.Action: { controller = "UrlGeneration", action = "Destination" }
route template: {controller}/{action}/{id?}
result: /UrlGeneration/Destination
Elke routeparameter in de routesjabloon wordt vervangen door namen die overeenkomen met de waarden en omgevingswaarden. Een routeparameter die geen waarde heeft, kan:
- Gebruik een standaardwaarde als deze een waarde heeft.
- Overgeslagen als dit optioneel is. Bijvoorbeeld de
id
van de routesjabloon{controller}/{action}/{id?}
.
Het genereren van url's mislukt als een vereiste routeparameter geen bijbehorende waarde heeft. Als het genereren van url's voor een route mislukt, wordt de volgende route geprobeerd totdat alle routes zijn geprobeerd of een overeenkomst wordt gevonden.
In het voorgaande voorbeeld wordt uitgegaan van Url.Action
conventionele routering. Het genereren van URL's werkt op dezelfde manier met kenmerkroutering, hoewel de concepten verschillen. Bij gebruik van conventionele routering:
- De routewaarden worden gebruikt om een sjabloon uit te vouwen.
- De routewaarden voor
controller
enaction
worden meestal weergegeven in die sjabloon. Dit werkt omdat de URL's die overeenkomen met routering voldoen aan een conventie.
In het volgende voorbeeld wordt kenmerkroutering gebruikt:
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();
}
}
De Source
actie in de voorgaande code genereert custom/url/to/destination
.
LinkGenerator is toegevoegd in ASP.NET Core 3.0 als alternatief voor IUrlHelper
.
LinkGenerator
biedt vergelijkbare maar flexibelere functionaliteit. Elke methode op IUrlHelper
heeft ook een bijbehorende reeks methoden LinkGenerator
.
URL's genereren op actienaam
Url.Action, LinkGenerator.GetPathByAction en alle gerelateerde overbelastingen zijn ontworpen om het doeleindpunt te genereren door een controllernaam en actienaam op te geven.
Wanneer u Url.Action
gebruikt, worden de huidige routewaarden voor controller
en action
geleverd door de runtime:
- De waarde van
controller
enaction
maken deel uit van zowel omgevingswaarden als waarden. De methodeUrl.Action
gebruikt altijd de huidige waarden vanaction
encontroller
genereert een URL-pad dat naar de huidige actie routeert.
Routering probeert de waarden in omgevingswaarden te gebruiken om informatie in te vullen die niet is opgegeven bij het genereren van een URL. Overweeg een route zoals {a}/{b}/{c}/{d}
met omgevingswaarden { a = Alice, b = Bob, c = Carol, d = David }
:
- Routering bevat voldoende informatie om een URL te genereren zonder extra waarden.
- Routering heeft voldoende informatie omdat alle routeparameters een waarde hebben.
Als de waarde { d = Donovan }
wordt toegevoegd:
- De waarde
{ d = David }
wordt genegeerd. - Het gegenereerde URL-pad is
Alice/Bob/Carol/Donovan
.
Waarschuwing: URL-paden zijn hiërarchisch. Als in het voorgaande voorbeeld de waarde { c = Cheryl }
wordt toegevoegd:
- Beide waarden
{ c = Carol, d = David }
worden genegeerd. - Er is geen waarde meer voor
d
en het genereren van URL's mislukt. - De gewenste waarden van
c
end
moeten worden opgegeven om een URL te genereren.
U kunt verwachten dat dit probleem zich voordoet met de standaardroute {controller}/{action}/{id?}
. Dit probleem komt zelden voor in de praktijk omdat Url.Action
altijd expliciet een controller
- en action
-waarde specificeert.
Verschillende overbelastingen van URL.Action voeren een routewaardenobject uit om waarden op te geven voor andere routeparameters dan controller
en action
. Het object voor routewaarden wordt vaak gebruikt met id
. Bijvoorbeeld: Url.Action("Buy", "Products", new { id = 17 })
. Het routewaardenobject:
- Volgens conventie is een object meestal van anoniem type.
- Kan een
IDictionary<>
of een POCO zijn).
Eventuele extra routewaarden die niet overeenkomen met routeparameters, worden in de querytekenreeks geplaatst.
public IActionResult Index()
{
var url = Url.Action("Buy", "Products", new { id = 17, color = "red" });
return Content(url);
}
De voorgaande code genereert /Products/Buy/17?color=red
.
Met de volgende code wordt een absolute URL gegenereerd:
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);
}
Gebruik een van de volgende manieren om een absolute URL te maken:
- Een overload-functie die een
protocol
accepteert. Bijvoorbeeld de voorgaande code. - LinkGenerator.GetUriByAction, waarmee standaard absolute URI's worden gegenereerd.
URLs per route genereren
In de voorgaande code is het genereren van een URL gedemonstreerd door de controller en de actienaam door te geven.
IUrlHelper
biedt ook de url.RouteUrl-reeks methoden. Deze methoden zijn vergelijkbaar met Url.Action, maar ze kopiëren niet de huidige waarden van action
en controller
naar de routewaarden. Het meest voorkomende gebruik van Url.RouteUrl
:
- Hiermee geeft u een routenaam op voor het genereren van de URL.
- Over het algemeen specificeer je geen controller- of actienaam.
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();
}
In het volgende Razor bestand wordt een HTML-koppeling naar het Destination_Route
volgende bestand gegenereerd:
<h1>Test Links</h1>
<ul>
<li><a href="@Url.RouteUrl("Destination_Route")">Test Destination_Route</a></li>
</ul>
URLs genereren in HTML en Razor
IHtmlHelperbiedt de HtmlHelper methoden Html.BeginForm en Html.ActionLink om respectievelijk elementen te genereren<form>
.<a>
Deze methoden gebruiken de methode Url.Action om een URL te genereren en ze accepteren vergelijkbare argumenten. De metgezellen voor Url.RouteUrl
zijn HtmlHelper
en Html.BeginRouteForm
, die vergelijkbare functionaliteit hebben.
TagHelpers genereren URL's met behulp van de TagHelper form
en de TagHelper <a>
. Beide gebruiken IUrlHelper
voor hun implementatie. Zie Tag Helpers in formulieren voor meer informatie.
In weergaven is de IUrlHelper
functie beschikbaar via de Url
eigenschap voor elke ad-hoc-URL-generatie die niet wordt gedekt door het bovenstaande.
URL-generatie in actieresultaten
In de voorgaande voorbeelden is het gebruik IUrlHelper
in een controller getoond. Het meest voorkomende gebruik in een controller is het genereren van een URL als onderdeel van een actieresultaat.
De ControllerBase en Controller basisklassen bieden handige methoden voor actieresultaten die verwijzen naar een andere actie. Een typisch gebruik is om om te leiden na het accepteren van gebruikersinvoer:
[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);
}
De actie resulteert in factory-methoden zoals RedirectToAction en CreatedAtAction volgen een vergelijkbaar patroon als de methoden op IUrlHelper
.
Speciaal geval voor speciale conventionele routes
Conventionele routering kan een speciaal soort routedefinitie gebruiken, een speciale conventionele route genoemd. In het volgende voorbeeld is de benoemde blog
route een toegewezen conventionele route:
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?}");
});
Met behulp van de voorgaande routedefinities Url.Action("Index", "Home")
genereert u het URL-pad /
met behulp van de default
route, maar waarom? U kunt raden dat de routewaarden { controller = Home, action = Index }
voldoende zijn om een URL te genereren met behulp van blog
, en het resultaat zou zijn /blog?action=Index&controller=Home
.
Toegewezen conventionele routes zijn afhankelijk van een speciaal gedrag van standaardwaarden die geen bijbehorende routeparameter hebben die voorkomt dat de route te greedy is met het genereren van URL's. In dit geval zijn de standaardwaarden en { controller = Blog, action = Article }
worden ze controller
niet action
weergegeven als routeparameter. Wanneer routering URL-generatie uitvoert, moeten de opgegeven waarden overeenkomen met de standaardwaarden. Het genereren van URL's met behulp van blog
mislukt omdat de waarden { controller = Home, action = Index }
niet overeenkomen { controller = Blog, action = Article }
. Routering valt vervolgens terug om te proberen default
, wat slaagt.
Areas
Gebieden zijn een MVC-functie die wordt gebruikt voor het organiseren van gerelateerde functionaliteit in een groep als afzonderlijke:
- Routeringsnaamruimte voor controlleracties.
- Mapstructuur voor weergaven.
Als u gebieden gebruikt, kan een app meerdere controllers met dezelfde naam hebben, zolang ze verschillende gebieden hebben. Met behulp van gebieden wordt een hiërarchie gemaakt voor routering door een andere routeparameter area
toe te voegen aan controller
en action
. In deze sectie wordt beschreven hoe routering communiceert met gebieden. Zie Gebieden voor meer informatie over hoe gebieden in combinatie met weergaven worden gebruikt.
In het volgende voorbeeld wordt MVC geconfigureerd voor het gebruik van de standaard conventionele route en een area
route voor een area
met de naam Blog
.
app.UseEndpoints(endpoints =>
{
endpoints.MapAreaControllerRoute("blog_route", "Blog",
"Manage/{controller}/{action}/{id?}");
endpoints.MapControllerRoute("default_route", "{controller}/{action}/{id?}");
});
In de voorgaande code MapAreaControllerRoute wordt aangeroepen om de "blog_route"
. De tweede parameter, "Blog"
is de gebiedsnaam.
Wanneer het overeenkomt met een URL-pad zoals /Manage/Users/AddUser
, genereert de "blog_route"
route de routewaarden { area = Blog, controller = Users, action = AddUser }
. De area
routewaarde wordt geproduceerd door een standaardwaarde voor area
. De route die is gemaakt door MapAreaControllerRoute
, is gelijk aan het volgende:
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
maakt een route met zowel een standaardwaarde als een beperking voor area
het gebruik van de opgegeven gebiedsnaam, in dit geval Blog
. De standaardwaarde zorgt ervoor dat de route altijd produceert { area = Blog, ... }
. De beperking vereist de waarde { area = Blog, ... }
voor het genereren van URL's.
Conventionele routering is orderafhankelijk. In het algemeen moeten routes met gebieden eerder worden geplaatst omdat ze specifieker zijn dan routes zonder een gebied.
In het voorgaande voorbeeld komen de routewaarden { area = Blog, controller = Users, action = AddUser }
overeen met de volgende actie:
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}");
}
}
}
Het kenmerk [Gebied] geeft een controller aan als onderdeel van een gebied. Deze controller bevindt zich in het Blog
gebied. Controllers zonder kenmerk [Area]
zijn geen lid van een gebied en komen niet overeen wanneer de area
routewaarde wordt geleverd door routering. In het volgende voorbeeld kan alleen de eerste vermelde controller overeenkomen met de routewaarden { 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}");
}
}
}
De naamruimte van elke controller wordt hier weergegeven voor volledigheid. Als de voorgaande controllers dezelfde naamruimte gebruikten, wordt er een compilerfout gegenereerd. Klassenaamruimten hebben geen invloed op de routering van MVC.
De eerste twee controllers zijn leden van gebieden en komen alleen overeen wanneer hun respectieve gebiedsnaam wordt opgegeven door de area
routewaarde. De derde controller is geen lid van een gebied en kan alleen overeenkomen wanneer er geen waarde area
wordt opgegeven door routering.
In termen van de overeenkomende geen waarde betekent het ontbreken van de area
waarde hetzelfde als wanneer de waarde voor area
null of een lege tekenreeks is.
Bij het uitvoeren van een actie binnen een gebied wordt de routewaarde voor area
als een omgevingswaarde beschikbaar, die moet worden gebruikt voor de routering en het genereren van URL's. Dit betekent dat standaard gebieden blijven hangen voor het genereren van URL's, zoals in het volgende voorbeeld wordt gedemonstreerd.
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);
}
}
}
Met de volgende code wordt een URL gegenereerd voor /Zebra/Users/AddUser
:
public class HomeController : Controller
{
public IActionResult About()
{
var url = Url.Action("AddUser", "Users", new { Area = "Zebra" });
return Content($"URL: {url}");
}
Action definition
Openbare methoden op een controller, met uitzondering van methoden met het kenmerk NonAction , zijn acties.
Sample code
- MyDisplayRouteInfo wordt geleverd door het Rick.Docs.Samples.RouteInfo NuGet-pakket en toont routegegevens.
- Voorbeeldcode bekijken of downloaden (hoe download je)
Debug diagnostics
Voor gedetailleerde routeringsdiagnose-uitvoer, stel Logging:LogLevel:Microsoft
in op Debug
. Stel in de ontwikkelomgeving het logboekniveau in:appsettings.Development.json
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Debug",
"Microsoft.Hosting.Lifetime": "Information"
}
}
}