aspnetcore/mvc/controllers/routing.md
By Ryan Nowak, Kirk Larkin, and Rick Anderson
:::moniker range=">= aspnetcore-6.0"
ASP.NET Core controllers use the Routing middleware to match the URLs of incoming requests and map them to actions. Route templates:
Program.cs or in attributes.Actions are either conventionally-routed or attribute-routed. Placing a route on the controller or action makes it attribute-routed. See Mixed routing for more information.
This document:
<a name="cr6"></a>
The ASP.NET Core MVC template generates conventional routing code similar to the following example:
Use xref:Microsoft.AspNetCore.Builder.ControllerEndpointRouteBuilderExtensions.MapControllerRoute%2A to create a single route. The single route is the default route. Most apps with controllers and views use a route template similar to the default route. REST APIs should use attribute routing.
The route template "{controller=Home}/{action=Index}/{id?}":
Matches a URL path like /Products/Details/5
Extracts the route values { controller = Products, action = Details, id = 5 } by tokenizing the path. The extraction of route values results in a match if the app has a controller named ProductsController and a Details action:
/Products/Details/5 model binds the value of id = 5 to set the id parameter to 5. For more information, see Model Binding.
{controller=Home} defines Home as the default controller.
{action=Index} defines Index as the default action.
The ? character in {id?} defines id as optional.
Matches the URL path /.
Produces the route values { controller = Home, action = Index }.
The values for controller and action make use of the default values. id doesn't produce a value since there's no corresponding segment in the URL path. / only matches if there exists a HomeController and Index action:
public class HomeController : Controller
{
public IActionResult Index() { ... }
}
Using the preceding controller definition and route template, the HomeController.Index action runs for the following URL paths:
/Home/Index/17/Home/Index/Home/The URL path / uses the route template default Home controller and Index action. The URL path /Home uses the route template default Index action.
The convenience method xref:Microsoft.AspNetCore.Builder.ControllerEndpointRouteBuilderExtensions.MapDefaultControllerRoute%2A:
Replaces:
[!IMPORTANT] Routing is configured by using the xref:Microsoft.AspNetCore.Builder.EndpointRoutingApplicationBuilderExtensions.UseRouting%2A and xref:Microsoft.AspNetCore.Builder.EndpointRoutingApplicationBuilderExtensions.UseEndpoints%2A middleware. To use controllers:
- Call xref:Microsoft.AspNetCore.Builder.ControllerEndpointRouteBuilderExtensions.MapControllers%2A to map attribute routed controllers.
- Call xref:Microsoft.AspNetCore.Builder.ControllerEndpointRouteBuilderExtensions.MapControllerRoute%2A or xref:Microsoft.AspNetCore.Builder.ControllerEndpointRouteBuilderExtensions.MapAreaControllerRoute%2A, to map both conventionally routed controllers and attribute routed controllers.
Apps typically don't need to call
UseRoutingorUseEndpoints. xref:Microsoft.AspNetCore.Builder.WebApplicationBuilder configures a middleware pipeline that wraps middleware added inProgram.csby usingUseRoutingandUseEndpoints. For more information, see xref:fundamentals/routing.
<a name="routing-conventional-ref-label"></a> <a name="crd6"></a>
Use conventional routing with controllers and views. The default route is:
The preceding code is an example of a conventional route. It's called conventional routing because it establishes a convention for URL paths:
{controller=Home}, maps to the controller name.{action=Index}, maps to the action name.{id?} is used for an optional id. The ? in {id?} makes it optional. id maps to a model entity.Using this default route, the URL path:
/Products/List maps to the ProductsController.List action./Blog/Article/17 maps to BlogController.Article and typically model binds the id parameter to 17.This mapping:
By using conventional routing with the default route, you don't need to create a new URL pattern for each action. For an app with CRUD style actions, having consistency for the URLs across controllers:
[!WARNING] The route template defines the
idas optional. Actions can execute without the optional ID provided as part of the URL. Generally, whenidis omitted from the URL:
- Model binding sets
idto0.- No entity is found in the database matching
id == 0.Attribute routing provides fine-grained control to make the ID required for some actions and not for others. By convention, the documentation includes optional parameters like
idwhen they're likely to appear in correct usage.
Most apps should choose a basic and descriptive routing scheme so that URLs are readable and meaningful. The default conventional route {controller=Home}/{action=Index}/{id?}:
xref:Microsoft.AspNetCore.Builder.ControllerEndpointRouteBuilderExtensions.MapControllerRoute%2A and xref:Microsoft.AspNetCore.Builder.MvcAreaRouteBuilderExtensions.MapAreaRoute%2A :
Endpoint routing in ASP.NET Core:
Enable Logging to see how the built-in routing implementations, such as xref:Microsoft.AspNetCore.Routing.Route, match requests.
Attribute routing is explained later in this document.
<a name="mr6"></a>
You can configure multiple conventional routes by adding more calls to xref:Microsoft.AspNetCore.Builder.ControllerEndpointRouteBuilderExtensions.MapControllerRoute%2A and xref:Microsoft.AspNetCore.Builder.ControllerEndpointRouteBuilderExtensions.MapAreaControllerRoute%2A. When you add these calls, you can define multiple conventions or add conventional routes that are dedicated to a specific action, such as:
<a name="dcr"></a>
The blog route in the preceding code is a dedicated conventional route. It's a dedicated conventional route because:
Because the route template "blog/{*article}" doesn't include controller and action as parameters:
{ controller = "Blog", action = "Article" }.BlogController.Article./Blog, /Blog/Article, and /Blog/{any-string} are the only URL paths that match the blog route.
In the preceding example:
blog route has a higher priority for matches than the default route because you add it first.[!WARNING] In ASP.NET Core, routing doesn't:
- Define a concept called a route.
UseRoutingadds route matching to the middleware pipeline. TheUseRoutingmiddleware looks at the set of endpoints defined in the app, and selects the best endpoint match based on the request.- Provide guarantees about the execution order of extensibility like xref:Microsoft.AspNetCore.Routing.IRouteConstraint or xref:Microsoft.AspNetCore.Mvc.ActionConstraints.IActionConstraint.
See Routing for reference material on routing.
<a name="cro6"></a>
Conventional routing only matches a combination of action and controller that the app defines. This approach simplifies cases where conventional routes overlap.
When you add routes by using xref:Microsoft.AspNetCore.Builder.ControllerEndpointRouteBuilderExtensions.MapControllerRoute%2A, xref:Microsoft.AspNetCore.Builder.ControllerEndpointRouteBuilderExtensions.MapDefaultControllerRoute%2A, and xref:Microsoft.AspNetCore.Builder.ControllerEndpointRouteBuilderExtensions.MapAreaControllerRoute%2A, the endpoints automatically get an order value based on the order you invoke these methods. Matches from a route that appears earlier in the list have a higher priority. Conventional routing depends on order. In general, place routes with areas earlier because they're more specific than routes without an area. Dedicated conventional routes with catch-all route parameters, such as {*article}, can make a route too greedy. A greedy route matches URLs that you intended to be matched by other routes. Put the greedy routes later in the route table to prevent greedy matches.
<a name="best"></a>
When two endpoints match through routing, routing must do one of the following steps:
For example:
The preceding controller defines two actions that match:
/Products33/Edit/17{ controller = Products33, action = Edit, id = 17 }.This is a typical pattern for MVC controllers:
Edit(int) displays a form to edit a product.Edit(int, Product) processes the posted form.To resolve the correct route:
Edit(int, Product) is selected when the request is an HTTP POST.Edit(int) is selected when the HTTP verb is anything else. Edit(int) is generally called via GET.The xref:Microsoft.AspNetCore.Mvc.HttpPostAttribute, [HttpPost], is provided to routing so that it can choose based on the HTTP method of the request. The HttpPostAttribute makes Edit(int, Product) a better match than Edit(int).
It's important to understand the role of attributes like HttpPostAttribute. Similar attributes are defined for other HTTP verbs. In conventional routing, actions often use the same action name when they're part of a show form, submit form workflow. For example, see Examine the two Edit action methods.
If routing can't choose the best candidate, it throws an xref:System.Reflection.AmbiguousMatchException and lists the multiple matched endpoints.
<a name="routing-route-name-ref-label"></a>
The strings "blog" and "default" in the following examples are conventional route names:
The route names give the route a logical name. The named route can be used for URL generation. Using a named route simplifies URL creation when the ordering of routes could make URL generation complicated. Route names must be unique application wide.
Route names:
The route name concept is represented in routing as IEndpointNameMetadata. The terms route name and endpoint name:
<a name="attribute-routing-ref-label"></a> <a name="ar6"></a>
REST APIs should use attribute routing to model the app's functionality as a set of resources where operations are represented by HTTP verbs.
Attribute routing uses a set of attributes to map actions directly to route templates. The following code is typical for a REST API and is used in the next sample:
In the preceding code, you call xref:Microsoft.AspNetCore.Builder.ControllerEndpointRouteBuilderExtensions.MapControllers%2A to map attribute routed controllers.
In the following example:
HomeController matches a set of URLs similar to what the default conventional route {controller=Home}/{action=Index}/{id?} matches.The HomeController.Index action runs for any of the URL paths /, /Home, /Home/Index, or /Home/Index/3.
This example highlights a key programming difference between attribute routing and conventional routing. Attribute routing requires more input to specify a route. The conventional default route handles routes more succinctly. However, attribute routing allows and requires precise control of which route templates apply to each action.
With attribute routing, the controller and action names play no part in which action is matched, unless token replacement is used. The following example matches the same URLs as the previous example:
The following code uses token replacement for action and controller:
The following code applies [Route("[controller]/[action]")] to the controller:
In the preceding code, the Index method templates must prepend / or ~/ to the route templates. Route templates applied to an action that begin with / or ~/ don't get combined with route templates applied to the controller.
See Route template precedence for information on route template selection.
The following keywords are reserved route parameter names when you use Controllers or Razor Pages:
actionareacontrollerhandlerpageUsing page as a route parameter with attribute routing is a common error. This choice results in inconsistent and confusing behavior with URL generation.
URL generation uses these special parameter names to determine if a URL generation operation refers to a Razor Page or to a Controller.
The following keywords are reserved in the context of a Razor view or a Razor Page:
pageusingnamespaceinjectsectioninheritsmodeladdTagHelperremoveTagHelperDon't use these keywords for link generations, model bound parameters, or top level properties.
<a name="verb6"></a>
ASP.NET Core includes the following HTTP verb templates:
<a name="rt6"></a>
ASP.NET Core includes the following route templates:
<a name="arx"></a>
Consider the following controller:
In the preceding code:
[HttpGet] attribute, which constrains matching to HTTP GET requests only.GetProduct action includes the "{id}" template, so the id appends to the "api/[controller]" template on the controller. The method's template is "api/[controller]/{id}". Therefore this action only matches GET requests for the form /api/test2/xyz, /api/test2/123, /api/test2/{any string}, and so on.
[!code-csharp]GetIntProduct action contains the "int/{id:int}" template. The :int portion of the template constrains the id route values to strings that can be converted to an integer. A GET request to /api/test2/int/abc:
GetInt2Product action contains {id} in the template, but doesn't constrain id to values that can be converted to an integer. A GET request to /api/test2/int2/abc:
abc to an integer. The id parameter of the method is integer.abc to an integer.
[!code-csharp]Attribute routing can use xref:Microsoft.AspNetCore.Mvc.Routing.HttpMethodAttribute attributes such as xref:Microsoft.AspNetCore.Mvc.HttpPostAttribute, xref:Microsoft.AspNetCore.Mvc.HttpPutAttribute, and xref:Microsoft.AspNetCore.Mvc.HttpDeleteAttribute. All of the HTTP verb attributes accept a route template. The following example shows two actions that match the same route template:
Using the URL path /products3:
MyProductsController.ListProducts action runs when the HTTP verb is GET.MyProductsController.CreateProduct action runs when the HTTP verb is POST.When building a REST API, it's rare that you need to use [Route(...)] on an action method because the action accepts all HTTP methods. Use the more specific HTTP verb attribute to be precise about what your API supports. Clients of REST APIs are expected to know what paths and HTTP verbs map to specific logical operations.
REST APIs should use attribute routing to model the app's functionality as a set of resources where operations are represented by HTTP verbs. This design means that many operations, such as GET and POST on the same logical resource, use the same URL. Attribute routing provides the level of control needed to carefully design an API's public endpoint layout.
Since an attribute route applies to a specific action, it's easy to make parameters required as part of the route template definition. In the following example, id is required as part of the URL path:
The Products2ApiController.GetProduct(int) action:
/products2/3/products2.The [Consumes] attribute allows an action to limit the supported request content types. For more information, see Define supported request content types with the Consumes attribute.
See Routing for a full description of route templates and related options.
For more information on [ApiController], see ApiController attribute.
The following code defines a route name of Products_List:
Use route names to generate a URL based on a specific route. Route names:
Route names must be unique application-wide.
Contrast the preceding code with the conventional default route, which defines the id parameter as optional ({id?}). The ability to precisely specify APIs has advantages, such as allowing /products and /products/5 to be dispatched to different actions.
<a name="routing-combining-ref-label"></a>
To make attribute routing less repetitive, combine route attributes on the controller with route attributes on the individual actions. The route templates you define on the controller are prepended to route templates on the actions. When you place a route attribute on the controller, all actions in the controller use attribute routing.
In the preceding example:
/products can match ProductsApi.ListProducts/products/5 can match ProductsApi.GetProduct(int).Both of these actions only match HTTP GET because they're marked with the [HttpGet] attribute.
Route templates that you apply to an action and that begin with / or ~/ don't get combined with route templates that you apply to the controller. The following example matches a set of URL paths similar to the default route.
The following table explains the [Route] attributes in the preceding code:
| Attribute | Combines with [Route("Home")] | Defines route template |
|---|---|---|
[Route("")] | Yes | "Home" |
[Route("Index")] | Yes | "Home/Index" |
[Route("/")] | No | "" |
[Route("About")] | Yes | "Home/About" |
<a name="routing-ordering-ref-label"></a> <a name="oar"></a>
Routing builds a tree and matches all endpoints simultaneously:
For example, an attribute route like blog/search/{topic} is more specific than an attribute route like blog/{*article}. The blog/search/{topic} route has higher priority, by default, because it's more specific. By using conventional routing, the developer is responsible for placing routes in the desired order.
Attribute routes can configure an order using the xref:Microsoft.AspNetCore.Mvc.RouteAttribute.Order property. All of the framework provided route attributes include Order . Routes are processed according to an ascending sort of the Order property. The default order is 0. Setting a route using Order = -1 runs before routes that don't set an order. Setting a route using Order = 1 runs after default route ordering.
Avoid depending on Order. If an app's URL-space requires explicit order values to route correctly, then it's likely confusing to clients as well. In general, attribute routing selects the correct route with URL matching. If the default order used for URL generation isn't working, using a route name as an override is usually simpler than applying the Order property.
Consider the following two controllers which both define the route matching /home:
Requesting /home by using the preceding code throws an exception similar to the following:
AmbiguousMatchException: The request matched multiple endpoints. Matches:
WebMvcRouting.Controllers.HomeController.Index
WebMvcRouting.Controllers.MyDemoController.MyIndex
Adding Order to one of the route attributes resolves the ambiguity:
With the preceding code, /home runs the HomeController.Index endpoint. To get to the MyDemoController.MyIndex, request /home/MyIndex. Note:
Order property.Order property only resolves the ambiguity. That template cannot be matched. It's better to remove the [Route("Home")] template.For information on route order with Razor Pages, see Razor Pages route and app conventions: Route order.
In some cases, an HTTP 500 error is returned with ambiguous routes. Use logging to see which endpoints caused the AmbiguousMatchException.
<a name="routing-token-replacement-templates-ref-label"></a>
For convenience, attribute routes support token replacement by enclosing a token in square brackets ([, ]). The tokens [action], [area], and [controller] are replaced with the values of the action name, area name, and controller name from the action where you define the route:
In the preceding code:
/Products0/List/Products0/Edit/{id}Token replacement happens as the last step of building the attribute routes. The preceding example behaves the same as the following code:
You can also combine attribute routes with inheritance. This combination is powerful when you use token replacement. Token replacement also applies to route names defined by attribute routes.
[Route("[controller]/[action]", Name="[controller]_[action]")]generates a unique route name for each action:
To match the literal token replacement delimiter [ or ], escape it by repeating the character ([[ or ]]).
<a name="routing-token-replacement-transformers-ref-label"></a>
You can customize token replacement by using a parameter transformer. A parameter transformer implements xref:Microsoft.AspNetCore.Routing.IOutboundParameterTransformer and transforms the value of parameters. For example, a custom SlugifyParameterTransformer parameter transformer changes the SubscriptionManagement route value to subscription-management:
The xref:Microsoft.AspNetCore.Mvc.ApplicationModels.RouteTokenTransformerConvention is an application model convention that:
The preceding ListAll method matches /subscription-management/list-all.
The RouteTokenTransformerConvention is registered as an option:
For the definition of slug, see MDN web docs on Slug.
[!INCLUDE] <a name="routing-multiple-routes-ref-label"></a>
Attribute routing supports defining multiple routes that reach the same action. The most common usage of this is to mimic the behavior of the default conventional route as shown in the following example:
Putting multiple route attributes on the controller means that each one combines with each of the route attributes on the action methods:
All the HTTP verb route constraints implement IActionConstraint.
When multiple route attributes that implement xref:Microsoft.AspNetCore.Mvc.ActionConstraints.IActionConstraint are placed on an action:
Using multiple routes on actions might seem useful and powerful, it's better to keep your app's URL space basic and well defined. Use multiple routes on actions only where needed, for example, to support existing clients.
<a name="routing-attr-options"></a>
Attribute routes support the same inline syntax as conventional routes to specify optional parameters, default values, and constraints.
In the preceding code, [HttpPost("product14/{id:int}")] applies a route constraint. The Products14Controller.ShowProduct action is matched only by URL paths like /product14/3. The route template portion {id:int} constrains that segment to only integers.
For a detailed description of route template syntax, see Route Template Reference.
<a name="routing-cust-rt-attr-irt-ref-label"></a>
All of the route attributes implement xref:Microsoft.AspNetCore.Mvc.Routing.IRouteTemplateProvider. The ASP.NET Core runtime:
IRouteTemplateProvider to build the initial set of routes.Implement IRouteTemplateProvider to define custom route attributes. Each IRouteTemplateProvider allows you to define a single route with a custom route template, order, and name:
The preceding Get method returns Order = 2, Template = api/MyTestApi.
<a name="routing-app-model-ref-label"></a>
The application model:
Program.cs.The application model includes all of the data gathered from route attributes. The data from route attributes is provided by the IRouteTemplateProvider implementation. Conventions:
This section shows a basic example of customizing routing by using the application model. The following code makes routes roughly line up with the folder structure of the project.
The following code prevents the namespace convention from being applied to controllers that are attribute routed:
For example, the following controller doesn't use NamespaceRoutingConvention:
The NamespaceRoutingConvention.Apply method:
namespace, with the base namespace removed.The NamespaceRoutingConvention can be applied in Program.cs:
For example, consider the following controller:
In the preceding code:
namespace is My.Application.My.Application.Admin.Controllers.UsersController.NamespaceRoutingConvention sets the controllers template to Admin/Controllers/Users/[action]/{id?.The NamespaceRoutingConvention can also be applied as an attribute on a controller:
<a name="routing-mixed-ref-label"></a>
ASP.NET Core apps can mix the use of conventional routing and attribute routing. Typically, you use conventional routes for controllers that serve HTML pages to browsers, and attribute routing for controllers that serve REST APIs.
Actions are either conventionally routed or attribute routed. When you place a route on the controller or the action, it becomes attribute routed. You can't reach actions that define attribute routes through the conventional routes, and vice versa. Any route attribute on the controller makes all actions in the controller attribute routed.
Attribute routing and conventional routing use the same routing engine.
<a name="routing-url-gen-ref-label"></a> <a name="ambient"></a>
Apps can use routing URL generation features to generate URL links to actions. Generating URLs eliminates hard-coding URLs, making code more robust and maintainable. This section focuses on the URL generation features provided by MVC and only cover basics of how URL generation works. See Routing for a detailed description of URL generation.
The xref:Microsoft.AspNetCore.Mvc.IUrlHelper interface is the underlying element of infrastructure between MVC and routing for URL generation. An instance of IUrlHelper is available through the Url property in controllers, views, and view components.
In the following example, the IUrlHelper interface is used through the Controller.Url property to generate a URL to another action.
If the app uses the default conventional route, the value of the url variable is the URL path string /UrlGeneration/Destination. Routing creates this URL path by combining:
Url.Action and substituting those values into the route template:ambient values: { controller = "UrlGeneration", action = "Source" }
values passed to Url.Action: { controller = "UrlGeneration", action = "Destination" }
route template: {controller}/{action}/{id?}
result: /UrlGeneration/Destination
Each route parameter in the route template has its value substituted by matching names with the values and ambient values. A route parameter that doesn't have a value can:
id from the route template {controller}/{action}/{id?}.URL generation fails if any required route parameter doesn't have a corresponding value. If URL generation fails for a route, the next route is tried until all routes have been tried or a match is found.
The preceding example of Url.Action assumes conventional routing. URL generation works similarly with attribute routing, though the concepts are different. With conventional routing:
controller and action usually appear in that template. This works because the URLs matched by routing adhere to a convention.The following example uses attribute routing:
The Source action in the preceding code generates custom/url/to/destination.
xref:Microsoft.AspNetCore.Routing.LinkGenerator was added in ASP.NET Core 3.0 as an alternative to IUrlHelper. LinkGenerator offers similar but more flexible functionality. Each method on IUrlHelper has a corresponding family of methods on LinkGenerator as well.
Url.Action, LinkGenerator.GetPathByAction, and all related overloads all are designed to generate the target endpoint by specifying a controller name and action name.
When you use Url.Action, the runtime provides the current route values for controller and action:
controller and action are part of both ambient values and values. The method Url.Action always uses the current values of action and controller and generates a URL path that routes to the current action.Routing attempts to use the values in ambient values to fill in information that wasn't provided when generating a URL. Consider a route like {a}/{b}/{c}/{d} with ambient values { a = Alice, b = Bob, c = Carol, d = David }:
If the value { d = Donovan } is added:
{ d = David } is ignored.Alice/Bob/Carol/Donovan.Warning: URL paths are hierarchical. In the preceding example, if the value { c = Cheryl } is added:
{ c = Carol, d = David } are ignored.d and URL generation fails.c and d to generate a URL.You might expect to hit this problem with the default route {controller}/{action}/{id?}. This problem is rare in practice because Url.Action always explicitly specifies a controller and action value.
Several overloads of Url.Action take a route values object to provide values for route parameters other than controller and action. The route values object is frequently used with id. For example, Url.Action("Buy", "Products", new { id = 17 }). The route values object:
IDictionary<> or a POCO).Any additional route values that don't match route parameters go in the query string.
The preceding code generates /Products/Buy/17?color=red.
The following code generates an absolute URL:
To create an absolute URL, use one of the following options:
protocol. For example, the preceding code.<a name="routing-gen-urls-route-ref-label"></a>
The preceding code demonstrated generating a URL by passing in the controller and action name. IUrlHelper also provides the Url.RouteUrl family of methods. These methods are similar to Url.Action, but they don't copy the current values of action and controller to the route values. The most common usage of Url.RouteUrl:
The following Razor file generates an HTML link to the Destination_Route:
<a name="routing-gen-urls-html-ref-label"></a>
xref:Microsoft.AspNetCore.Mvc.Rendering.IHtmlHelper provides the xref:Microsoft.AspNetCore.Mvc.ViewFeatures.HtmlHelper methods Html.BeginForm and Html.ActionLink to generate <form> and <a> elements respectively. These methods use the Url.Action method to generate a URL and they accept similar arguments. The Url.RouteUrl companions for HtmlHelper are Html.BeginRouteForm and Html.RouteLink which have similar functionality.
TagHelpers generate URLs through the form TagHelper and the <a> TagHelper. Both of these use IUrlHelper for their implementation. For more information, see Tag Helpers in forms.
Inside views, the IUrlHelper is available through the Url property for any ad-hoc URL generation not covered by the preceding methods.
<a name="routing-gen-urls-action-ref-label"></a>
The preceding examples show how to use IUrlHelper in a controller. The most common usage in a controller is to generate a URL as part of an action result.
The xref:Microsoft.AspNetCore.Mvc.ControllerBase and xref:Microsoft.AspNetCore.Mvc.Controller base classes provide convenience methods for action results that reference another action. One typical usage is to redirect after accepting user input:
The action results factory methods such as xref:Microsoft.AspNetCore.Mvc.ControllerBase.RedirectToAction%2A and xref:Microsoft.AspNetCore.Mvc.ControllerBase.CreatedAtAction%2A follow a similar pattern to the methods on IUrlHelper.
<a name="routing-dedicated-ref-label"></a>
Conventional routing can use a special kind of route definition called a dedicated conventional route. In the following example, the route named blog is a dedicated conventional route:
Using the preceding route definitions, Url.Action("Index", "Home") generates the URL path / by using the default route, but why? You might guess the route values { controller = Home, action = Index } are enough to generate a URL by using blog, and the result would be /blog?action=Index&controller=Home.
Dedicated conventional routes rely on a special behavior of default values that don't have a corresponding route parameter that prevents the route from being too greedy with URL generation. In this case the default values are { controller = Blog, action = Article }, and neither controller nor action appears as a route parameter. When routing performs URL generation, the values provided must match the default values. URL generation using blog fails because the values { controller = Home, action = Index } don't match { controller = Blog, action = Article }. Routing then falls back to try default, which succeeds.
<a name="routing-areas-ref-label"></a>
Areas are an MVC feature used to organize related functionality into a group as a separate:
Using areas allows an app to have multiple controllers with the same name, as long as they have different areas. Using areas creates a hierarchy for the purpose of routing by adding another route parameter, area to controller and action. This section discusses how routing interacts with areas. See Areas for details about how areas are used with views.
The following example configures MVC to use the default conventional route and an area route for an area named Blog:
In the preceding code, xref:Microsoft.AspNetCore.Builder.ControllerEndpointRouteBuilderExtensions.MapAreaControllerRoute%2A is called to create the "blog_route". The second parameter, "Blog", is the area name.
When matching a URL path like /Manage/Users/AddUser, the "blog_route" route generates the route values { area = Blog, controller = Users, action = AddUser }. The area route value comes from a default value for area. The route created by MapAreaControllerRoute is equivalent to the following code:
MapAreaControllerRoute creates a route using both a default value and constraint for area by using the provided area name, in this case Blog. The default value ensures that the route always produces { area = Blog, ... }, and the constraint requires the value { area = Blog, ... } for URL generation.
Conventional routing is order-dependent. In general, place routes with areas earlier as they're more specific than routes without an area.
Using the preceding example, the route values { area = Blog, controller = Users, action = AddUser } match the following action:
The [Area] attribute is what denotes a controller as part of an area. This controller is in the Blog area. Controllers without an [Area] attribute aren't members of any area, and don't match when the area route value is provided by routing. In the following example, only the first controller listed can match the route values { area = Blog, controller = Users, action = AddUser }.
For completeness, the namespace of each controller is shown here. If the preceding controllers used the same namespace, a compiler error would be generated. Class namespaces have no effect on MVC's routing.
The first two controllers are members of areas, and only match when their respective area name is provided by the area route value. The third controller isn't a member of any area, and can only match when no value for area is provided by routing.
<a name="aa"></a>
In terms of matching no value, the absence of the area value is the same as if the value for area were null or the empty string.
When executing an action inside an area, the route value for area is available as an ambient value for routing to use for URL generation. This means that by default areas act sticky for URL generation as demonstrated by the following sample.
The following code generates a URL to /Zebra/Users/AddUser:
<a name="action"></a>
Public methods on a controller, except those with the NonAction attribute, are actions.
:::moniker-end
:::moniker range="< aspnetcore-6.0"
ASP.NET Core controllers use the Routing middleware to match the URLs of incoming requests and map them to actions. Route templates:
Actions are either conventionally-routed or attribute-routed. Placing a route on the controller or action makes it attribute-routed. See Mixed routing for more information.
This document:
<a name="cr"></a>
Startup.Configure typically has code similar to the following example when using conventional routing:
Inside the call to xref:Microsoft.AspNetCore.Builder.EndpointRoutingApplicationBuilderExtensions.UseEndpoints%2A, xref:Microsoft.AspNetCore.Builder.ControllerEndpointRouteBuilderExtensions.MapControllerRoute%2A is used to create a single route. The single route is named default route. Most apps with controllers and views use a route template similar to the default route. REST APIs should use attribute routing.
The route template "{controller=Home}/{action=Index}/{id?}":
Matches a URL path like /Products/Details/5
Extracts the route values { controller = Products, action = Details, id = 5 } by tokenizing the path. The extraction of route values results in a match if the app has a controller named ProductsController and a Details action:
/Products/Details/5 model binds the value of id = 5 to set the id parameter to 5. For more information, see Model Binding.
{controller=Home} defines Home as the default controller.
{action=Index} defines Index as the default action.
The ? character in {id?} defines id as optional.
Default and optional route parameters don't need to be present in the URL path for a match. For a detailed description of route template syntax, see Route Template Reference.
Matches the URL path /.
Produces the route values { controller = Home, action = Index }.
The values for controller and action make use of the default values. id doesn't produce a value since there's no corresponding segment in the URL path. / only matches if there exists a HomeController and Index action:
public class HomeController : Controller
{
public IActionResult Index() { ... }
}
Using the preceding controller definition and route template, the HomeController.Index action runs for the following URL paths:
/Home/Index/17/Home/Index/Home/The URL path / uses the route template default Home controller and Index action. The URL path /Home uses the route template default Index action.
The convenience method xref:Microsoft.AspNetCore.Builder.ControllerEndpointRouteBuilderExtensions.MapDefaultControllerRoute%2A:
endpoints.MapDefaultControllerRoute();
Replaces:
endpoints.MapControllerRoute("default", "{controller=Home}/{action=Index}/{id?}");
[!IMPORTANT] Routing is configured by using the xref:Microsoft.AspNetCore.Builder.EndpointRoutingApplicationBuilderExtensions.UseRouting%2A,
MapControllerRoute, andMapAreaControllerRoutemiddleware. To use controllers:
- Call xref:Microsoft.AspNetCore.Builder.ControllerEndpointRouteBuilderExtensions.MapControllers%2A inside
UseEndpointsto map attribute routed controllers.- Call xref:Microsoft.AspNetCore.Builder.ControllerEndpointRouteBuilderExtensions.MapControllerRoute%2A or xref:Microsoft.AspNetCore.Builder.ControllerEndpointRouteBuilderExtensions.MapAreaControllerRoute%2A to map both conventionally routed controllers and attribute routed controllers.
<a name="routing-conventional-ref-label"></a> <a name="crd"></a>
Use conventional routing with controllers and views. The default route is:
The preceding code is an example of a conventional route. It's called conventional routing because it establishes a convention for URL paths:
{controller=Home}, maps to the controller name.{action=Index}, maps to the action name.{id?} is used for an optional id. The ? in {id?} makes it optional. id maps to a model entity.Using this default route, the URL path:
/Products/List maps to the ProductsController.List action./Blog/Article/17 maps to BlogController.Article and typically model binds the id parameter to 17.This mapping:
By using conventional routing with the default route, you don't need to create a new URL pattern for each action. For an app with CRUD style actions, having consistency for the URLs across controllers:
[!WARNING] The route template defines the
idas optional. Actions can execute without the optional ID provided as part of the URL. Generally, whenidis omitted from the URL:
- Model binding sets
idto0.- No entity is found in the database matching
id == 0.Attribute routing provides fine-grained control to make the ID required for some actions and not for others. By convention, the documentation includes optional parameters like
idwhen they're likely to appear in correct usage.
Most apps should choose a basic and descriptive routing scheme so that URLs are readable and meaningful. The default conventional route {controller=Home}/{action=Index}/{id?}:
xref:Microsoft.AspNetCore.Builder.ControllerEndpointRouteBuilderExtensions.MapControllerRoute%2A and xref:Microsoft.AspNetCore.Builder.MvcAreaRouteBuilderExtensions.MapAreaRoute%2A :
Endpoint routing in ASP.NET Core 3.0 or later:
Enable Logging to see how the built-in routing implementations, such as xref:Microsoft.AspNetCore.Routing.Route, match requests.
Attribute routing is explained later in this document.
<a name="mr"></a>
Multiple conventional routes can be added inside UseEndpoints by adding more calls to xref:Microsoft.AspNetCore.Builder.ControllerEndpointRouteBuilderExtensions.MapControllerRoute%2A and xref:Microsoft.AspNetCore.Builder.ControllerEndpointRouteBuilderExtensions.MapAreaControllerRoute%2A. Doing so allows defining multiple conventions, or to adding conventional routes that are dedicated to a specific action, such as:
<a name="dcr"></a>
The blog route in the preceding code is a dedicated conventional route. It's a dedicated conventional route because:
Because the route template "blog/{*article}" doesn't include controller and action as parameters:
{ controller = "Blog", action = "Article" }.BlogController.Article./Blog, /Blog/Article, and /Blog/{any-string} are the only URL paths that match the blog route.
In the preceding example:
blog route has a higher priority for matches than the default route because you add it first.[!WARNING] In ASP.NET Core 3.0 or later, routing doesn't:
- Define a concept called a route.
UseRoutingadds route matching to the middleware pipeline. TheUseRoutingmiddleware looks at the set of endpoints defined in the app, and selects the best endpoint match based on the request.- Provide guarantees about the execution order of extensibility like xref:Microsoft.AspNetCore.Routing.IRouteConstraint or xref:Microsoft.AspNetCore.Mvc.ActionConstraints.IActionConstraint.
See Routing for reference material on routing.
<a name="cro"></a>
Conventional routing only matches a combination of action and controller that the app defines. This approach simplifies cases where conventional routes overlap.
When you add routes by using xref:Microsoft.AspNetCore.Builder.ControllerEndpointRouteBuilderExtensions.MapControllerRoute%2A, xref:Microsoft.AspNetCore.Builder.ControllerEndpointRouteBuilderExtensions.MapDefaultControllerRoute%2A, and xref:Microsoft.AspNetCore.Builder.ControllerEndpointRouteBuilderExtensions.MapAreaControllerRoute%2A, the endpoints automatically get an order value based on the order you invoke these methods. Matches from a route that appears earlier in the list have a higher priority. Conventional routing depends on order. In general, place routes with areas earlier because they're more specific than routes without an area. Dedicated conventional routes with catch-all route parameters, such as {*article}, can make a route too greedy. A greedy route matches URLs that you intended to be matched by other routes. Put the greedy routes later in the route table to prevent greedy matches.
<a name="best"></a>
When two endpoints match through routing, routing must do one of the following steps:
For example:
The preceding controller defines two actions that match:
/Products33/Edit/17{ controller = Products33, action = Edit, id = 17 }.This is a typical pattern for MVC controllers:
Edit(int) displays a form to edit a product.Edit(int, Product) processes the posted form.To resolve the correct route:
Edit(int, Product) is selected when the request is an HTTP POST.Edit(int) is selected when the HTTP verb is anything else. Edit(int) is generally called via GET.The xref:Microsoft.AspNetCore.Mvc.HttpPostAttribute, [HttpPost], is provided to routing so that it can choose based on the HTTP method of the request. The HttpPostAttribute makes Edit(int, Product) a better match than Edit(int).
It's important to understand the role of attributes like HttpPostAttribute. Similar attributes are defined for other HTTP verbs. In conventional routing, it's common for actions to use the same action name when they're part of a show form, submit form workflow. For example, see Examine the two Edit action methods.
If routing can't choose the best candidate, it throws an xref:System.Reflection.AmbiguousMatchException and lists the multiple matched endpoints.
<a name="routing-route-name-ref-label"></a>
The strings "blog" and "default" in the following examples are conventional route names:
The route names give the route a logical name. The named route can be used for URL generation. Using a named route simplifies URL creation when the ordering of routes could make URL generation complicated. Route names must be unique application wide.
Route names:
The route name concept is represented in routing as IEndpointNameMetadata. The terms route name and endpoint name:
<a name="attribute-routing-ref-label"></a> <a name="ar"></a>
REST APIs should use attribute routing to model the app's functionality as a set of resources where operations are represented by HTTP verbs.
Attribute routing uses a set of attributes to map actions directly to route templates. The following StartUp.Configure code is typical for a REST API and is used in the next sample:
In the preceding code, xref:Microsoft.AspNetCore.Builder.ControllerEndpointRouteBuilderExtensions.MapControllers%2A is called inside UseEndpoints to map attribute routed controllers.
In the following example:
HomeController matches a set of URLs similar to what the default conventional route {controller=Home}/{action=Index}/{id?} matches.The HomeController.Index action runs for any of the URL paths /, /Home, /Home/Index, or /Home/Index/3.
This example highlights a key programming difference between attribute routing and conventional routing. Attribute routing requires more input to specify a route. The conventional default route handles routes more succinctly. However, attribute routing allows and requires precise control of which route templates apply to each action.
With attribute routing, the controller and action names play no part in which action is matched, unless token replacement is used. The following example matches the same URLs as the previous example:
The following code uses token replacement for action and controller:
The following code applies [Route("[controller]/[action]")] to the controller:
In the preceding code, the Index method templates must prepend / or ~/ to the route templates. Route templates applied to an action that begin with / or ~/ don't get combined with route templates applied to the controller.
See Route template precedence for information on route template selection.
The following keywords are reserved route parameter names when you use Controllers or Razor Pages:
actionareacontrollerhandlerpageUsing page as a route parameter with attribute routing is a common error. This choice results in inconsistent and confusing behavior with URL generation.
URL generation uses these special parameter names to determine if a URL generation operation refers to a Razor Page or to a Controller.
The following keywords are reserved in the context of a Razor view or a Razor Page:
pageusingnamespaceinjectsectioninheritsmodeladdTagHelperremoveTagHelperDon't use these keywords for link generations, model bound parameters, or top level properties.
<a name="verb"></a>
ASP.NET Core includes the following HTTP verb templates:
<a name="rt"></a>
ASP.NET Core includes the following route templates:
<a name="arx"></a>
Consider the following controller:
In the preceding code:
[HttpGet] attribute, which constrains matching to HTTP GET requests only.GetProduct action includes the "{id}" template, so the id appends to the "api/[controller]" template on the controller. The method's template is "api/[controller]/{id}". Therefore this action only matches GET requests for the form /api/test2/xyz, /api/test2/123, /api/test2/{any string}, and so on.
[!code-csharp]GetIntProduct action contains the "int/{id:int}" template. The :int portion of the template constrains the id route values to strings that can be converted to an integer. A GET request to /api/test2/int/abc:
GetInt2Product action contains {id} in the template, but doesn't constrain id to values that can be converted to an integer. A GET request to /api/test2/int2/abc:
abc to an integer. The id parameter of the method is integer.abc to an integer.
[!code-csharp]Attribute routing can use xref:Microsoft.AspNetCore.Mvc.Routing.HttpMethodAttribute attributes such as xref:Microsoft.AspNetCore.Mvc.HttpPostAttribute, xref:Microsoft.AspNetCore.Mvc.HttpPutAttribute, and xref:Microsoft.AspNetCore.Mvc.HttpDeleteAttribute. All of the HTTP verb attributes accept a route template. The following example shows two actions that match the same route template:
Using the URL path /products3:
MyProductsController.ListProducts action runs when the HTTP verb is GET.MyProductsController.CreateProduct action runs when the HTTP verb is POST.When building a REST API, it's rare that you'll need to use [Route(...)] on an action method because the action accepts all HTTP methods. It's better to use the more specific HTTP verb attribute to be precise about what your API supports. Clients of REST APIs are expected to know what paths and HTTP verbs map to specific logical operations.
REST APIs should use attribute routing to model the app's functionality as a set of resources where operations are represented by HTTP verbs. This design means that many operations, such as GET and POST on the same logical resource, use the same URL. Attribute routing provides the level of control needed to carefully design an API's public endpoint layout.
Since an attribute route applies to a specific action, it's easy to make parameters required as part of the route template definition. In the following example, id is required as part of the URL path:
The Products2ApiController.GetProduct(int) action:
/products2/3/products2.The [Consumes] attribute allows an action to limit the supported request content types. For more information, see Define supported request content types with the Consumes attribute.
See Routing for a full description of route templates and related options.
For more information on [ApiController], see ApiController attribute.
The following code defines a route name of Products_List:
Use route names to generate a URL based on a specific route. Route names:
Route names must be unique application-wide.
Contrast the preceding code with the conventional default route, which defines the id parameter as optional ({id?}). The ability to precisely specify APIs has advantages, such as allowing /products and /products/5 to be dispatched to different actions.
<a name="routing-combining-ref-label"></a>
To make attribute routing less repetitive, combine route attributes on the controller with route attributes on the individual actions. The route templates you define on the controller are prepended to route templates on the actions. When you place a route attribute on the controller, all actions in the controller use attribute routing.
In the preceding example:
/products can match ProductsApi.ListProducts/products/5 can match ProductsApi.GetProduct(int).Both of these actions only match HTTP GET because they're marked with the [HttpGet] attribute.
Route templates that you apply to an action and that begin with / or ~/ don't get combined with route templates that you apply to the controller. The following example matches a set of URL paths similar to the default route.
The following table explains the [Route] attributes in the preceding code:
| Attribute | Combines with [Route("Home")] | Defines route template |
|---|---|---|
[Route("")] | Yes | "Home" |
[Route("Index")] | Yes | "Home/Index" |
[Route("/")] | No | "" |
[Route("About")] | Yes | "Home/About" |
<a name="routing-ordering-ref-label"></a> <a name="oar"></a>
Routing builds a tree and matches all endpoints simultaneously:
For example, an attribute route like blog/search/{topic} is more specific than an attribute route like blog/{*article}. The blog/search/{topic} route has higher priority, by default, because it's more specific. Using conventional routing, the developer is responsible for placing routes in the desired order.
Attribute routes can configure an order using the xref:Microsoft.AspNetCore.Mvc.RouteAttribute.Order property. All of the framework provided route attributes include Order . Routes are processed according to an ascending sort of the Order property. The default order is 0. Setting a route using Order = -1 runs before routes that don't set an order. Setting a route using Order = 1 runs after default route ordering.
Avoid depending on Order. If an app's URL-space requires explicit order values to route correctly, then it's likely confusing to clients as well. In general, attribute routing selects the correct route with URL matching. If the default order used for URL generation isn't working, using a route name as an override is usually simpler than applying the Order property.
Consider the following two controllers which both define the route matching /home:
Requesting /home by using the preceding code throws an exception similar to the following:
AmbiguousMatchException: The request matched multiple endpoints. Matches:
WebMvcRouting.Controllers.HomeController.Index
WebMvcRouting.Controllers.MyDemoController.MyIndex
Adding Order to one of the route attributes resolves the ambiguity:
[!code-csharp[](routing/samples/3.x/main/Controllers/MyDemo3Controller.cs?name=snippet3& highlight=2)]
With the preceding code, /home runs the HomeController.Index endpoint. To get to the MyDemoController.MyIndex, request /home/MyIndex. Note:
Order property.Order property only resolves the ambiguity. That template cannot be matched. It's better to remove the [Route("Home")] template.For information on route order with Razor Pages, see Razor Pages route and app conventions: Route order.
In some cases, an HTTP 500 error is returned with ambiguous routes. Use logging to see which endpoints caused the AmbiguousMatchException.
<a name="routing-token-replacement-templates-ref-label"></a>
For convenience, attribute routes support token replacement by enclosing a token in square brackets ([, ]). The tokens [action], [area], and [controller] are replaced with the values of the action name, area name, and controller name from the action where you define the route:
In the preceding code:
/Products0/List/Products0/Edit/{id}Token replacement happens as the last step of building the attribute routes. The preceding example behaves the same as the following code:
You can also combine attribute routes with inheritance. This combination is powerful when you use token replacement. Token replacement also applies to route names defined by attribute routes.
[Route("[controller]/[action]", Name="[controller]_[action]")]generates a unique route name for each action:
To match the literal token replacement delimiter [ or ], escape it by repeating the character ([[ or ]]).
<a name="routing-token-replacement-transformers-ref-label"></a>
You can customize token replacement by using a parameter transformer. A parameter transformer implements xref:Microsoft.AspNetCore.Routing.IOutboundParameterTransformer and transforms the value of parameters. For example, a custom SlugifyParameterTransformer parameter transformer changes the SubscriptionManagement route value to subscription-management:
The xref:Microsoft.AspNetCore.Mvc.ApplicationModels.RouteTokenTransformerConvention is an application model convention that:
The preceding ListAll method matches /subscription-management/list-all.
The RouteTokenTransformerConvention is registered as an option in ConfigureServices.
For the definition of slug, see MDN web docs on Slug.
[!INCLUDE] <a name="routing-multiple-routes-ref-label"></a>
Attribute routing supports defining multiple routes that reach the same action. The most common usage of this is to mimic the behavior of the default conventional route as shown in the following example:
Putting multiple route attributes on the controller means that each one combines with each of the route attributes on the action methods:
All the HTTP verb route constraints implement IActionConstraint.
When multiple route attributes that implement xref:Microsoft.AspNetCore.Mvc.ActionConstraints.IActionConstraint are placed on an action:
Using multiple routes on actions might seem useful and powerful, it's better to keep your app's URL space basic and well defined. Use multiple routes on actions only where needed, for example, to support existing clients.
<a name="routing-attr-options"></a>
Attribute routes support the same inline syntax as conventional routes to specify optional parameters, default values, and constraints.
In the preceding code, [HttpPost("product14/{id:int}")] applies a route constraint. The Products14Controller.ShowProduct action is matched only by URL paths like /product14/3. The route template portion {id:int} constrains that segment to only integers.
For a detailed description of route template syntax, see Route Template Reference.
<a name="routing-cust-rt-attr-irt-ref-label"></a>
All of the route attributes implement xref:Microsoft.AspNetCore.Mvc.Routing.IRouteTemplateProvider. The ASP.NET Core runtime:
IRouteTemplateProvider to build the initial set of routes.Implement IRouteTemplateProvider to define custom route attributes. Each IRouteTemplateProvider allows you to define a single route with a custom route template, order, and name:
The preceding Get method returns Order = 2, Template = api/MyTestApi.
<a name="routing-app-model-ref-label"></a>
The application model:
The application model includes all of the data gathered from route attributes. The data from route attributes is provided by the IRouteTemplateProvider implementation. Conventions:
This section shows a basic example of customizing routing by using the application model. The following code makes routes roughly line up with the folder structure of the project.
The following code prevents the namespace convention from being applied to controllers that are attribute routed:
For example, the following controller doesn't use NamespaceRoutingConvention:
The NamespaceRoutingConvention.Apply method:
namespace, with the base namespace removed.The NamespaceRoutingConvention can be applied in Startup.ConfigureServices:
For example, consider the following controller:
In the preceding code:
namespace is My.Application.My.Application.Admin.Controllers.UsersController.NamespaceRoutingConvention sets the controllers template to Admin/Controllers/Users/[action]/{id?.The NamespaceRoutingConvention can also be applied as an attribute on a controller:
<a name="routing-mixed-ref-label"></a>
ASP.NET Core apps can mix the use of conventional routing and attribute routing. Typically, you use conventional routes for controllers that serve HTML pages to browsers, and attribute routing for controllers that serve REST APIs.
Actions are either conventionally routed or attribute routed. Placing a route on the controller or the action makes it attribute routed. Actions that define attribute routes cannot be reached through the conventional routes and vice-versa. Any route attribute on the controller makes all actions in the controller attribute routed.
Attribute routing and conventional routing use the same routing engine.
<a name="routing-url-gen-ref-label"></a> <a name="ambient"></a>
Apps can use routing URL generation features to generate URL links to actions. Generating URLs eliminates hardcoding URLs, making code more robust and maintainable. This section focuses on the URL generation features provided by MVC and only cover basics of how URL generation works. See Routing for a detailed description of URL generation.
The xref:Microsoft.AspNetCore.Mvc.IUrlHelper interface is the underlying element of infrastructure between MVC and routing for URL generation. An instance of IUrlHelper is available through the Url property in controllers, views, and view components.
In the following example, the IUrlHelper interface is used through the Controller.Url property to generate a URL to another action.
If the app uses the default conventional route, the value of the url variable is the URL path string /UrlGeneration/Destination. Routing creates this URL path by combining:
Url.Action and substituting those values into the route template:ambient values: { controller = "UrlGeneration", action = "Source" }
values passed to Url.Action: { controller = "UrlGeneration", action = "Destination" }
route template: {controller}/{action}/{id?}
result: /UrlGeneration/Destination
Each route parameter in the route template has its value substituted by matching names with the values and ambient values. A route parameter that doesn't have a value can:
id from the route template {controller}/{action}/{id?}.URL generation fails if any required route parameter doesn't have a corresponding value. If URL generation fails for a route, the next route is tried until all routes have been tried or a match is found.
The preceding example of Url.Action assumes conventional routing. URL generation works similarly with attribute routing, though the concepts are different. With conventional routing:
controller and action usually appear in that template. This works because the URLs matched by routing adhere to a convention.The following example uses attribute routing:
The Source action in the preceding code generates custom/url/to/destination.
xref:Microsoft.AspNetCore.Routing.LinkGenerator was added in ASP.NET Core 3.0 as an alternative to IUrlHelper. LinkGenerator offers similar but more flexible functionality. Each method on IUrlHelper has a corresponding family of methods on LinkGenerator as well.
Url.Action, LinkGenerator.GetPathByAction, and all related overloads all are designed to generate the target endpoint by specifying a controller name and action name.
When you use Url.Action, the runtime provides the current route values for controller and action:
controller and action are part of both ambient values and values. The method Url.Action always uses the current values of action and controller and generates a URL path that routes to the current action.Routing attempts to use the values in ambient values to fill in information that wasn't provided when generating a URL. Consider a route like {a}/{b}/{c}/{d} with ambient values { a = Alice, b = Bob, c = Carol, d = David }:
If the value { d = Donovan } is added:
{ d = David } is ignored.Alice/Bob/Carol/Donovan.Warning: URL paths are hierarchical. In the preceding example, if the value { c = Cheryl } is added:
{ c = Carol, d = David } are ignored.d and URL generation fails.c and d to generate a URL.You might expect to hit this problem with the default route {controller}/{action}/{id?}. This problem is rare in practice because Url.Action always explicitly specifies a controller and action value.
Several overloads of Url.Action take a route values object to provide values for route parameters other than controller and action. The route values object is frequently used with id. For example, Url.Action("Buy", "Products", new { id = 17 }). The route values object:
IDictionary<> or a POCO).Any additional route values that don't match route parameters go in the query string.
The preceding code generates /Products/Buy/17?color=red.
The following code generates an absolute URL:
To create an absolute URL, use one of the following options:
protocol. For example, the preceding code.<a name="routing-gen-urls-route-ref-label"></a>
The preceding code demonstrated generating a URL by passing in the controller and action name. IUrlHelper also provides the Url.RouteUrl family of methods. These methods are similar to Url.Action, but they don't copy the current values of action and controller to the route values. The most common usage of Url.RouteUrl:
The following Razor file generates an HTML link to the Destination_Route:
<a name="routing-gen-urls-html-ref-label"></a>
xref:Microsoft.AspNetCore.Mvc.Rendering.IHtmlHelper provides the xref:Microsoft.AspNetCore.Mvc.ViewFeatures.HtmlHelper methods Html.BeginForm and Html.ActionLink to generate <form> and <a> elements respectively. These methods use the Url.Action method to generate a URL and they accept similar arguments. The Url.RouteUrl companions for HtmlHelper are Html.BeginRouteForm and Html.RouteLink which have similar functionality.
TagHelpers generate URLs through the form TagHelper and the <a> TagHelper. Both of these use IUrlHelper for their implementation. For more information, see Tag Helpers in forms.
Inside views, the IUrlHelper is available through the Url property for any ad-hoc URL generation not covered by the preceding methods.
<a name="routing-gen-urls-action-ref-label"></a>
The preceding examples show how to use IUrlHelper in a controller. The most common usage in a controller is to generate a URL as part of an action result.
The xref:Microsoft.AspNetCore.Mvc.ControllerBase and xref:Microsoft.AspNetCore.Mvc.Controller base classes provide convenience methods for action results that reference another action. One typical usage is to redirect after accepting user input:
The action results factory methods such as xref:Microsoft.AspNetCore.Mvc.ControllerBase.RedirectToAction%2A and xref:Microsoft.AspNetCore.Mvc.ControllerBase.CreatedAtAction%2A follow a similar pattern to the methods on IUrlHelper.
<a name="routing-dedicated-ref-label"></a>
Conventional routing can use a special kind of route definition called a dedicated conventional route. In the following example, the route named blog is a dedicated conventional route:
Using the preceding route definitions, Url.Action("Index", "Home") generates the URL path / by using the default route, but why? You might guess the route values { controller = Home, action = Index } are enough to generate a URL by using blog, and the result would be /blog?action=Index&controller=Home.
Dedicated conventional routes rely on a special behavior of default values that don't have a corresponding route parameter that prevents the route from being too greedy with URL generation. In this case the default values are { controller = Blog, action = Article }, and neither controller nor action appears as a route parameter. When routing performs URL generation, the values provided must match the default values. URL generation using blog fails because the values { controller = Home, action = Index } don't match { controller = Blog, action = Article }. Routing then falls back to try default, which succeeds.
<a name="routing-areas-ref-label"></a>
Areas are an MVC feature used to organize related functionality into a group as a separate:
Using areas allows an app to have multiple controllers with the same name, as long as they have different areas. Using areas creates a hierarchy for the purpose of routing by adding another route parameter, area to controller and action. This section discusses how routing interacts with areas. See Areas for details about how areas are used with views.
The following example configures MVC to use the default conventional route and an area route for an area named Blog:
In the preceding code, xref:Microsoft.AspNetCore.Builder.ControllerEndpointRouteBuilderExtensions.MapAreaControllerRoute%2A is called to create the "blog_route". The second parameter, "Blog", is the area name.
When matching a URL path like /Manage/Users/AddUser, the "blog_route" route generates the route values { area = Blog, controller = Users, action = AddUser }. The area route value comes from a default value for area. The route created by MapAreaControllerRoute is equivalent to the following code:
MapAreaControllerRoute creates a route using both a default value and constraint for area by using the provided area name, in this case Blog. The default value ensures that the route always produces { area = Blog, ... }, and the constraint requires the value { area = Blog, ... } for URL generation.
Conventional routing is order-dependent. In general, place routes with areas earlier as they're more specific than routes without an area.
Using the preceding example, the route values { area = Blog, controller = Users, action = AddUser } match the following action:
The [Area] attribute is what denotes a controller as part of an area. This controller is in the Blog area. Controllers without an [Area] attribute aren't members of any area, and don't match when the area route value is provided by routing. In the following example, only the first controller listed can match the route values { area = Blog, controller = Users, action = AddUser }.
For completeness, the namespace of each controller is shown here. If the preceding controllers used the same namespace, a compiler error would be generated. Class namespaces have no effect on MVC's routing.
The first two controllers are members of areas, and only match when their respective area name is provided by the area route value. The third controller isn't a member of any area, and can only match when no value for area is provided by routing.
<a name="aa"></a>
In terms of matching no value, the absence of the area value is the same as if the value for area were null or the empty string.
When executing an action inside an area, the route value for area is available as an ambient value for routing to use for URL generation. This means that by default areas act sticky for URL generation as demonstrated by the following sample.
The following code generates a URL to /Zebra/Users/AddUser:
<a name="action"></a>
Public methods on a controller, except those with the NonAction attribute, are actions.
:::moniker-end