Overview
MVC Controllers use Routing middleware to match a URL of an incoming request to and map them to actions.
Route templates are defined in Program.cs
, describe how URL paths are matched to actions, and are used to generate URLs for links which are typically returned in responses.
To Use Controllers
Call MapControllers
to map attribute routed Controllers.
Call MapControllerRoute
or MapAreaControllerRoute
to map both conventionally routed Controllers and attribute routed Controllers.
Conventional Routing
Conventional routing is typically used with Controllers and Views.
Creating
Conventional routes are typically created in one place in the application, like the middleware pipeline. The default conventional route:
app.MapControllerRoute(
name: "default", // The route's name
pattern: "{controller=Home}/{action=Index}/{id?}"); // The route template
The route name is used only for URL generation and has no impact on matching.
The convenience method app.MapDefaultControllerRoute()
replaces the above because it uses the DefaultControllerRoute
.
The DefaultControllerRoute
is very common: {controller=Home}/{action=Index}/{id?}
For a URL like /Products/Details/5
:
The route template tokenizes the route path as follows: { controller = Products, action = Details, id = 5 }
If the app has a controller named ProductsController
and an action named Details
, a match exists:
public class ProductsController : Controller
{
public IActionResult Details(int id) => ControllerContext.MyDisplayRouteInfo(id);
}
Tool to display route information: NuGet Gallery | Rick.Docs.Samples.RouteInfo 1.0.0.8
Multiple Conventional Routes
Add more calls to MapControllerRoute
or MapAreaControllerRoute
:
app.MapControllerRoute(name: "blog",
pattern: "blog/{*article}",
defaults: new { controller = "Blog", action = "Article" });
// Matches URL paths /Blog, /Blog/Article, /Blog/any-string
app.MapControllerRoute(name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
Conventional Routing Order
Conventional routing is order-dependent based on the order in which they are invoked. Routes with areas should be placed earlier as they are more specific. Greedy routes should be placed later in the definition.
Ambiguous Actions
When more than one action matches a route, the actions are ambiguous. Routing attempts to choose the best candidate. If it cannot, it will throw an AmbiguousMatchException
listing the multiple matched endpoints.
Attribute Routing
Attribute routes are applied to controllers and actions directly rather than in the middleware pipeline.
Attribute routing is used with REST APIs to model the app’s functionality as a set of resources represented by HTTP verbs.
It allows for precise control of which route templates apply to each action.
app.MapControllers()
is called in Program.cs
to map attribute routed controllers.
public class HomeController : Controller
{
[Route("")]
[Route("Home")]
[Route("Home/Index")]
[Route("Home/Index/{id?}")]
public IActionResult Index(int? id) => ControllerContext.MyDisplayRouteInfo(id);
[Route("Home/About")]
[Route("Home/About/{id?}")]
public IActionResult About(int? id) => ControllerContext.MyDisplayRouteInfo(id);
}
Token Replacement
Use token replacement attributes on actions to match URLs dynamically:
[Route("")]
[Route("Home")]
[Route("[controller]/[action]")]
public IActionResult Index() => ControllerContext.MyDisplayRouteInfo();
Or on classes:
[Route("[controller]/[action]")]
public class HomeController : Controller
{
// Route templates applied to an action that start with "/" or "~/" do not get combined with
// route templates applied to a controller:
[Route("~/")]
[Route("/Home")]
[Route("~/Home/Index")]
public IActionResult Index() => ControllerContext.MyDisplayRouteInfo();
}
HTTP Verb Templates
These are both HTTP verb templates and route templates:
[HttpGet]
[HttpPost]
[HttpPut]
[HttpDelete]
[HttpHead]
[HttpPatch]
Attribute Routing with HTTP Verb Attributes
Assuming:
[Route("api/[controller]")]
[ApiController]
public class Test2Controller : ControllerBase
{
[HttpGet] // GET /api/test2
public IActionResult ListProducts() => ControllerContext.MyDisplayRouteInfo();
// Because {id} is included here, id is appended to the template on the controller, so this action's template is api/[controller]/"{id}
[HttpGet("{id}")] // GET /api/test2/xyz
public IActionResult GetProduct(string id) => ControllerContext.MyDisplayRouteInfo(id);
// The :int portion of this template contstrains the id route values to strings that can be converted to integers.
[HttpGet("int/{id:int}")] // GET /api/test2/int/3
public IActionResult GetIntProduct(int id) => ControllerContext.MyDisplayRouteInfo(id);
// For /api/test2/int2/abc, model binding would fail and this would return HTTP/400 Bad Request
[HttpGet("int2/{id}")] // GET /api/test2/int2/3
public IActionResult GetInt2Product(int id) => ControllerContext.MyDisplayRouteInfo(id);
}
Here, for URL path /products3
, ListProducts
runs when the verb is GET; CreateProduct
runs when it is POST:
[HttpGet("/products3")]
public IActionResult ListProducts() => ControllerContext.MyDisplayRouteInfo();
[HttpPost("/products3")]
public IActionResult CreateProduct(MyProduct myProduct) => ControllerContext.MyDisplayRouteInfo(myProduct.Name);
Here, the id
attribute is required:
[HttpGet("/products2/{id}", Name = "Products_List")]
public IActionResult GetProduct(int id) => ControllerContext.MyDisplayRouteInfo(id);
Attribute Route Ordering
Attribute routes can configure an Order
property.
All framework-provided routes include Order
.
Setting Order = -1
runs the route before routes that don’t set an order.
Setting Order = 1
runs the route after default route ordering.