Hinweis
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, sich anzumelden oder das Verzeichnis zu wechseln.
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, das Verzeichnis zu wechseln.
Von Ryan Nowak, Kirk Larkin und Rick Anderson
Note
Dies ist nicht die neueste Version dieses Artikels. Die aktuelle Version finden Sie in der .NET 10-Version dieses Artikels.
Warning
Diese Version von ASP.NET Core wird nicht mehr unterstützt. Weitere Informationen finden Sie unter .NET und .NET Core Support Policy. Die aktuelle Version finden Sie in der .NET 10-Version dieses Artikels.
ASP.NET Core Controller verwenden die Routing-Middleware, um die URLs eingehender Anforderungen abzugleichen und ihnen Aktionen zuzuordnen. Routenvorlagen:
- Werden beim Start in oder in Attributen definiert
- Beschreiben, wie URL-Pfade mit Aktionen abgeglichen werden
- Werden verwendet, um URLs für Links zu generieren Die generierten Links werden in der Regel in Antworten zurückgegeben
Aktionen werden entweder konventionell geroutet oder attributbasiert geroutet. Eine Route auf dem Controller oder der Aktion zu platzieren macht sie attributgesteuert. Weitere Informationen finden Sie im Abschnitt Gemischtes Routing.
Dieses Dokument:
- Die Interaktionen zwischen MVC und Routing werden erläutert:
- Es wird erklärt, wie typische MVC-Apps die Routingfeatures nutzen.
- Deckt beides ab:
- Herkömmliches Routing, das in der Regel mit Controllern und Ansichten verwendet wird.
- Attribut-Routing verwendet mit -APIs. Wenn Sie sich hauptsächlich für das Routing für -APIs interessieren, wechseln Sie zum Abschnitt Attributrouting für -APIs.
- Informationen zum erweiterten Routing finden Sie unter Routing.
- Bezieht sich auf das Standardroutingsystem als Endpunktrouting. Sie können Controller mit der vorherigen Version des Routings für Kompatibilitätszwecke verwenden. Anweisungen finden Sie im Migrationsleitfaden 2.2–3.0.
Einrichten einer herkömmlichen Route
Die ASP.NET Core MVC-Vorlage generiert conventional routing Code ähnlich dem folgenden Beispiel:
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();
Dient zum Erstellen einer einzelnen Route. Die einzige Route ist die Route. Die meisten Apps mit Controllern und Ansichten verwenden eine Routenvorlage, die der -Route ähnelt. -APIs sollten Attribut-Routingverwenden.
app.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
Die Routenvorlage :
Entspricht einem URL-Pfad wie .
Extrahiert die Routenwerte durch Tokenisieren des Pfads. Die Extraktion von Routenwerten führt zu einer Übereinstimmung, wenn die App über einen Controller namens und eine -Aktion verfügt:
public class ProductsController : Controller { public IActionResult Details(int id) { return ControllerContext.MyDisplayRouteInfo(id); } }MyDisplayRouteInfo wird von dem NuGet-Paket Rick.Docs.Samples.RouteInfo bereitgestellt und zeigt Routeninformationen an.
Das -Modell bindet den Wert von , um den -Parameter auf festzulegen. Weitere Informationen finden Sie unter "Modellbindung".
definiert als Standard-.
definiert als Standard-.
Das -Zeichen in definiert als optional.
- Standardmäßige und optionale Routenparameter müssen nicht im URL-Pfad vorhanden sein, damit es eine Übereinstimmung gibt. Eine detaillierte Beschreibung der Routenvorlagensyntax finden Sie unter Route Template Reference.
Es besteht eine Übereinstimmung mit dem URL-Pfad .
Die Routenwerte werden erzeugt.
Die Werte für und verwenden die Standardwerte. erzeugt keine Werte, da kein entsprechendes Segment im URL-Pfad vorhanden ist. stimmt nur überein, wenn eine - und -Aktion vorhanden ist:
public class HomeController : Controller
{
public IActionResult Index() { ... }
}
Mithilfe der vorherigen Controllerdefinition und Routenvorlage wird die Aktion für die folgenden URL-Pfade ausgeführt:
/Home/Index/17/Home/Index/Home/
Der URL-Pfad verwendet den Standardcontroller der Routenvorlage und die Standardaktion. Der URL-Pfad verwendet die -Standardaktion der Routenvorlage.
Mit der Hilfsmethode :
app.MapDefaultControllerRoute();
Replaces:
app.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
Important
Routing wird mithilfe von Middleware konfiguriert. So verwenden Sie Controller:
- Rufen Sie zum Zuordnen von über Attribute zugeordneten Controllern auf.
- Rufen Sie oder auf, um sowohl herkömmlich als auch über Attribute zugeordnete Controller zuzuordnen.
Apps müssen oder normalerweise nicht aufrufen. konfiguriert eine Middleware-Pipeline, die Middleware einbindet, indem sie mit anderen Komponenten interagiert und . Weitere Informationen finden Sie unter Routing in ASP.NET Core.
Herkömmliches Routing
Verwenden Sie herkömmliches Routing mit Controllern und Ansichten. Die Route lautet:
app.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
Der vorangehende Code ist ein Beispiel für eine herkömmliche Route. Das herkömmliche (auch konventionelle) Routing heißt so, weil dabei eine Konvention für URL-Pfade erstellt wird:
- Das erste Pfadsegment () entspricht dem Namen des Controllers.
- Das zweite Segment () entspricht dem Namen der Aktion.
- Das dritte Segment () wird für eine optionale verwendet. Die in macht es optional. ordnet einer Modellentität zu.
Bei Verwendung dieser -Route gilt der URL-Pfad:
- wird der -Aktion zugeordnet.
- wird zugeordnet, und das Modell bindet den -Parameter üblicherweise an 17.
Diese Zuordnung:
- Sie basiert nur auf den Controller- und Aktionsnamen.
- Sie basiert nicht auf Namespaces, Quelldateispeicherorten oder Methodenparametern.
Wenn Sie herkömmliches Routing mit der Standardroute verwenden, müssen Sie für jede Aktion kein neues URL-Muster erstellen. Für eine App mit Aktionen im CRUD-Stil bewirkt die Konsistenz für die URLs zwischen Controllern Folgendes:
- Sie vereinfacht den Code.
- Sie macht die Benutzeroberfläche vorhersagbarer.
Warning
Die Routenvorlage definiert die Option als optional. Aktionen können ohne die optionale ID ausgeführt werden, die als Teil der URL angegeben wird. Im Allgemeinen gilt Folgendes, wenn in der URL nicht angegeben wird:
- Modellbindungssätze auf .
- Es wurde keine Entität in der Datenbank gefunden, die mit übereinstimmt.
Mit dem Attributrouting können Sie präzise steuern, für welche Aktionen die ID erforderlich ist und für welche nicht. Gemäß der Konvention enthält die Dokumentation optionale Parameter wie , wenn sie bei korrekter Nutzung wahrscheinlich auftreten.
Für die meisten Apps sollte eine grundlegendes und beschreibendes Routingschema ausgewählt werden, um lesbare und aussagekräftige URLs zu erhalten. Die konventionelle Standardroute :
- Sie unterstützt ein grundlegendes und beschreibendes Routingschema.
- Sie stellt einen nützlichen Startpunkt für benutzeroberflächenbasierte Apps dar.
- Ist die einzige Routenvorlage, die für viele Apps mit Webbenutzeroberfläche benötigt wird. Für größere Apps mit Webbenutzeroberfläche genügt häufig eine andere Route, die Bereiche verwendet.
und :
- Diese weisen ihren Endpunkten automatisch einen Reihenfolgenwert zu, basierend auf der Reihenfolge, in der sie aufgerufen werden.
Endpunktrouting in ASP.NET Core:
- Weist kein Konzept für Routen auf.
- Bietet keine Bestellgarantien für die Ausführung der Erweiterbarkeit. Alle Endpunkte werden gleichzeitig verarbeitet.
Wenn Sie die Protokollierung aktivieren, erfahren Sie, wie die integrierten Routingimplementierungen (z.B. ) Zuordnungen für Anforderungen ermitteln.
Das Attributrouting wird weiter unten in diesem Dokument erläutert.
Mehrere herkömmliche Routen
Sie können mehrere herkömmliche Routen konfigurieren, indem Sie weitere Anrufe zu und hinzufügen. Wenn Sie diese Aufrufe hinzufügen, können Sie mehrere Konventionen definieren oder herkömmliche Routen hinzufügen, die einer bestimmten Aktion zugeordnet sind, z. B.:
app.MapControllerRoute(name: "blog",
pattern: "blog/{*article}",
defaults: new { controller = "Blog", action = "Article" });
app.MapControllerRoute(name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
Die -Route im vorherigen Code ist eine dedizierte herkömmliche Route. Es ist eine dedizierte herkömmliche Route, da:
- Sie verwendet herkömmliches Routing.
- Sie ist für eine bestimmte Aktion bestimmt.
Da die Routenvorlage nicht enthalten ist und als Parameter gilt:
- Sie können nur über die -Standardwerte verfügen.
- Diese Route wird immer der Aktion zugeordnet.
, und sind die einzigen URL-Pfade, die der Blogroute entsprechen.
Im vorherigen Beispiel:
- Die Route hat eine höhere Priorität für Übereinstimmungen als die andere Route, weil Sie sie zuerst hinzufügen.
- Es ist ein Beispiel für das Routing im Slug-Stil , bei dem es typisch ist, einen Artikelnamen als Teil der URL zu haben.
Warning
In ASP.NET Core funktioniert das Routing nicht:
- Ein Konzept namens Route definieren. fügt der Middlewarepipeline einen Routenabgleich hinzu. Diese -Middleware prüft die in der App definierten Endpunkte und wählt anhand der Anforderung die beste Endpunktübereinstimmung aus.
- Geben Sie Garantien für die Ausführungsreihenfolge von Erweiterungen wie oder an.
Referenzmaterial zum Routing finden Sie unter Routing.
Reihenfolge des herkömmlichen Routings
Herkömmliches Routing entspricht nur einer Kombination aus Aktion und Controller, die die App definiert. Dieser Ansatz vereinfacht Fälle, in denen herkömmliche Routen überlappen. Wenn Sie Routen mithilfe der Platzhalter hinzufügen, erhalten die Endpunkte automatisch einen Bestellwert basierend auf der Reihenfolge, in der Sie diese Methoden aufrufen. Übereinstimmungen aus einer Route, die weiter oben in der Liste angezeigt wird, haben eine höhere Priorität. Konventionelles Routing hängt von der Bestellung ab. Im Allgemeinen platzieren Sie Routen mit Bereichen früher, da sie spezifischer sind als Routen ohne einen Bereich. Speziell eingerichtete herkömmliche Routen mit universellen Routenparametern, wie z.B., können die Route überfordern. Eine gierige Route matcht URLs, die eigentlich von anderen Routen abgeglichen werden sollten. Fügen Sie die „gierigen“ Routen später in die Routingtabelle ein, um solche Übereinstimmungen zu verhindern.
Warning
Ein catch-all-Parameter kann aufgrund eines Fehlers beim Routing nicht ordnungsgemäß mit Routen übereinstimmen. Apps, die von diesem Fehler betroffen sind, weisen die folgenden Merkmale auf:
- Eine catch-all-Route, zum Beispiel
- Die catch-all-Route kann nicht mit Anforderungen abgeglichen werden, die abgeglichen werden sollen.
- Durch das Entfernen anderer Routen funktioniert die catch-all-Route.
Siehe GitHub Fehler 18677 und 16579 z. B. Fälle, die diesen Fehler treffen.
Ein Opt-In-Fix für diesen Fehler ist in .NET Core 3.1.301 oder höher SDK enthalten. Der folgende Code legt einen internen Switch fest, mit dem dieser Fehler behoben wird:
public static void Main(string[] args)
{
AppContext.SetSwitch("Microsoft.AspNetCore.Routing.UseCorrectCatchAllBehavior",
true);
CreateHostBuilder(args).Build().Run();
}
// Remaining code removed for brevity.
Klärung von mehrdeutigen Aktionen
Wenn zwei Endpunkte über Routing übereinstimmen, muss Routing einen der folgenden Schritte ausführen:
- Den besten Kandidaten auswählen
- Löst eine Ausnahme aus.
Beispiel:
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);
}
}
Der vorherige Controller definiert zwei Aktionen, die mit Folgendem übereinstimmen:
- Der URL-Pfad
- Routendaten
Dies ist ein typisches Muster für MVC-Controller:
- zeigt ein Formular zum Bearbeiten eines Produkts an.
- verarbeitet das bereitgestellte Formular.
Um die korrekte Route zu ermitteln:
- wird ausgewählt, wenn die Anforderung ein HTTP- ist.
- wird ausgewählt, wenn das HTTP-Verb etwas anderes ist. wird im Allgemeinen über aufgerufen.
Das () wird für das Routing bereitgestellt, sodass es basierend auf der HTTP-Methode der Anforderung eine Auswahl treffen kann. Das macht zu einer besseren Übereinstimmung als .
Es ist wichtig, die Rolle von Attributen wie zu verstehen. Ähnliche Attribute werden für andere HTTP-Verben definiert. Beim herkömmlichen Routing verwenden Aktionen häufig denselben Aktionsnamen, wenn sie Teil eines Anzeigeformulars oder eines Absendeformular-Workflows sind. Weitere Informationen finden Sie beispielsweise unter Untersuchen der beiden Edit-Aktionsmethoden.
Wenn das Routing den besten Kandidaten nicht auswählen kann, löst es einen Fehler aus und listet die mehreren übereinstimmenden Endpunkte auf.
Namen herkömmlicher Routen
Die Zeichenfolgen und in den folgenden Beispielen sind herkömmliche Routennamen:
app.MapControllerRoute(name: "blog",
pattern: "blog/{*article}",
defaults: new { controller = "Blog", action = "Article" });
app.MapControllerRoute(name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
Die Routennamen geben der Route einen logischen Namen. Die benannte Route kann bei der URL-Generierung verwendet werden. Durch das Verwenden einer benannten Route wird die URL-Erstellung erheblich vereinfacht, obwohl die Reihenfolge der Routen die URL-Generierung verkomplizieren sollte. Routennamen müssen anwendungsweit eindeutig sein.
Routennamen:
- Haben keine Auswirkungen auf den URL-Abgleich oder die Verarbeitung von Anforderungen
- Werden nur für die URL-Generierung verwendet
Das Routennamenkonzept wird im Routing als IEndpointNameMetadata dargestellt. Für die Begriffe Routenname und Endpunktname gilt Folgendes:
- Sind austauschbar.
- Welcher in der Dokumentation und im Code verwendet wird, hängt von der beschriebenen API ab.
Attribut-Routing für -APIs
-APIs sollten das Attributrouting verwenden, um die Funktionalität der App als eine Gruppe von Ressourcen zu modellieren, bei denen Vorgänge durch HTTP-Verben dargestellt werden.
Beim Attributrouting werden Aktionen mithilfe von Attributen direkt Routenvorlagen zugeordnet. Der folgende Code ist typisch für eine -API und wird im nächsten Beispiel verwendet:
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllers();
var app = builder.Build();
app.UseHttpsRedirection();
app.UseAuthorization();
app.MapControllers();
app.Run();
Im vorherigen Code rufen Sie auf, um Attribut-geroutete Controller zuzuordnen.
Im folgenden Beispiel:
- entspricht einer Gruppe von URLs, ähnlich wie die herkömmliche Standardroute .
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);
}
}
Die Aktion wird für jeden der URL-Pfade , , , oder ausgeführt.
In diesem Beispiel wird ein wichtiger Unterschied beim Programmieren zwischen dem Attributrouting und dem herkömmlichen Routing hervorgehoben. Attributrouting erfordert mehr Eingaben, um eine Route anzugeben. Die herkömmliche Standardroute handhabt Routen prägnanter. Attributrouting ermöglicht jedoch (und erfordert auch) die präzise Kontrolle der Routenvorlagen, die für die einzelnen Aktionen gelten.
Beim Attributrouting haben die Namen des Controllers und der Aktion keinen Einfluss darauf, welche Aktion übereinstimmt, es sei denn, es wird die Tokenersetzung verwendet. Im folgenden Beispiel werden dieselben URLs wie im vorherigen Beispiel verwendet:
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);
}
}
Der folgende Code verwendet die Tokenersetzung für und :
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();
}
}
Der folgende Code wendet auf den Controller an:
[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();
}
}
Im vorangehenden Code müssen die -Methodenvorlagen den Routenvorlagen oder voranstellen. Routenvorlagen, die auf eine Aktion angewendet werden, die mit einem oder beginnen, können nicht mit Routenvorlagen kombiniert werden, die auf den Controller angewendet werden.
Informationen zur Auswahl von Routenvorlagen finden Sie unter Priorität der Routenvorlage.
Reservierte Routingnamen
Die folgenden Schlüsselwörter sind reservierte Routenparameternamen, wenn Sie Controller oder Seiten verwenden:
actionareacontrollerhandlerpage
Die Verwendung von als Routenparameter mit Attributrouting ist ein häufiger Fehler. Diese Auswahl führt zu inkonsistenten und verwirrenden Verhaltensweisen bei der URL-Generierung.
public class MyDemo2Controller : Controller
{
[Route("/articles/{page}")]
public IActionResult ListArticles(int page)
{
return ControllerContext.MyDisplayRouteInfo(page);
}
}
Die URL-Generierung verwendet diese speziellen Parameternamen, um zu bestimmen, ob ein URL-Generierungsvorgang auf eine Seite oder einen Controller verweist.
Die folgenden Schlüsselwörter sind im Kontext einer -Ansicht oder einer -Seite reserviert:
pageusingnamespaceinjectsectioninheritsmodeladdTagHelperremoveTagHelper
Verwenden Sie diese Schlüsselwörter nicht für Verknüpfungsgenerationen, modellgebundene Parameter oder Eigenschaften der obersten Ebene.
HTTP-Verbvorlagen
ASP.NET Core enthält die folgenden HTTP-Verbvorlagen:
- [HttpGet]
- [HttpPost]
- [HttpPut]
- [HttpDelete]
- [HttpHead]
- [HttpPatch]
Routenvorlagen
ASP.NET Core enthält die folgenden Routenvorlagen:
- Alle HTTP-Verbvorlagen sind Routenvorlagen.
- [Route]
Attribut-Routing mit HTTP-Verb-Attributen
Betrachten Sie den folgenden 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);
}
}
Im vorhergehenden Code:
- Jede Aktion enthält das -Attribut, das nur den Abgleich mit HTTP GET-Anforderungen einschränkt.
- Die Aktion umfasst die Vorlage, sodass sie an die Vorlage auf dem Controller angehängt wird. Die Vorlage der Methode lautet . Daher stimmt diese Aktion nur mit GET-Anforderungen für das Formular , , usw. überein.
[HttpGet("{id}")] // GET /api/test2/xyz public IActionResult GetProduct(string id) { return ControllerContext.MyDisplayRouteInfo(id); } - Die -Aktion enthält die -Vorlage. Der -Teil der Vorlage beschränkt die -Routenwerte auf Zeichenfolgen, die in eine ganze Zahl konvertiert werden können. Eine GET-Anforderung an :
- Sie entspricht dieser Aktion nicht.
- Sie gibt den Fehler 404 Nicht gefunden zurück.
[HttpGet("int/{id:int}")] // GET /api/test2/int/3 public IActionResult GetIntProduct(int id) { return ControllerContext.MyDisplayRouteInfo(id); }
- Die -Aktion enthält in der Vorlage, beschränkt aber nicht auf die Werte, die in eine ganze Zahl konvertiert werden können. Eine GET-Anforderung an :
- Sie entspricht dieser Route.
- Die Modellbindung kann nicht in eine ganze Zahl konvertieren. Der -Parameter der Methode ist eine ganze Zahl.
- Sie gibt 400 Ungültige Anforderung zurück, da die Modellbindung nicht in eine ganze Zahl konvertieren konnte.
[HttpGet("int2/{id}")] // GET /api/test2/int2/3 public IActionResult GetInt2Product(int id) { return ControllerContext.MyDisplayRouteInfo(id); }
Beim Attributrouting können -Attribute wie , und verwendet werden. Alle HTTP-Verb-Attribute akzeptieren eine Routenvorlage. Im folgenden Beispiel werden zwei Aktionen gezeigt, die derselben Routenvorlage zugeordnet sind:
[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);
}
}
Für die Verwendung des URL-Pfads gilt:
- Die -Aktion wird ausgeführt, wenn das HTTP-Verb ist.
- Die -Aktion wird ausgeführt, wenn das HTTP-Verb ist.
Beim Erstellen einer API ist es selten, dass Sie für eine Aktionsmethode verwenden müssen, da die Aktion alle HTTP-Methoden akzeptiert. Verwenden Sie das spezifischere HTTP-Verb-Attribut , um präziser zu sein, was Ihre API unterstützt. -API-Clients sollten wissen, welche Pfade und HTTP-Verben bestimmten logischen Operationen entsprechen.
-APIs sollten das Attributrouting verwenden, um die Funktionalität der App als eine Gruppe von Ressourcen zu modellieren, bei denen Vorgänge durch HTTP-Verben dargestellt werden. Dieser Entwurf bedeutet, dass viele Vorgänge wie GET und POST in derselben logischen Ressource dieselbe URL verwenden. Das Attributrouting stellt die Steuerungsebene bereit, die zum sorgfältigen Entwerfen des öffentlichen Endpunktlayouts einer API erforderlich ist.
Da eine Attributroute für eine bestimmte Aktion gilt, ist es einfach, Parameter als Teil der Routenvorlagendefinition erforderlich festzulegen. Im folgenden Beispiel ist als Teil des URL-Pfads erforderlich.
[ApiController]
public class Products2ApiController : ControllerBase
{
[HttpGet("/products2/{id}", Name = "Products_List")]
public IActionResult GetProduct(int id)
{
return ControllerContext.MyDisplayRouteInfo(id);
}
}
Für die -Aktion gilt:
- Sie wird mit einem URL-Pfad wie ausgeführt.
- Sie wird nicht mit einem URL-Pfad wie ausgeführt.
Das [Consumes]-Attribut ermöglicht es einer Aktion, die unterstützten Anforderungsinhaltstypen einzuschränken. Weitere Informationen finden Sie unter Definieren unterstützter Anforderungsinhaltstypen mit dem [Consumes]-Attribut.
Eine vollständige Beschreibung und Routenvorlagen und dazugehörige Optionen finden Sie unter Routing in ASP.NET Core.
Weitere Informationen zu finden Sie unter ApiController-Attribut.
Routenname
Im folgenden Code wird ein Routenname von definiert:
[ApiController]
public class Products2ApiController : ControllerBase
{
[HttpGet("/products2/{id}", Name = "Products_List")]
public IActionResult GetProduct(int id)
{
return ControllerContext.MyDisplayRouteInfo(id);
}
}
Verwenden Sie Routennamen, um eine URL basierend auf einer bestimmten Route zu generieren. Routennamen:
- Sie haben keine Auswirkungen auf das URL-Abgleichsverhalten des Routings.
- Sie werden nur für die URL-Generierung verwendet.
Routennamen müssen anwendungsweit eindeutig sein.
Vergleichen Sie den vorherigen Code mit der herkömmlichen Standardroute, die den -Parameter als optional definiert (). APIs präzise angeben zu können, hat Vorteile, z. B. können und an unterschiedliche Aktionen gesendet werden.
Kombinieren von Attributrouten
Um das Attributrouting weniger wiederholt zu gestalten, kombinieren Sie Routenattribute auf dem Controller mit Routenattributen für die einzelnen Aktionen. Die auf dem Controller definierten Routenvorlagen werden den Routenvorlagen der Aktionen vorangestellt. Wenn Sie ein Routenattribute auf dem Controller platzieren, verwenden alle Aktionen des Controllers das Attributrouting.
[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);
}
}
Im vorherigen Beispiel:
- Der URL-Pfad kann mit übereinstimmen.
- Der URL-Pfad kann mit übereinstimmen.
Beide Aktionen gleichen nur „HTTP “ ab, weil sie mit dem -Attribut markiert sind.
Routenvorlagen, die Sie auf eine Aktion anwenden und die mit einem bestimmten Muster beginnen oder leer sind, werden nicht mit den Routenvorlagen kombiniert, die Sie auf den Controller anwenden. Im folgenden Beispiel werden mehrere URL-Pfade zugeordnet, die der Standardroute ähneln.
[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 der folgenden Tabelle werden die -Attribute im vorherigen Code erläutert:
| Attribute | Kann mit kombiniert werden | Definiert die Routenvorlage |
|---|---|---|
[Route("")] |
Yes | "Home" |
[Route("Index")] |
Yes | "Home/Index" |
[Route("/")] |
No | "" |
[Route("About")] |
Yes | "Home/About" |
Reihenfolge der Attributrouten
Beim Routing wird eine Struktur erstellt, die alle Endpunkte gleichzeitig abgleicht:
- Die Routeneinträge verhalten sich so, als ob sie in einer idealen Reihenfolge platziert werden.
- Die spezifischsten Routen können also vor den allgemeineren ausgeführt werden.
Eine Attributroute wie ist beispielsweise spezifischer als eine Attributroute wie . Die -Route hat standardmäßig eine höhere Priorität, da sie spezifischer ist. Mit herkömmlichem Routing ist der Entwickler für die Platzierung von Routen in der gewünschten Reihenfolge verantwortlich.
Attributrouten können die Reihenfolge mit der Eigenschaft konfigurieren. Alle vom Framework bereitgestellten Routenattribute enthalten . Routen werden entsprechend einer aufsteigenden Reihenfolge der -Eigenschaft verarbeitet. Die Standardreihenfolge ist . Das Festlegen einer Route mit wird vor Routen ausgeführt, die keine Reihenfolge vorgeben. Das Festlegen einer Route mit wird nach der Standardreihenfolge der Routen ausgeführt.
Vermeiden Sie eine Abhängigkeit von . Wenn der URL-Raum einer App explizite Reihenfolgenwerte erfordert, um korrekt weiterzuleiten, ist es wahrscheinlich auch für Clients verwirrend. Beim Attributrouting wird im Allgemeinen mithilfe der URL-Zuordnung die richtige Route ausgewählt. Wenn die für die URL-Generierung verwendete Standardreihenfolge nicht funktioniert, ist es meist einfacher, Routennamen als Außerkraftsetzung zu verwenden, statt die -Eigenschaft anzuwenden.
Betrachten Sie die folgenden beiden Controller, die beide den Routenabgleich definieren:
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);
}
}
Beim Anfordern mithilfe des vorherigen Codes wird eine Ausnahme ausgelöst, die der folgenden ähnelt:
AmbiguousMatchException: The request matched multiple endpoints. Matches:
WebMvcRouting.Controllers.HomeController.Index
WebMvcRouting.Controllers.MyDemoController.MyIndex
Das Hinzufügen von zu einem der Routenattribute löst die Mehrdeutigkeit auf:
[Route("")]
[Route("Home", Order = 2)]
[Route("Home/MyIndex")]
public IActionResult MyIndex()
{
return ControllerContext.MyDisplayRouteInfo();
}
Mithilfe des vorherigen Codes führt den -Endpunkt aus. Um zu zu gelangen, fordern Sie . Note:
- Der vorangehende Code ist ein Beispiel für ein schlechtes Routingdesign. Es wird die Eigenschaft veranschaulicht.
- Die Eigenschaft löst nur die Mehrdeutigkeit auf. Diese Vorlage kann nicht übereinstimmen. Es ist besser, die Vorlage zu entfernen.
Informationen zur Routenreihenfolge mit "Pages" finden Sie unter "Pages"-Routen- und App-Konventionen: Routenreihenfolge.
In einigen Fällen wird ein HTTP 500-Fehler mit mehrdeutigen Routen zurückgegeben. Verwenden Sie die Protokollierung, um zu ermitteln, welche Endpunkte die verursacht haben.
Ersetzen von Token in Routenvorlagen ([controller], [action], [area])
Aus Gründen der Einfachheit unterstützen Attributrouten die Tokenersetzung, indem ein Token in eckige Klammern [ ] eingeschlossen wird. Die Token , und werden durch die Werte des Aktionsnamens, des Bereichsnamens und des Controllernamens aus der Aktion ersetzt, in der Sie die Route definieren:
[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);
}
}
Im vorhergehenden Code:
[HttpGet]
public IActionResult List()
{
return ControllerContext.MyDisplayRouteInfo();
}
- Stimmt mit überein
[HttpGet("{id}")]
public IActionResult Edit(int id)
{
return ControllerContext.MyDisplayRouteInfo(id);
}
- Stimmt mit überein
Die Token-Ersetzung erfolgt als letzter Schritt beim Erstellen der Attributrouten. Der folgende Code verhält sich genauso wie der aus dem obigen Beispiel:
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);
}
}
Wenn Sie dies in einer anderen Sprache als Englisch lesen, informieren Sie uns in diesem GitHub Diskussionsproblem wenn Sie die Codekommentare in Ihrer Muttersprache anzeigen möchten.
Sie können Attributrouten auch mit Vererbung kombinieren. Diese Kombination ist leistungsfähig, wenn Sie die Tokenersetzung verwenden. Tokenersetzung gilt auch für Routennamen, die durch Attributrouten definiert werden. generiert für jede Aktion einen eindeutigen Routennamen.
[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);
}
}
Damit das Trennzeichen oder der Tokenersetzungs-Literalzeichenfolge bei einem Abgleich gefunden wird, muss es doppelt vorhanden sein ( oder ), was einem Escapezeichen entspricht.
Verwenden Sie einen Parametertransformator, um die Tokenersetzung anzupassen.
Sie können die Tokenersetzung mithilfe eines Parametertransformors anpassen. Ein Parametertransformator implementiert und wandelt den Wert der Parameter um. Beispielsweise ändert ein benutzerdefinierter -Parametertransformator den Routenwert in :
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();
}
}
Die ist eine Anwendungsmodellkonvention, die Folgendes ausführt:
- Wenden Sie einen Parametertransformator auf alle Attributrouten in einer Anwendung an.
- Passt die Attributroutentokenwerte an, während sie ersetzt werden.
public class SubscriptionManagementController : Controller
{
[HttpGet("[controller]/[action]")]
public IActionResult ListAll()
{
return ControllerContext.MyDisplayRouteInfo();
}
}
Die vorherige -Method stimmt mit überein.
Die wird als Option registriert:
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();
Die Definition von "Slug" finden Sie in der MDN-Webdokumentation.
Warning
Übergeben Sie ein Timeout, wenn Sie zum Verarbeiten nicht vertrauenswürdiger Eingaben verwenden. Ein böswilliger Benutzer kann Eingaben für angeben, um einen Denial-of-Service-Angriff durchzuführen. ASP.NET Core Framework-APIs, die RegularExpressions verwenden, übergeben ein Timeout.
Mehrere Attribut-Routen
Attributrouting unterstützt das Definieren mehrerer Routen, die zu derselben Aktion führen. Dies wird am häufigsten beim Imitieren des Verhaltens der herkömmlichen Standardroute verwendet. Im folgenden Beispiel wird dies gezeigt:
[Route("[controller]")]
public class Products13Controller : Controller
{
[Route("")] // Matches 'Products13'
[Route("Index")] // Matches 'Products13/Index'
public IActionResult Index()
{
return ControllerContext.MyDisplayRouteInfo();
}
Wenn mehrere Routenattribute auf dem Controller platziert werden, bedeutet dies, dass jedes Attribut mit den Routenattributen der Aktionsmethoden kombiniert wird:
[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 Routeneinschränkungen von HTTP-Verben implementieren .
Wenn mehrere Routenattribute, die implementieren, einer Aktion zugeordnet werden, geschieht Folgendes:
- Jede Aktionseinschränkung wird mit der Routenvorlage kombiniert, die auf den Controller angewendet wird.
[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();
}
}
Die Verwendung mehrerer Routen für Aktionen mag zwar nützlich und leistungsfähig erscheinen, es ist jedoch besser, den URL-Bereich Ihrer App einfach und klar definiert zu halten. Verwenden Sie nur mehrere Routen für Aktionen, wenn dies notwendig ist, z. B. um vorhandene Clients zu unterstützen.
Angeben von optionalen Attributroutenparametern, Standardwerten und Einschränkungen
Attributrouten unterstützen dieselbe Inline-Syntax wie herkömmliche Routen, um optionale Parameter, Standardwerte und Einschränkungen anzugeben.
public class Products14Controller : Controller
{
[HttpPost("product14/{id:int}")]
public IActionResult ShowProduct(int id)
{
return ControllerContext.MyDisplayRouteInfo(id);
}
}
wendet im vorherigen Code eine Routeneinschränkung an. Die -Aktion wird nur mit URL-Pfaden wie abgeglichen. Der Routenvorlagenteil schränkt dieses Segment auf ganze Zahlen ein.
Eine detaillierte Beschreibung der Routenvorlagensyntax finden Sie unter Route Template Reference.
Benutzerdefinierte Routenattribute unter Verwendung des IRouteTemplateProvider
Alle Routenattribute implementieren . Die ASP.NET Core Laufzeit:
- Sie sucht nach Attributen für Controllerklassen und Aktionsmethoden, wenn die App gestartet wird.
- Sie verwendet die Attribute, die implementieren, um die erste Gruppe der Routen zu erstellen.
Implementieren Sie , um benutzerdefinierte Routenattribute zu definieren. Jeder lässt Sie eine einzelne Route mit einer benutzerdefinierten Routenvorlage, Reihenfolge und einem benutzerdefinierten Namen definieren:
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();
}
}
Die vorhergehende -Methode gibt zurück.
Anpassen von Attributrouten mithilfe des Anwendungsmodells
Das Anwendungsmodell:
- Ist ein Objektmodell, das beim Start in erstellt wurde
- Enthält alle Metadaten, die von ASP.NET Core zum Weiterleiten und Ausführen der Aktionen in einer App verwendet werden.
Das Anwendungsmodell enthält alle Daten, die aus Routenattributen erfasst wurden. Die Daten aus Routenattributen werden von der -Implementierung bereitgestellt. Conventions:
- Können geschrieben werden, um das Anwendungsmodell zu ändern und das Routingverhalten anzupassen
- Werden beim Starten der App gelesen
In diesem Abschnitt wird ein grundlegendes Beispiel zum Anpassen des Routings mithilfe des Anwendungsmodells gezeigt. Der folgende Code sorgt dafür, dass die Routen in etwa mit der Ordnerstruktur des Projekts übereinstimmen.
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()
};
}
}
}
Der folgende Code verhindert, dass die -Konvention auf Controller angewendet wird, die über Attribute zugeordnet werden:
public void Apply(ControllerModel controller)
{
var hasRouteAttributes = controller.Selectors.Any(selector =>
selector.AttributeRouteModel != null);
if (hasRouteAttributes)
{
return;
}
Der folgende Controller verwendet beispielsweise nicht:
[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}");
}
}
Die -Methode:
- Wird nicht ausgeführt, wenn der Controller mit einem Attribut weitergeleitet wird
- Legt die Controllervorlage basierend auf dem fest, während die Basis entfernt wird.
Die kann in angewendet werden:
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();
Betrachten Sie beispielsweise den folgenden 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}");
}
}
}
Im vorhergehenden Code:
- Die Basis ist .
- Der vollständige Name des vorherigen Controllers lautet .
- Die legt die Controllervorlage auf fest.
Die kann auch als Attribut auf einen Controller angewendet werden:
[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}");
}
}
Gemischtes Routing: Attributrouting vs. herkömmliches Routing
ASP.NET Core Apps können die Verwendung herkömmlicher Routing- und Attributroutings kombinieren. In der Regel verwenden Sie herkömmliche Routen für Controller, die HTML-Seiten an Browser bereitstellen, und das Attributrouting für Controller, die APIs bereitstellen .
Aktionen werden entweder herkömmlich oder über Attribute zugeordnet, Wenn Sie eine Route auf dem Controller oder der Aktion definieren, wird sie zur Attributroute. Sie können nicht über die herkömmlichen Routen auf Aktionen zugreifen, die Attributrouten definieren, und umgekehrt. Jedes-Route-Attribut auf dem Controller bewirkt, dass alle Aktionen in dem Controller-Attribut geroutet werden.
Attributrouting und herkömmliches Routing verwenden dieselbe Routing-Engine.
Routing mit Sonderzeichen
Ein Routing mit Sonderzeichen kann zu unerwarteten Ergebnissen führen. Stellen Sie sich z. B. einen Controller mit der folgenden Aktionsmethode vor:
[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;
}
Wenn die folgenden codierten Werte enthält, können unerwartete Ergebnisse auftreten:
| ASCII | Encoded |
|---|---|
/ |
%2F |
|
+ |
Routenparameter sind nicht immer URL-decodiert. Dieses Problem wird möglicherweise in Zukunft behoben. Weitere Informationen finden Sie in diesem GitHub Issue;
URL-Generierungs- und Umgebungswerte
Apps können Routing-URL-Generierungsfunktionen verwenden, um URLs zu Aktionen zu erstellen. Durch das Generieren von URLs müssen URLs nicht mehr hartcodiert werden, sodass der Code robuster und leichter verwaltbar wird. Dieser Abschnitt konzentriert sich auf die von MVC bereitgestellte URL-Generierung und befasst sich nur kurz mit der Funktionsweise. Eine detaillierte Beschreibung der URL-Generierung finden Sie unter Routing in ASP.NET Core.
Die -Schnittstelle ist das zugrunde liegende Element der Infrastruktur zwischen MVC und dem Routing für die URL-Generierung. Eine Instanz von ist über die -Eigenschaft in Controllern, Ansichten und Ansichtskomponenten verfügbar.
Im folgenden Beispiel wird die -Schnittstelle durch die -Eigenschaft verwendet, um eine URL zu einer anderen Aktion zu generieren.
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();
}
}
Wenn die App die herkömmliche Standardroute verwendet, ist der Wert der Variablen die URL-Pfadzeichenfolge . Routing erstellt diesen URL-Pfad durch Kombinieren:
- Die Routenwerte aus der aktuellen Anforderung, die als Umgebungswerte bezeichnet werden
- Die an übergebenen Werte und das Einfügen dieser Werte in die Routenvorlage:
ambient values: { controller = "UrlGeneration", action = "Source" }
values passed to Url.Action: { controller = "UrlGeneration", action = "Destination" }
route template: {controller}/{action}/{id?}
result: /UrlGeneration/Destination
Der Wert eines jeden Routenparameters wird in der Routenvorlage durch die entsprechenden Namen mit den Werten und Umgebungswerten ersetzt. Ein Routenparameter, der keinen Wert aufweist, kann Folgendes tun:
- Einen Standardwert verwenden (falls vorhanden)
- Übersprungen werden (falls möglich). Als Beispiel kann die aus der Routenvorlage genannt werden.
Die URL-Generierung schlägt fehl, wenn ein erforderlicher Routenparameter keinen entsprechenden Wert besitzt. Wenn die URL-Generierung für eine Route fehlschlägt, wird die nächste Route ausprobiert, bis alle Routen getestet wurden oder eine Übereinstimmung gefunden wurde.
Im vorherigen Beispiel wird von herkömmlichen Routing ausgegangen. Die URL-Generierung funktioniert ähnlich wie das Attributrouting, obwohl sich die Konzepte unterscheiden. Für das herkömmliche Routing gilt Folgendes:
- Die Routenwerte werden verwendet, um eine Vorlage zu erweitern.
- Die Routenwerte für und werden in der Regel in dieser Vorlage angezeigt. Dies funktioniert, da die vom Routing abgeglichenen URLs einer Konvention entsprechen.
Im folgenden Beispiel wird Attributrouting verwendet:
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();
}
}
Die -Aktion im vorherigen Code generiert .
LinkGenerator wurde in ASP.NET Core 3.0 als Alternative zu IUrlHelper hinzugefügt. bietet ähnliche, aber flexiblere Funktionen. Jede Methode für verfügt ebenfalls über eine entsprechende Gruppe von Methoden für .
Generieren von URLs nach Aktionsnamen
Url.Action, LinkGenerator.GetPathByAction und alle zugehörigen Überladungen sind alle dafür konzipiert, den Zielendpunkt durch Angabe eines Controllernamens und eines Aktionsnamens zu erzeugen.
Bei Verwendung stellt die Laufzeit die aktuellen Routenwerte für und :
- Die Werte von und sind Teil sowohl von Umgebungswerten als auch von Werten. Die Methode verwendet immer die aktuellen Werte von und und generiert einen URL-Pfad, der zur aktuellen Aktion weiterleitet.
Beim Routing wird versucht, mit den Werten in den Umgebungswerten Informationen zu ergänzen, die beim Generieren einer URL nicht angegeben wurden. Betrachten Sie eine Route wie mit Umgebungswerten :
- Das Routing verfügt über genügend Informationen, um eine URL ohne zusätzliche Werte zu generieren.
- Das Routing verfügt über genügend Informationen, da alle Routenparameter über einen Wert verfügen.
Wenn der Wert hinzugefügt wird, geschieht Folgendes:
- Der -Wert wird ignoriert.
- Der generierte URL-Pfad ist .
Warnung: URL-Pfade sind hierarchisch. Wenn der Wert im vorherigen Beispiel hinzugefügt wird, geschieht Folgendes:
- Beide der Werte werden ignoriert.
- Es gibt keinen Wert mehr, und die URL-Generierung schlägt fehl.
- Sie müssen die gewünschten Werte angeben und eine URL generieren.
Sie können davon ausgehen, dass dieses Problem mit der Standardroute auftritt. Dieses Problem tritt in der Praxis selten auf, da immer explizit einen - und -Wert angibt.
Mehrere Überladungen von Url.Action nehmen ein Routenwerteobjekt, um Werte für andere Routenparameter als und bereitzustellen. Das Routenwertobjekt wird häufig mit verwendet. Beispiel: . Für das Routenwertobjekt gilt Folgendes:
- Es ist üblicherweise ein Objekt von anonymem Typ.
- Es kann ein oder POCO sein.
Alle zusätzlichen Routenwerte, die nicht mit den Routenparametern übereinstimmen, gehen in die Abfragezeichenfolge.
public IActionResult Index()
{
var url = Url.Action("Buy", "Products", new { id = 17, color = "red" });
return Content(url!);
}
Der vorangehende Code generiert .
Der folgende Code generiert eine absolute URL:
public IActionResult Index2()
{
var url = Url.Action("Buy", "Products", new { id = 17 }, protocol: Request.Scheme);
// Returns https://localhost:5001/Products/Buy/17
return Content(url!);
}
Verwenden Sie zum Erstellen einer absoluten URL eine der folgenden Optionen:
- Eine Überladung, die ein akzeptiert. Beispiel: der vorangehende Code.
- LinkGenerator.GetUriByAction, der standardmäßig absolute URIs generiert
Generieren von URLs nach Route
Im vorangehenden Code wurde das Generieren einer URL durch das Übergeben des Controller- und Aktionsnamens veranschaulicht. stellt außerdem die Url.RouteUrl-Methodengruppe bereit. Diese Methoden ähneln Url.Action, kopieren jedoch nicht die aktuellen Werte und in die Routenwerte. Die häufigste Verwendung von :
- Sie gibt einen Routennamen an, um die URL zu generieren.
- Sie gibt im Allgemeinen keinen Controller- oder Aktionsnamen an.
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();
}
Die folgende -Datei generiert einen HTML-Link zu :
<h1>Test Links</h1>
<ul>
<li><a href="@Url.RouteUrl("Destination_Route")">Test Destination_Route</a></li>
</ul>
Generieren von URLs in HTML und
stellt die -Methoden Html.BeginForm und Html.ActionLink bereit, um jeweils - und -Elemente zu generieren. Diese Methoden verwenden die Url.Action-Methode, um eine URL zu generieren, und akzeptieren ähnliche Argumente. Die -Begleiter für sind und , die ähnliche Funktionen aufweisen.
Taghilfsprogramme generieren URLs mit den Taghilfsprogrammen und . Beide verwenden für ihre Implementierung. Weitere Informationen finden Sie unter Tag Helpers in Formularen.
Innerhalb von Ansichten ist die Eigenschaft für die Ad-hoc-URL-Generierung verfügbar, die nicht von den vorhergehenden Methoden abgedeckt wird.
URL-Generierung in Aktionsergebnissen
In den vorherigen Beispielen wird gezeigt, wie sie in einem Controller verwendet werden . Die häufigste Verwendung in einem Controller besteht darin, eine URL als Teil eines Aktionsergebnisses zu generieren.
Die Basisklassen und stellen Hilfsmethoden für Aktionsergebnisse bereit, die auf eine andere Aktionen verweisen. Eine typische Verwendung besteht darin, nach dem Akzeptieren einer Benutzereingabe weiterzuleiten:
[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);
}
Die Factorymethoden der Aktionsergebnisse (wie und ) folgen einem ähnlichen Muster wie die Methoden für .
Sonderfall für dedizierte herkömmliche Routen
Beim herkömmlichen Routing können Sie eine bestimmte Art von Routendefinition verwenden, die als dedizierte herkömmliche Route bezeichnet wird. Die Route namens im folgenden Beispiel ist eine dedizierte herkömmliche Route.
app.MapControllerRoute(name: "blog",
pattern: "blog/{*article}",
defaults: new { controller = "Blog", action = "Article" });
app.MapControllerRoute(name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
Mithilfe der vorherigen Routendefinitionen wird der URL-Pfad mithilfe der Route generiert, aber warum? Sie können vermuten, dass die Routenwerte ausreichen, um eine URL mithilfe von , und das Ergebnis wäre .
Dedizierte herkömmliche Routen nutzen ein spezielles Verhalten von Standardwerten, die keinen entsprechenden Routenparameter besitzen, der verhindert, dass die Route bei der URL-Generierung „zu gierig“ wird. In diesem Fall sind die Standardwerte , und weder noch werden als Routenparameter verwendet. Wenn das Routing die URL-Generierung ausführt, müssen die angegebenen Werte mit den Standardwerten übereinstimmen. Die URL-Generierung mithilfe von schlägt fehl, da die Werte nicht mit übereinstimmen. Routing versucht dann, auf zurückzugreifen, was erfolgreich ist.
Areas
Bereiche sind ein Feature von MVC, das zur Organisation verwandter Funktionen in eine separate Einheit verwendet wird.
- Routing-Namespace für Controlleraktionen
- Ordnerstruktur für Ansichten
Mithilfe von Bereichen kann eine App mehrere Controller mit demselben Namen haben – solange sie verschiedene Bereiche haben. Mithilfe von Bereichen wird außerdem eine Hierarchie erstellt, damit das Routing durch Hinzufügen eines anderen Routenparameters ausgeführt werden kann: zu und . In diesem Abschnitt wird erläutert, wie Routing mit Bereichen interagiert. Weitere Informationen zur Verwendung von Bereichen mit Ansichten finden Sie unter Bereiche.
Im folgenden Beispiel wird MVC konfiguriert, sodass es die herkömmliche Standardroute und eine -Route für einen namens verwendet:
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();
Im vorherigen Code wird aufgerufen, um die zu erstellen. Der zweite Parameter, , ist der Bereichsname.
Beim Abgleich mit einem URL-Pfad wie generiert die -Route die Routenwerte . Der Routenwert stammt aus einem Standardwert für . Die erstellte Route entspricht dem folgenden Code:
app.MapControllerRoute("blog_route", "Manage/{controller}/{action}/{id?}",
defaults: new { area = "Blog" }, constraints: new { area = "Blog" });
app.MapControllerRoute("default_route", "{controller}/{action}/{id?}");
erstellt eine Route mit einem Standardwert und einer Einschränkung für die Verwendung des angegebenen Bereichsnamens in diesem Fall . Der Standardwert stellt sicher, dass die Route immer ein gültiges Ergebnis liefert, und die Einschränkung verlangt einen definierten Wert für die URL-Generierung.
Beim herkömmlichen Routing ist die Reihenfolge wichtig. Platzieren Sie im Allgemeinen Routen mit Gebieten früher, da sie spezifischer sind als Routen ohne Gebiet.
Die Routenwerte im vorherigen Beispiel werden der folgenden Aktion zugeordnet:
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}");
}
}
}
Das Attribut [Area] kennzeichnet einen Controller als Teil eines Bereichs. Dieser Controller befindet sich im -Bereich. Controller ohne Attribut sind keine Mitglieder eines Bereichs und stimmen nicht überein, wenn der Routenwert durch Routing bereitgestellt wird. Im folgenden Beispiel kann nur der erste aufgelistete Controller die Routenwerte abgleichen.
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}");
}
}
}
Zur Vollständigkeit wird der Namespace der einzelnen Controller hier angezeigt. Wenn die vorherigen Controller denselben Namespace verwenden, wird ein Compilerfehler generiert. Klassennamespaces haben keine Auswirkungen auf das MVC-Routing.
Die ersten beiden Controller gehören zu Bereichen und werden können nur abgleichen, wenn ihr jeweiliger Bereichsname vom -Routenwert bereitgestellt wird. Der dritte Controller gehört keinem Bereich an und kann nur abgleichen, wenn vom Routing kein Wert für bereitgestellt wird.
Im Hinblick auf das Erkennen keines Werts hat die Abwesenheit des -Werts dieselben Auswirkungen, wie wenn der Wert für 0 (null) oder eine leere Zeichenfolge wäre.
Beim Ausführen einer Aktion innerhalb eines Bereichs ist der Routenwert für als Umgebungswert für das Routing verfügbar und kann für die URL-Generierung verwendet werden. Das bedeutet, dass Bereiche bei der URL-Generierung wie im folgenden Beispiel dargestellt standardmäßig beständig sind.
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);
}
}
}
Der folgende Code erzeugt eine URL zu :
public class HomeController : Controller
{
public IActionResult About()
{
var url = Url.Action("AddUser", "Users", new { Area = "Zebra" });
return Content($"URL: {url}");
}
Aktionsdefinition
Öffentliche Methoden in Controllern sind Aktionen, mit Ausnahme von Methoden mit NonAction-Attributen.
Beispielcode
- MyDisplayRouteInfo wird von dem NuGet-Paket Rick.Docs.Samples.RouteInfo bereitgestellt und zeigt Routeninformationen an.
- Anzeigen oder Herunterladen von Beispielcode (Vorgehensweise zum Herunterladen)
Fehlerdiagnostik
Legen Sie für eine ausführliche Routingdiagnoseausgabe auf fest. In der Umgebung, legen Sie die Protokollierungsstufe in fest.
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Debug",
"Microsoft.Hosting.Lifetime": "Information"
}
}
}
ASP.NET Core Controller verwenden die Routing-Middleware, um die URLs eingehender Anforderungen abzugleichen und ihnen Aktionen zuzuordnen. Routenvorlagen:
- Werden im Startcode oder in Attributen definiert
- Beschreiben, wie URL-Pfade mit Aktionen abgeglichen werden
- Werden verwendet, um URLs für Links zu generieren Die generierten Links werden in der Regel in Antworten zurückgegeben
Aktionen werden entweder konventionell geroutet oder attributbasiert geroutet. Eine Route auf dem Controller oder der Aktion zu platzieren macht sie attributgesteuert. Weitere Informationen finden Sie im Abschnitt Gemischtes Routing.
Dieses Dokument:
- Die Interaktionen zwischen MVC und Routing werden erläutert:
- Es wird erklärt, wie typische MVC-Apps die Routingfeatures nutzen.
- Deckt beides ab:
- Herkömmliches Routing, das in der Regel mit Controllern und Ansichten verwendet wird.
- Attribut-Routing verwendet mit -APIs. Wenn Sie sich hauptsächlich für das Routing für -APIs interessieren, wechseln Sie zum Abschnitt Attributrouting für -APIs.
- Informationen zum erweiterten Routing finden Sie unter Routing.
- Bezieht sich auf das in ASP.NET Core 3.0 hinzugefügte Standardroutingsystem, das als Endpunktrouting bezeichnet wird. Aus Kompatibilitätsgründen ist es möglich, Controller mit der vorherigen Version des Routings zu verwenden. Anweisungen finden Sie im Migrationsleitfaden 2.2–3.0. Verweisen Sie auf die Version 2.2 dieses Dokuments für Informationen zum Legacy-Routingsystem.
Einrichten einer herkömmlichen Route
weist normalerweise Code auf, der dem folgenden Beispiel ähnelt, wenn herkömmliches Routing verwendet wird:
app.UseEndpoints(endpoints =>
{
endpoints.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
});
Innerhalb des Aufrufs von wird verwendet, um eine einzelne Route zu erstellen. Die einzelne Route heißt -Route. Die meisten Apps mit Controllern und Ansichten verwenden eine Routenvorlage, die der -Route ähnelt. -APIs sollten Attribut-Routingverwenden.
Die Routenvorlage :
Entspricht einem URL-Pfad wie .
Extrahiert die Routenwerte durch Tokenisieren des Pfads. Die Extraktion von Routenwerten führt zu einer Übereinstimmung, wenn die App über einen Controller namens und eine -Aktion verfügt:
public class ProductsController : Controller { public IActionResult Details(int id) { return ControllerContext.MyDisplayRouteInfo(id); } }MyDisplayRouteInfo wird von dem NuGet-Paket Rick.Docs.Samples.RouteInfo bereitgestellt und zeigt Routeninformationen an.
Das -Modell bindet den Wert von , um den -Parameter auf festzulegen. Weitere Informationen finden Sie unter "Modellbindung".
definiert als Standard-.
definiert als Standard-.
Das -Zeichen in definiert als optional.
Standardmäßige und optionale Routenparameter müssen nicht im URL-Pfad vorhanden sein, damit es eine Übereinstimmung gibt. Eine detaillierte Beschreibung der Routenvorlagensyntax finden Sie unter Route Template Reference.
Es besteht eine Übereinstimmung mit dem URL-Pfad .
Die Routenwerte werden erzeugt.
Die Werte für und verwenden die Standardwerte. erzeugt keine Werte, da kein entsprechendes Segment im URL-Pfad vorhanden ist. stimmt nur überein, wenn eine - und -Aktion vorhanden ist:
public class HomeController : Controller
{
public IActionResult Index() { ... }
}
Mithilfe der vorherigen Controllerdefinition und Routenvorlage wird die Aktion für die folgenden URL-Pfade ausgeführt:
/Home/Index/17/Home/Index/Home/
Der URL-Pfad verwendet den Standardcontroller und die Aktion der Routenvorlage. Der URL-Pfad verwendet die -Standardaktion der Routenvorlage.
Mit der Hilfsmethode :
endpoints.MapDefaultControllerRoute();
Replaces:
endpoints.MapControllerRoute("default", "{controller=Home}/{action=Index}/{id?}");
Important
Routing wird mithilfe der Middleware konfiguriert. So verwenden Sie Controller:
- Rufen Sie in zum Zuordnen von über Attribute zugeordneten Controllern auf.
- Rufen Sie sowohl herkömmliche Routingcontroller als auch Attributroutencontroller auf oder ordnen Sie sie zu.
Herkömmliches Routing
Verwenden Sie herkömmliches Routing mit Controllern und Ansichten. Die Route lautet:
endpoints.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
Der vorangehende Code ist ein Beispiel für eine herkömmliche Route. Das herkömmliche (auch konventionelle) Routing heißt so, weil dabei eine Konvention für URL-Pfade erstellt wird:
- Das erste Pfadsegment () entspricht dem Namen des Controllers.
- Das zweite Segment () entspricht dem Namen der Aktion.
- Das dritte Segment () wird für eine optionale verwendet. Die in macht es optional. ordnet einer Modellentität zu.
Bei Verwendung dieser -Route gilt der URL-Pfad:
- wird der -Aktion zugeordnet.
- wird zugeordnet, und das Modell bindet den -Parameter üblicherweise an 17.
Diese Zuordnung:
- Sie basiert nur auf den Controller- und Aktionsnamen.
- Sie basiert nicht auf Namespaces, Quelldateispeicherorten oder Methodenparametern.
Wenn Sie herkömmliches Routing mit der Standardroute verwenden, müssen Sie für jede Aktion kein neues URL-Muster erstellen. Für eine App mit Aktionen im CRUD-Stil bewirkt die Konsistenz für die URLs zwischen Controllern Folgendes:
- Sie vereinfacht den Code.
- Sie macht die Benutzeroberfläche vorhersagbarer.
Warning
Die Routenvorlage definiert die Option als optional. Aktionen können ohne die optionale ID ausgeführt werden, die als Teil der URL angegeben wird. Im Allgemeinen gilt Folgendes, wenn in der URL nicht angegeben wird:
- Modellbindungssätze auf .
- Es wurde keine Entität in der Datenbank gefunden, die mit übereinstimmt.
Mit dem Attributrouting können Sie präzise steuern, für welche Aktionen die ID erforderlich ist und für welche nicht. Gemäß der Konvention enthält die Dokumentation optionale Parameter wie , wenn sie bei korrekter Nutzung wahrscheinlich auftreten.
Für die meisten Apps sollte eine grundlegendes und beschreibendes Routingschema ausgewählt werden, um lesbare und aussagekräftige URLs zu erhalten. Die konventionelle Standardroute :
- Sie unterstützt ein grundlegendes und beschreibendes Routingschema.
- Sie stellt einen nützlichen Startpunkt für benutzeroberflächenbasierte Apps dar.
- Ist die einzige Routenvorlage, die für viele Apps mit Webbenutzeroberfläche benötigt wird. Für größere Apps mit Webbenutzeroberfläche genügt häufig eine andere Route, die Bereiche verwendet.
und :
- Diese weisen ihren Endpunkten automatisch einen Reihenfolgenwert zu, basierend auf der Reihenfolge, in der sie aufgerufen werden.
Endpunktrouting in ASP.NET Core 3.0 oder höher:
- Weist kein Konzept für Routen auf.
- Bietet keine Bestellgarantien für die Ausführung der Erweiterbarkeit. Alle Endpunkte werden gleichzeitig verarbeitet.
Wenn Sie die Protokollierung aktivieren, erfahren Sie, wie die integrierten Routingimplementierungen (z.B. ) Zuordnungen für Anforderungen ermitteln.
Das Attributrouting wird weiter unten in diesem Dokument erläutert.
Mehrere herkömmliche Routen
Mehrere herkömmliche Routen können innerhalb von hinzugefügt werden, indem weitere Aufrufe zu und hinzugefügt werden. So können Sie mehrere Konventionen definieren oder herkömmlichen Routen hinzufügen, die einer bestimmten Aktion zugeordnet sind, z. B.:
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?}");
});
Die -Route im vorherigen Code ist eine dedizierte herkömmliche Route. Es ist eine dedizierte herkömmliche Route, da:
- Sie verwendet herkömmliches Routing.
- Sie ist für eine bestimmte Aktion bestimmt.
Da die Routenvorlage nicht {parameter1} und {parameter2} als Parameter einschließt:
- Sie können nur über die -Standardwerte verfügen.
- Diese Route wird immer der Aktion zugeordnet.
, und sind die einzigen URL-Pfade, die der Blogroute entsprechen.
Im vorherigen Beispiel:
- Die Route hat eine höhere Priorität für Übereinstimmungen als die Route, da Sie sie zuerst hinzufügen.
- Es ist ein Beispiel für das Routing im Slug-Stil , bei dem es typisch ist, einen Artikelnamen als Teil der URL zu haben.
Warning
In ASP.NET Core 3.0 oder höher funktioniert das Routing nicht:
- Ein Konzept namens Route definieren. fügt der Middlewarepipeline einen Routenabgleich hinzu. Diese -Middleware prüft die in der App definierten Endpunkte und wählt anhand der Anforderung die beste Endpunktübereinstimmung aus.
- Geben Sie Garantien für die Ausführungsreihenfolge von Erweiterungen wie oder an.
Referenzmaterial zum Routing finden Sie unter Routing.
Reihenfolge des herkömmlichen Routings
Herkömmliches Routing entspricht nur einer Kombination aus Aktion und Controller, die die App definiert. Dieser Ansatz vereinfacht Fälle, in denen herkömmliche Routen überlappen. Wenn Sie Routen mithilfe von , , und hinzufügen, erhalten die Endpunkte automatisch einen Prioritätswert basierend auf der Reihenfolge, in der Sie diese Methoden aufrufen. Übereinstimmungen aus einer Route, die weiter oben in der Liste angezeigt wird, haben eine höhere Priorität. Konventionelles Routing hängt von der Bestellung ab. Im Allgemeinen platzieren Sie Routen mit Bereichen früher, da sie spezifischer sind als Routen ohne einen Bereich. Dedizierte herkömmliche Routen mit allgemeinen Routenparametern, wie z.B. können eine Route zu gierig machen. Eine gierige Route erfasst URLs, die eigentlich von anderen Routen erfasst werden sollten. Fügen Sie die „gierigen“ Routen später in die Routingtabelle ein, um solche Übereinstimmungen zu verhindern.
Warning
Ein catch-all-Parameter kann aufgrund eines Fehlers beim Routing nicht ordnungsgemäß mit Routen übereinstimmen. Apps, die von diesem Fehler betroffen sind, weisen die folgenden Merkmale auf:
- Eine catch-all-Route, zum Beispiel
- Die catch-all-Route kann nicht mit Anforderungen abgeglichen werden, die abgeglichen werden sollen.
- Durch das Entfernen anderer Routen funktioniert die catch-all-Route.
Siehe GitHub Fehler 18677 und 16579 z. B. Fälle, die diesen Fehler treffen.
Ein Opt-In-Fix für diesen Fehler ist in .NET Core 3.1.301 oder höher SDK enthalten. Der folgende Code legt einen internen Switch fest, mit dem dieser Fehler behoben wird:
public static void Main(string[] args)
{
AppContext.SetSwitch("Microsoft.AspNetCore.Routing.UseCorrectCatchAllBehavior",
true);
CreateHostBuilder(args).Build().Run();
}
// Remaining code removed for brevity.
Klärung von mehrdeutigen Aktionen
Wenn zwei Endpunkte über Routing übereinstimmen, muss Routing einen der folgenden Schritte ausführen:
- Den besten Kandidaten auswählen
- Löst eine Ausnahme aus.
Beispiel:
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);
}
}
}
Der vorherige Controller definiert zwei Aktionen, die mit Folgendem übereinstimmen:
- Der URL-Pfad
- Routendaten
Dies ist ein typisches Muster für MVC-Controller:
- zeigt ein Formular zum Bearbeiten eines Produkts an.
- verarbeitet das bereitgestellte Formular.
Um die korrekte Route zu ermitteln:
- wird ausgewählt, wenn die Anforderung ein HTTP- ist.
- wird ausgewählt, wenn das HTTP-Verb etwas anderes ist. wird im Allgemeinen über aufgerufen.
Das () wird für das Routing bereitgestellt, sodass es basierend auf der HTTP-Methode der Anforderung eine Auswahl treffen kann. Das macht zu einer besseren Übereinstimmung als .
Es ist wichtig, die Rolle von Attributen wie zu verstehen. Ähnliche Attribute werden für andere HTTP-Verben definiert. Beim herkömmlichen Routing nutzen Aktionen oft denselben Aktionsnamen, wenn sie Teil eines Workflows für das Anzeigen und Absenden von Formularen sind. Weitere Informationen finden Sie beispielsweise unter Untersuchen der beiden Edit-Aktionsmethoden.
Wenn das Routing den besten Kandidaten nicht auswählen kann, löst es eine Ausnahme aus und listet die mehreren passenden Endpunkte auf.
Namen herkömmlicher Routen
Die Zeichenfolgen und in den folgenden Beispielen sind herkömmliche Routennamen:
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?}");
});
Die Routennamen geben der Route einen logischen Namen. Die benannte Route kann bei der URL-Generierung verwendet werden. Durch das Verwenden einer benannten Route wird die URL-Erstellung erheblich vereinfacht, obwohl die Reihenfolge der Routen die URL-Generierung verkomplizieren sollte. Routennamen müssen anwendungsweit eindeutig sein.
Routennamen:
- Haben keine Auswirkungen auf den URL-Abgleich oder die Verarbeitung von Anforderungen
- Werden nur für die URL-Generierung verwendet
Das Routennamenkonzept wird im Routing als IEndpointNameMetadata dargestellt. Für die Begriffe Routenname und Endpunktname gilt Folgendes:
- Sie sind austauschbar.
- Welcher in der Dokumentation und im Code verwendet wird, hängt von der beschriebenen API ab.
Attribut-Routing für -APIs
-APIs sollten das Attributrouting verwenden, um die Funktionalität der App als eine Gruppe von Ressourcen zu modellieren, bei denen Vorgänge durch HTTP-Verben dargestellt werden.
Beim Attributrouting werden Aktionen mithilfe von Attributen direkt Routenvorlagen zugeordnet. Der folgende -Code ist typisch für eine -API und wird im nächsten Beispiel verwendet:
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();
});
}
Im vorherigen Code wird innerhalb von aufgerufen, um Controller zu mappen, die per Attribut-Routing zugeordnet werden.
Im folgenden Beispiel:
- entspricht einer Gruppe von URLs, ähnlich wie die herkömmliche Standardroute .
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);
}
}
Die Aktion wird für jeden der URL-Pfade , , , oder ausgeführt.
In diesem Beispiel wird ein wichtiger Unterschied beim Programmieren zwischen dem Attributrouting und dem herkömmlichen Routing hervorgehoben. Attributrouting erfordert mehr Eingaben, um eine Route anzugeben. Die herkömmliche Standardroute handhabt Routen prägnanter. Attributrouting ermöglicht jedoch (und erfordert auch) die präzise Kontrolle der Routenvorlagen, die für die einzelnen Aktionen gelten.
Beim Attributrouting haben die Namen des Controllers und der Aktion keinen Einfluss darauf, welche Aktion übereinstimmt, es sei denn, es wird die Tokenersetzung verwendet. Im folgenden Beispiel werden dieselben URLs wie im vorherigen Beispiel verwendet:
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);
}
}
Der folgende Code verwendet die Tokenersetzung für und :
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();
}
}
Der folgende Code wendet auf den Controller an:
[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();
}
}
Im vorangehenden Code müssen die -Methodenvorlagen den Routenvorlagen oder voranstellen. Routenvorlagen, die auf eine Aktion angewendet werden, die mit einem oder beginnen, können nicht mit Routenvorlagen kombiniert werden, die auf den Controller angewendet werden.
Informationen zur Auswahl von Routenvorlagen finden Sie unter Priorität der Routenvorlage.
Reservierte Routingnamen
Die folgenden Schlüsselwörter sind reservierte Routenparameternamen, wenn Sie Controller oder Seiten verwenden:
actionareacontrollerhandlerpage
Die Verwendung von als Routenparameter mit Attributrouting ist ein häufiger Fehler. Diese Auswahl führt zu inkonsistenten und verwirrenden Verhaltensweisen bei der URL-Generierung.
public class MyDemo2Controller : Controller
{
[Route("/articles/{page}")]
public IActionResult ListArticles(int page)
{
return ControllerContext.MyDisplayRouteInfo(page);
}
}
Die URL-Generierung verwendet diese speziellen Parameternamen, um zu bestimmen, ob ein URL-Generierungsvorgang auf eine Seite oder einen Controller verweist.
Die folgenden Schlüsselwörter sind im Kontext einer -Ansicht oder einer -Seite reserviert:
pageusingnamespaceinjectsectioninheritsmodeladdTagHelperremoveTagHelper
Verwenden Sie diese Schlüsselwörter nicht für Verknüpfungsgenerationen, modellgebundene Parameter oder Eigenschaften der obersten Ebene.
HTTP-Verbvorlagen
ASP.NET Core enthält die folgenden HTTP-Verbvorlagen:
- [HttpGet]
- [HttpPost]
- [HttpPut]
- [HttpDelete]
- [HttpHead]
- [HttpPatch]
Routenvorlagen
ASP.NET Core enthält die folgenden Routenvorlagen:
- Alle HTTP-Verbvorlagen sind Routenvorlagen.
- [Route]
Attributrouting mit HTTP-Verbattributen
Betrachten Sie den folgenden 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);
}
}
Im vorhergehenden Code:
- Jede Aktion enthält das -Attribut, das nur den Abgleich mit HTTP GET-Anforderungen einschränkt.
- Die Aktion enthält die Vorlage, sodass die Vorlage an die Vorlage auf dem Controller angefügt wird. Die Vorlage der Methode lautet . Daher stimmt diese Aktion nur mit GET-Anforderungen für das Formular , , usw. überein.
[HttpGet("{id}")] // GET /api/test2/xyz public IActionResult GetProduct(string id) { return ControllerContext.MyDisplayRouteInfo(id); } - Die -Aktion enthält die -Vorlage. Der -Teil der Vorlage beschränkt die -Routenwerte auf Zeichenfolgen, die in eine ganze Zahl konvertiert werden können. Eine GET-Anforderung an :
- Sie entspricht dieser Aktion nicht.
- Sie gibt den Fehler 404 Nicht gefunden zurück.
[HttpGet("int/{id:int}")] // GET /api/test2/int/3 public IActionResult GetIntProduct(int id) { return ControllerContext.MyDisplayRouteInfo(id); }
- Die -Aktion enthält in der Vorlage, beschränkt aber nicht auf die Werte, die in eine ganze Zahl konvertiert werden können. Eine GET-Anforderung an :
- Sie entspricht dieser Route.
- Die Modellbindung kann nicht in eine ganze Zahl konvertieren. Der -Parameter der Methode ist eine ganze Zahl.
- Sie gibt 400 Ungültige Anforderung zurück, da die Modellbindung nicht in eine ganze Zahl konvertieren konnte.
[HttpGet("int2/{id}")] // GET /api/test2/int2/3 public IActionResult GetInt2Product(int id) { return ControllerContext.MyDisplayRouteInfo(id); }
Beim Attributrouting können -Attribute wie , und verwendet werden. Alle HTTP-Verb-Attribute akzeptieren eine Routenvorlage. Im folgenden Beispiel werden zwei Aktionen gezeigt, die derselben Routenvorlage zugeordnet sind:
[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);
}
}
Für die Verwendung des URL-Pfads gilt:
- Die -Aktion wird ausgeführt, wenn das HTTP-Verb ist.
- Die -Aktion wird ausgeführt, wenn das HTTP-Verb ist.
Beim Erstellen einer -API wird selten für eine Aktionsmethode verwendet, weil die Aktionsmethode alle HTTP-Methoden akzeptiert. Es ist besser, das spezifischere HTTP-Verbattribut zu nutzen, um präzise anzugeben, was Ihre API unterstützt. -API-Clients sollten wissen, welche Pfade und HTTP-Verben bestimmten logischen Operationen entsprechen.
-APIs sollten das Attributrouting verwenden, um die Funktionalität der App als eine Gruppe von Ressourcen zu modellieren, bei denen Vorgänge durch HTTP-Verben dargestellt werden. Dieser Entwurf bedeutet, dass viele Vorgänge wie GET und POST in derselben logischen Ressource dieselbe URL verwenden. Das Attributrouting stellt die Steuerungsebene bereit, die zum sorgfältigen Entwerfen des öffentlichen Endpunktlayouts einer API erforderlich ist.
Da eine Attributroute für eine bestimmte Aktion gilt, ist es einfach, Parameter als Teil der Routenvorlagendefinition erforderlich festzulegen. Im folgenden Beispiel ist als Teil des URL-Pfads erforderlich.
[ApiController]
public class Products2ApiController : ControllerBase
{
[HttpGet("/products2/{id}", Name = "Products_List")]
public IActionResult GetProduct(int id)
{
return ControllerContext.MyDisplayRouteInfo(id);
}
}
Für die -Aktion gilt:
- Sie wird mit einem URL-Pfad wie ausgeführt.
- Sie wird nicht mit einem URL-Pfad wie ausgeführt.
Das [Consumes]-Attribut ermöglicht es einer Aktion, die unterstützten Anforderungsinhaltstypen einzuschränken. Weitere Informationen finden Sie unter Definieren unterstützter Anforderungsinhaltstypen mit dem [Consumes]-Attribut.
Eine vollständige Beschreibung und Routenvorlagen und dazugehörige Optionen finden Sie unter Routing in ASP.NET Core.
Weitere Informationen zu finden Sie unter ApiController-Attribut.
Routenname
Im folgenden Code wird ein Routenname von definiert:
[ApiController]
public class Products2ApiController : ControllerBase
{
[HttpGet("/products2/{id}", Name = "Products_List")]
public IActionResult GetProduct(int id)
{
return ControllerContext.MyDisplayRouteInfo(id);
}
}
Verwenden Sie Routennamen, um eine URL basierend auf einer bestimmten Route zu generieren. Routennamen:
- Sie haben keine Auswirkungen auf das URL-Abgleichsverhalten des Routings.
- Sie werden nur für die URL-Generierung verwendet.
Routennamen müssen anwendungsweit eindeutig sein.
Vergleichen Sie den vorherigen Code mit der herkömmlichen Standardroute, die den -Parameter als optional definiert (). APIs präzise angeben zu können, hat Vorteile, z. B. können und an unterschiedliche Aktionen gesendet werden.
Kombinieren von Attributrouten
Um das Attributrouting weniger wiederholt zu gestalten, kombinieren Sie Routenattribute auf dem Controller mit Routenattributen für die einzelnen Aktionen. Die auf dem Controller definierten Routenvorlagen werden den Routenvorlagen der Aktionen vorangestellt. Wenn Sie ein Routenattribute auf dem Controller platzieren, verwenden alle Aktionen des Controllers das Attributrouting.
[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);
}
}
Im vorherigen Beispiel:
- Der URL-Pfad kann mit übereinstimmen.
- Der URL-Pfad kann mit übereinstimmen.
Beide Aktionen gleichen nur „HTTP “ ab, weil sie mit dem -Attribut markiert sind.
Routenvorlagen, die Sie auf eine Aktion anwenden und die beginnen oder nicht mit Routenvorlagen kombiniert werden, die Sie auf den Controller anwenden. Im folgenden Beispiel werden mehrere URL-Pfade zugeordnet, die der Standardroute ähneln.
[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 der folgenden Tabelle werden die -Attribute im vorherigen Code erläutert:
| Attribute | Kann mit kombiniert werden | Definiert die Routenvorlage |
|---|---|---|
[Route("")] |
Yes | "Home" |
[Route("Index")] |
Yes | "Home/Index" |
[Route("/")] |
No | "" |
[Route("About")] |
Yes | "Home/About" |
Reihenfolge der Attributrouten
Beim Routing wird eine Struktur erstellt, die alle Endpunkte gleichzeitig abgleicht:
- Die Routeneinträge verhalten sich so, als ob sie in einer idealen Reihenfolge platziert werden.
- Die spezifischsten Routen können also vor den allgemeineren ausgeführt werden.
Eine Attributroute wie ist beispielsweise spezifischer als eine Attributroute wie . Die -Route hat standardmäßig eine höhere Priorität, da sie spezifischer ist. Beim herkömmlichen Routing ist der*die Entwickler*in verantwortlich dafür, die Routen in die gewünschte Reihenfolge zu bringen.
Attributrouten können die Reihenfolge mit der Eigenschaft konfigurieren. Alle vom Framework bereitgestellten Routenattribute enthalten . Routen werden entsprechend einer aufsteigenden Reihenfolge der -Eigenschaft verarbeitet. Die Standardreihenfolge ist . Das Festlegen einer Route mit wird vor Routen ausgeführt, die keine Reihenfolge vorgeben. Das Festlegen einer Route mit wird nach der Standardreihenfolge der Routen ausgeführt.
Vermeiden Sie eine Abhängigkeit von . Wenn der URL-Raum einer App explizite Reihenfolgenwerte erfordert, um korrekt weiterzuleiten, ist es wahrscheinlich auch für Clients verwirrend. Beim Attributrouting wird im Allgemeinen mithilfe der URL-Zuordnung die richtige Route ausgewählt. Wenn die für die URL-Generierung verwendete Standardreihenfolge nicht funktioniert, ist es meist einfacher, Routennamen als Außerkraftsetzung zu verwenden, statt die -Eigenschaft anzuwenden.
Betrachten Sie die folgenden beiden Controller, die beide den Routenabgleich definieren:
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);
}
}
Beim Anfordern mithilfe des vorherigen Codes wird eine Ausnahme ausgelöst, die der folgenden ähnelt:
AmbiguousMatchException: The request matched multiple endpoints. Matches:
WebMvcRouting.Controllers.HomeController.Index
WebMvcRouting.Controllers.MyDemoController.MyIndex
Das Hinzufügen von zu einem der Routenattribute löst die Mehrdeutigkeit auf:
[Route("")]
[Route("Home", Order = 2)]
[Route("Home/MyIndex")]
public IActionResult MyIndex()
{
return ControllerContext.MyDisplayRouteInfo();
}
Mithilfe des vorherigen Codes führt den -Endpunkt aus. Um zu zu gelangen, fordern Sie . Note:
- Der vorangehende Code ist ein Beispiel für ein schlechtes Routingdesign. Es wird die Eigenschaft veranschaulicht.
- Die Eigenschaft löst nur die Mehrdeutigkeit auf. Diese Vorlage kann nicht übereinstimmen. Es ist besser, die Vorlage zu entfernen.
Informationen zur Routenreihenfolge mit "Pages" finden Sie unter "Pages"-Routen- und App-Konventionen: Routenreihenfolge.
In einigen Fällen wird ein HTTP 500-Fehler mit mehrdeutigen Routen zurückgegeben. Verwenden Sie die Protokollierung, um zu ermitteln, welche Endpunkte die verursacht haben.
Ersetzen von Token in Routenvorlagen ([controller], [action], [area])
Aus Gründen der Einfachheit unterstützen Attributrouten die Tokenersetzung, indem ein Token in eckige Klammern [ ] eingeschlossen wird. Die Token , und werden durch die Werte des Aktionsnamens, des Bereichsnamens und des Controllernamens aus der Aktion ersetzt, in der Sie die Route definieren:
[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);
}
}
Im vorhergehenden Code:
[HttpGet]
public IActionResult List()
{
return ControllerContext.MyDisplayRouteInfo();
}
- Stimmt mit überein
[HttpGet("{id}")]
public IActionResult Edit(int id)
{
return ControllerContext.MyDisplayRouteInfo(id);
}
- Stimmt mit überein
Die Token-Ersetzung erfolgt als letzter Schritt beim Erstellen der Attributrouten. Der folgende Code verhält sich genauso wie der aus dem obigen Beispiel:
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);
}
}
Wenn Sie dies in einer anderen Sprache als Englisch lesen, informieren Sie uns in diesem GitHub Diskussionsproblem wenn Sie die Codekommentare in Ihrer Muttersprache anzeigen möchten.
Sie können Attributrouten auch mit Vererbung kombinieren. Diese Kombination ist leistungsfähig, wenn Sie die Tokenersetzung verwenden. Tokenersetzung gilt auch für Routennamen, die durch Attributrouten definiert werden. generiert für jede Aktion einen eindeutigen Routennamen.
[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);
}
}
Damit das Trennzeichen oder der Tokenersetzungs-Literalzeichenfolge bei einem Abgleich gefunden wird, muss es doppelt vorhanden sein ( oder ), was einem Escapezeichen entspricht.
Verwenden Sie einen Parametertransformator, um die Tokenersetzung anzupassen.
Sie können die Tokenersetzung mithilfe eines Parametertransformors anpassen. Ein Parametertransformator implementiert und wandelt den Wert der Parameter um. Beispielsweise ändert ein benutzerdefinierter -Parametertransformator den Routenwert in :
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();
}
}
Die ist eine Anwendungsmodellkonvention, die Folgendes ausführt:
- Wenden Sie einen Parametertransformator auf alle Attributrouten in einer Anwendung an.
- Passt die Attributroutentokenwerte an, während sie ersetzt werden.
public class SubscriptionManagementController : Controller
{
[HttpGet("[controller]/[action]")]
public IActionResult ListAll()
{
return ControllerContext.MyDisplayRouteInfo();
}
}
Die vorherige -Method stimmt mit überein.
Die wird als Option in registriert.
public void ConfigureServices(IServiceCollection services)
{
services.AddControllersWithViews(options =>
{
options.Conventions.Add(new RouteTokenTransformerConvention(
new SlugifyParameterTransformer()));
});
}
Die Definition von "Slug" finden Sie in der MDN-Webdokumentation.
Warning
Übergeben Sie ein Timeout, wenn Sie zum Verarbeiten nicht vertrauenswürdiger Eingaben verwenden. Ein böswilliger Benutzer kann Eingaben für angeben, um einen Denial-of-Service-Angriff durchzuführen. ASP.NET Core Framework-APIs, die RegularExpressions verwenden, übergeben ein Timeout.
Mehrere Attribut-Routen
Attributrouting unterstützt das Definieren mehrerer Routen, die zu derselben Aktion führen. Dies wird am häufigsten beim Imitieren des Verhaltens der herkömmlichen Standardroute verwendet. Im folgenden Beispiel wird dies gezeigt:
[Route("[controller]")]
public class Products13Controller : Controller
{
[Route("")] // Matches 'Products13'
[Route("Index")] // Matches 'Products13/Index'
public IActionResult Index()
{
return ControllerContext.MyDisplayRouteInfo();
}
Wenn mehrere Routenattribute auf dem Controller platziert werden, bedeutet dies, dass jedes Attribut mit den Routenattributen der Aktionsmethoden kombiniert wird:
[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 Routeneinschränkungen von HTTP-Verben implementieren .
Wenn mehrere Routenattribute, die implementieren, einer Aktion zugeordnet werden, geschieht Folgendes:
- Jede Aktionseinschränkung wird mit der Routenvorlage kombiniert, die auf den Controller angewendet wird.
[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();
}
}
Die Verwendung mehrerer Routen für Aktionen mag zwar nützlich und leistungsfähig erscheinen, es ist jedoch besser, den URL-Bereich Ihrer App einfach und klar definiert zu halten. Verwenden Sie nur mehrere Routen für Aktionen, wenn dies notwendig ist, z. B. um vorhandene Clients zu unterstützen.
Angeben von optionalen Attributroutenparametern, Standardwerten und Einschränkungen
Attributrouten unterstützen dieselbe Inline-Syntax wie herkömmliche Routen, um optionale Parameter, Standardwerte und Einschränkungen anzugeben.
public class Products14Controller : Controller
{
[HttpPost("product14/{id:int}")]
public IActionResult ShowProduct(int id)
{
return ControllerContext.MyDisplayRouteInfo(id);
}
}
wendet im vorherigen Code eine Routeneinschränkung an. Die -Aktion wird nur mit URL-Pfaden wie abgeglichen. Der Routenvorlagenteil schränkt dieses Segment auf ganze Zahlen ein.
Eine detaillierte Beschreibung der Routenvorlagensyntax finden Sie unter Route Template Reference.
Benutzerdefinierte Routenattribute unter Verwendung des IRouteTemplateProvider
Alle Routenattribute implementieren . Die ASP.NET Core Laufzeit:
- Sie sucht nach Attributen für Controllerklassen und Aktionsmethoden, wenn die App gestartet wird.
- Sie verwendet die Attribute, die implementieren, um die erste Gruppe der Routen zu erstellen.
Implementieren Sie , um benutzerdefinierte Routenattribute zu definieren. Jeder lässt Sie eine einzelne Route mit einer benutzerdefinierten Routenvorlage, Reihenfolge und einem benutzerdefinierten Namen definieren:
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();
}
}
Die vorhergehende -Methode gibt zurück.
Anpassen von Attributrouten mithilfe des Anwendungsmodells
Das Anwendungsmodell:
- Ist ein Objektmodell, das beim Start erstellt wurde
- Enthält alle Metadaten, die von ASP.NET Core zum Weiterleiten und Ausführen der Aktionen in einer App verwendet werden.
Das Anwendungsmodell enthält alle Daten, die aus Routenattributen erfasst wurden. Die Daten aus Routenattributen werden von der -Implementierung bereitgestellt. Conventions:
- Können geschrieben werden, um das Anwendungsmodell zu ändern und das Routingverhalten anzupassen
- Werden beim Starten der App gelesen
In diesem Abschnitt wird ein grundlegendes Beispiel zum Anpassen des Routings mithilfe des Anwendungsmodells gezeigt. Der folgende Code sorgt dafür, dass die Routen in etwa mit der Ordnerstruktur des Projekts übereinstimmen.
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()
};
}
}
}
Der folgende Code verhindert, dass die -Konvention auf Controller angewendet wird, die über Attribute zugeordnet werden:
public void Apply(ControllerModel controller)
{
var hasRouteAttributes = controller.Selectors.Any(selector =>
selector.AttributeRouteModel != null);
if (hasRouteAttributes)
{
return;
}
Der folgende Controller verwendet beispielsweise nicht:
[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}");
}
}
Die -Methode:
- Wird nicht ausgeführt, wenn der Controller mit einem Attribut weitergeleitet wird
- Legt die Controllervorlage basierend auf dem fest, während die Basis entfernt wird.
Die kann in angewendet werden:
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.
Betrachten Sie beispielsweise den folgenden 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}");
}
}
}
Im vorhergehenden Code:
- Die Basis ist .
- Der vollständige Name des vorherigen Controllers lautet .
- Die legt die Controllervorlage auf fest.
Die kann auch als Attribut auf einen Controller angewendet werden:
[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}");
}
}
Gemischtes Routing: Attributrouting vs. herkömmliches Routing
ASP.NET Core Apps können die Verwendung herkömmlicher Routing- und Attributroutings kombinieren. In der Regel verwenden Sie herkömmliche Routen für Controller, die HTML-Seiten an Browser bereitstellen, und das Attributrouting für Controller, die APIs bereitstellen .
Aktionen werden entweder herkömmlich oder über Attribute zugeordnet, d.h., dass eine Route auf dem Controller oder der Aktion platziert wird. Aktionen, die Attributrouten definieren, können nicht über herkömmliche Routen erreicht werden, und umgekehrt. Alle Routen-Attribute auf dem Controller bewirkt, dass alle Aktionen in dem Steuerungsattribut geroutet werden.
Attributrouting und herkömmliches Routing verwenden dieselbe Routing-Engine.
URL-Generierungs- und Umgebungswerte
Apps können Routing-URL-Generierungsfunktionen verwenden, um URLs zu Aktionen zu erstellen. Durch das Generieren von URLs müssen URLs nicht mehr hartcodiert werden, sodass der Code robuster und leichter verwaltbar wird. Dieser Abschnitt konzentriert sich auf die von MVC bereitgestellte URL-Generierung und befasst sich nur kurz mit der Funktionsweise. Eine detaillierte Beschreibung der URL-Generierung finden Sie unter Routing in ASP.NET Core.
Die -Schnittstelle ist das zugrunde liegende Element der Infrastruktur zwischen MVC und dem Routing für die URL-Generierung. Eine Instanz von ist über die -Eigenschaft in Controllern, Ansichten und Ansichtskomponenten verfügbar.
Im folgenden Beispiel wird die -Schnittstelle durch die -Eigenschaft verwendet, um eine URL zu einer anderen Aktion zu generieren.
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();
}
}
Wenn die App die herkömmliche Standardroute verwendet, ist der Wert der Variablen die URL-Pfadzeichenfolge . Routing erstellt diesen URL-Pfad durch Kombinieren:
- Die Routenwerte aus der aktuellen Anforderung, die als Umgebungswerte bezeichnet werden
- Die an übergebenen Werte und das Einfügen dieser Werte in die Routenvorlage:
ambient values: { controller = "UrlGeneration", action = "Source" }
values passed to Url.Action: { controller = "UrlGeneration", action = "Destination" }
route template: {controller}/{action}/{id?}
result: /UrlGeneration/Destination
Der Wert eines jeden Routenparameters wird in der Routenvorlage durch die entsprechenden Namen mit den Werten und Umgebungswerten ersetzt. Ein Routenparameter, der keinen Wert aufweist, kann Folgendes tun:
- Einen Standardwert verwenden (falls vorhanden)
- Übersprungen werden (falls möglich). Als Beispiel kann die aus der Routenvorlage genannt werden.
Die URL-Generierung schlägt fehl, wenn ein erforderlicher Routenparameter keinen entsprechenden Wert besitzt. Wenn die URL-Generierung für eine Route fehlschlägt, wird die nächste Route ausprobiert, bis alle Routen getestet wurden oder eine Übereinstimmung gefunden wurde.
Im vorherigen Beispiel wird von herkömmlichen Routing ausgegangen. Die URL-Generierung funktioniert ähnlich wie das Attributrouting, obwohl sich die Konzepte unterscheiden. Für das herkömmliche Routing gilt Folgendes:
- Die Routenwerte werden verwendet, um eine Vorlage zu erweitern.
- Die Routenwerte für und werden in der Regel in dieser Vorlage angezeigt. Dies funktioniert, da die vom Routing abgeglichenen URLs einer Konvention entsprechen.
Im folgenden Beispiel wird Attributrouting verwendet:
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();
}
}
Die -Aktion im vorherigen Code generiert .
LinkGenerator wurde in ASP.NET Core 3.0 als Alternative zu IUrlHelper hinzugefügt. bietet ähnliche, aber flexiblere Funktionen. Jede Methode für verfügt ebenfalls über eine entsprechende Gruppe von Methoden für .
Generieren von URLs nach Aktionsnamen
Url.Action, LinkGenerator.GetPathByAction und alle zugehörigen Überladungen sind alle dafür konzipiert, den Zielendpunkt durch Angabe eines Controllernamens und eines Aktionsnamens zu erzeugen.
Bei Verwendung stellt die Laufzeit die aktuellen Routenwerte für und :
- Die Werte von und sind Teil sowohl von Umgebungswerten als auch von Werten. Die Methode verwendet immer die aktuellen Werte von und und generiert einen URL-Pfad, der zur aktuellen Aktion weiterleitet.
Beim Routing wird versucht, mit den Werten in den Umgebungswerten Informationen zu ergänzen, die beim Generieren einer URL nicht angegeben wurden. Betrachten Sie eine Route wie mit Umgebungswerten :
- Das Routing verfügt über genügend Informationen, um eine URL ohne zusätzliche Werte zu generieren.
- Das Routing verfügt über genügend Informationen, da alle Routenparameter über einen Wert verfügen.
Wenn der Wert hinzugefügt wird, geschieht Folgendes:
- Der -Wert wird ignoriert.
- Der generierte URL-Pfad ist .
Warnung: URL-Pfade sind hierarchisch. Wenn der Wert im vorherigen Beispiel hinzugefügt wird, geschieht Folgendes:
- Beide der Werte werden ignoriert.
- Es gibt keinen Wert mehr, und die URL-Generierung schlägt fehl.
- Sie müssen die gewünschten Werte angeben und eine URL generieren.
Sie können davon ausgehen, dass dieses Problem mit der Standardroute auftritt. Dieses Problem tritt in der Praxis selten auf, da immer explizit einen - und -Wert angibt.
Mehrere Überladungen von Url.Action nehmen ein Routenwerteobjekt, um Werte für andere Routenparameter als und bereitzustellen. Das Routenwertobjekt wird häufig mit verwendet. Beispiel: . Für das Routenwertobjekt gilt Folgendes:
- Es ist üblicherweise ein Objekt von anonymem Typ.
- Es kann ein oder POCO sein.
Alle zusätzlichen Routenwerte, die nicht mit den Routenparametern übereinstimmen, gehen in die Abfragezeichenfolge.
public IActionResult Index()
{
var url = Url.Action("Buy", "Products", new { id = 17, color = "red" });
return Content(url);
}
Der vorangehende Code generiert .
Der folgende Code generiert eine absolute URL:
public IActionResult Index2()
{
var url = Url.Action("Buy", "Products", new { id = 17 }, protocol: Request.Scheme);
// Returns https://localhost:5001/Products/Buy/17
return Content(url);
}
Verwenden Sie zum Erstellen einer absoluten URL eine der folgenden Optionen:
- Eine Überladung, die ein akzeptiert. Beispiel: der vorangehende Code.
- LinkGenerator.GetUriByAction, der standardmäßig absolute URIs generiert
Generieren von URLs nach Route
Im vorangehenden Code wurde das Generieren einer URL durch das Übergeben des Controller- und Aktionsnamens veranschaulicht. stellt außerdem die Url.RouteUrl-Methodengruppe bereit. Diese Methoden ähneln Url.Action, kopieren jedoch nicht die aktuellen Werte und in die Routenwerte. Die häufigste Verwendung von :
- Sie gibt einen Routennamen an, um die URL zu generieren.
- Sie gibt im Allgemeinen keinen Controller- oder Aktionsnamen an.
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();
}
Die folgende -Datei generiert einen HTML-Link zu :
<h1>Test Links</h1>
<ul>
<li><a href="@Url.RouteUrl("Destination_Route")">Test Destination_Route</a></li>
</ul>
Generieren von URLs in HTML und
stellt die -Methoden Html.BeginForm und Html.ActionLink bereit, um jeweils - und -Elemente zu generieren. Diese Methoden verwenden die Url.Action-Methode, um eine URL zu generieren, und akzeptieren ähnliche Argumente. Die -Begleiter für sind und , die ähnliche Funktionen aufweisen.
Taghilfsprogramme generieren URLs mit den Taghilfsprogrammen und . Beide verwenden für ihre Implementierung. Weitere Informationen finden Sie unter Tag Helpers in Formularen.
Innerhalb von Ansichten ist die Eigenschaft für die Ad-hoc-URL-Generierung verfügbar, die nicht von den vorhergehenden Methoden abgedeckt wird.
URL-Generierung in Aktionsergebnissen
In den vorherigen Beispielen wird gezeigt, wie sie in einem Controller verwendet werden . Die häufigste Verwendung in einem Controller besteht darin, eine URL als Teil eines Aktionsergebnisses zu generieren.
Die Basisklassen und stellen Hilfsmethoden für Aktionsergebnisse bereit, die auf eine andere Aktionen verweisen. Eine typische Verwendung besteht darin, nach dem Akzeptieren einer Benutzereingabe weiterzuleiten:
[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);
}
Die Factorymethoden der Aktionsergebnisse (wie und ) folgen einem ähnlichen Muster wie die Methoden für .
Sonderfall für dedizierte herkömmliche Routen
Beim herkömmlichen Routing können Sie eine bestimmte Art von Routendefinition verwenden, die als dedizierte herkömmliche Route bezeichnet wird. Die Route namens im folgenden Beispiel ist eine dedizierte herkömmliche 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?}");
});
Mithilfe der vorherigen Routendefinitionen wird der URL-Pfad mithilfe der Route generiert, aber warum? Sie können vermuten, dass die Routenwerte ausreichen, um eine URL mithilfe von , und das Ergebnis wäre .
Dedizierte herkömmliche Routen nutzen ein spezielles Verhalten von Standardwerten, die keinen entsprechenden Routenparameter besitzen, der verhindert, dass die Route bei der URL-Generierung „zu gierig“ wird. In diesem Fall sind die Standardwerte , und weder noch werden als Routenparameter verwendet. Wenn das Routing die URL-Generierung ausführt, müssen die angegebenen Werte mit den Standardwerten übereinstimmen. Die URL-Generierung mithilfe von schlägt fehl, da die Werte nicht mit übereinstimmen. Routing versucht dann, auf zurückzugreifen, was erfolgreich ist.
Areas
Bereiche sind ein Feature von MVC, das zur Organisation verwandter Funktionen in eine separate Einheit verwendet wird.
- Routing-Namespace für Controlleraktionen
- Ordnerstruktur für Ansichten
Mithilfe von Bereichen kann eine App mehrere Controller mit demselben Namen haben – solange sie verschiedene Bereiche haben. Mithilfe von Bereichen wird außerdem eine Hierarchie erstellt, damit das Routing durch Hinzufügen eines anderen Routenparameters ausgeführt werden kann: zu und . In diesem Abschnitt wird erläutert, wie Routing mit Bereichen interagiert. Weitere Informationen zur Verwendung von Bereichen mit Ansichten finden Sie unter Bereiche.
Im folgenden Beispiel wird MVC konfiguriert, sodass es die herkömmliche Standardroute und eine -Route für einen namens verwendet:
app.UseEndpoints(endpoints =>
{
endpoints.MapAreaControllerRoute("blog_route", "Blog",
"Manage/{controller}/{action}/{id?}");
endpoints.MapControllerRoute("default_route", "{controller}/{action}/{id?}");
});
Im vorherigen Code wird aufgerufen, um die zu erstellen. Der zweite Parameter, , ist der Bereichsname.
Beim Abgleich mit einem URL-Pfad wie generiert die -Route die Routenwerte . Der Routenwert stammt aus einem Standardwert für . Die erstellte Route entspricht dem folgenden Code:
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?}");
});
erstellt eine Route mit einem Standardwert und einer Einschränkung für die Verwendung des angegebenen Bereichsnamens in diesem Fall . Der Standardwert stellt sicher, dass die Route immer ein gültiges Ergebnis liefert, und die Einschränkung verlangt einen definierten Wert für die URL-Generierung.
Beim herkömmlichen Routing ist die Reihenfolge wichtig. Platzieren Sie im Allgemeinen Routen mit Gebieten früher, da sie spezifischer sind als Routen ohne Gebiet.
Die Routenwerte im vorherigen Beispiel werden der folgenden Aktion zugeordnet:
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}");
}
}
}
Das Attribut [Area] kennzeichnet einen Controller als Teil eines Bereichs. Dieser Controller befindet sich im -Bereich. Controller ohne Attribut sind keine Mitglieder eines Bereichs und stimmen nicht überein, wenn der Routenwert durch Routing bereitgestellt wird. Im folgenden Beispiel kann nur der erste aufgelistete Controller die Routenwerte abgleichen.
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}");
}
}
}
Zur Vollständigkeit wird der Namespace der einzelnen Controller hier angezeigt. Wenn die vorherigen Controller denselben Namespace verwenden, wird ein Compilerfehler generiert. Klassennamespaces haben keine Auswirkungen auf das MVC-Routing.
Die ersten beiden Controller gehören zu Bereichen und werden können nur abgleichen, wenn ihr jeweiliger Bereichsname vom -Routenwert bereitgestellt wird. Der dritte Controller gehört keinem Bereich an und kann nur abgleichen, wenn vom Routing kein Wert für bereitgestellt wird.
Im Hinblick auf das Erkennen keines Werts hat die Abwesenheit des -Werts dieselben Auswirkungen, wie wenn der Wert für 0 (null) oder eine leere Zeichenfolge wäre.
Beim Ausführen einer Aktion innerhalb eines Bereichs ist der Routenwert für als Umgebungswert für das Routing verfügbar und kann für die URL-Generierung verwendet werden. Das bedeutet, dass Bereiche bei der URL-Generierung wie im folgenden Beispiel dargestellt standardmäßig beständig sind.
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);
}
}
}
Der folgende Code erzeugt eine URL zu :
public class HomeController : Controller
{
public IActionResult About()
{
var url = Url.Action("AddUser", "Users", new { Area = "Zebra" });
return Content($"URL: {url}");
}
Aktionsdefinition
Öffentliche Methoden in Controllern sind Aktionen, mit Ausnahme von Methoden mit NonAction-Attributen.
Beispielcode
- MyDisplayRouteInfo wird von dem NuGet-Paket Rick.Docs.Samples.RouteInfo bereitgestellt und zeigt Routeninformationen an.
- Anzeigen oder Herunterladen von Beispielcode (Vorgehensweise zum Herunterladen)
Fehlerdiagnostik
Legen Sie für eine ausführliche Routingdiagnoseausgabe auf fest. In der Umgebung, legen Sie die Protokollierungsstufe in fest.
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Debug",
"Microsoft.Hosting.Lifetime": "Information"
}
}
}