Skip to main content

Command Palette

Search for a command to run...

ASP.Net Core: Routing - Controller pattern

Updated
•3 min read•View as Markdown

In the Controller Pattern, routing is primarily handled via Attributes directly on your classes and methods. This is the standard for Web APIs because it provides precise control over URL structures.

Here is the complete list of ways you can configure routing in the Controller pattern:

1. Attribute Routing (The API Standard)

This is the most common method. You define the URL path directly above the code that handles it.

  • Fixed Paths: Defining static route names.

      [Route("api/users")]
      public class UsersController : ControllerBase { ... }
    
  • Token Replacement: Using [controller] and [action] placeholders. The framework automatically fills these in based on the class/method name.

      [Route("api/[controller]")] // Becomes "api/Products"
      public class ProductsController : ControllerBase { ... }
    
  • Http Verb Templates: Combining the HTTP method and the route in one attribute.

      [HttpGet("details")] // Matches "api/[controller]/details"
      public IActionResult GetDetails() { ... }
    
  • Route Parameters: capturing dynamic values from the URL.

      [HttpGet("{id}")] // Matches "api/users/5"
      public IActionResult GetById(int id) { ... }
    
  • Route Constraints: Enforcing data types inline. If the data type doesn't match, the route is skipped (404).

      [HttpGet("{id:int}")] // Only matches if 'id' is an integer
      [HttpGet("{slug:minlength(5)}")] // Only matches if string is 5+ chars
    
  • Catch-All (Wildcards): Capturing the remainder of a URL path.

      [HttpGet("files/{*filePath}")] // Matches "files/images/logo.png"
    

2. Convention-Based Routing (Global/MVC Style)

This is rarely used for pure APIs but is the default for MVC apps serving Views. Instead of attributes on every controller, you define one global rule in Program.cs.

  • Global Route Map:

      // In Program.cs
      app.MapControllerRoute(
          name: "default",
          pattern: "{controller=Home}/{action=Index}/{id?}");
    
    • Effect: A method named Index in HomeController is automatically accessible at /Home/Index without any attributes.

3. Advanced Configuration

  • Route Order: Resolving conflicts when two routes match the same URL. Lower numbers run first.

      [HttpGet("{id:int}", Order = 1)] // Tried first
      [HttpGet("{name}", Order = 2)]   // Tried second
    
  • Multiple Routes: assigning multiple URL paths to a single action.

      [HttpGet("products/latest")]
      [HttpGet("products/new")]
      public IActionResult GetNew() { ... }
    
  • Areas: Grouping a set of controllers under a common prefix (useful for large monoliths like Admin panels).

      [Area("Admin")]
      [Route("admin/[controller]")] // Matches "admin/users"
      public class UsersController : Controller { ... }
    

3. Inheritance Routing

If you have a Base Controller with a [Route] attribute, child controllers inherit that prefix automatically.

1. The Base Controller Define an abstract base class and put the "master" [Route] attribute there.

using Microsoft.AspNetCore.Mvc;

// 1. Define the Route on the Base Class
// This says: "Start with 'api/v1/' and then append the Controller's name"
[ApiController]
[Route("api/v1/[controller]")]
public abstract class BaseApiController : ControllerBase
{
    // You can also put shared logic here (like retrieving the current user ID)
}

2. The Child Controller Inherit from the base class. Do NOT add a [Route] attribute to this class. It will automatically use the one from the parent.

// 2. Inherit from the Base
// Notice: No [Route] attribute here! It inherits "api/v1/[controller]"
public class UsersController : BaseApiController
{
    // The final URL combines the Base Route + The Method Route
    // Base: "api/v1/Users"
    // Method: "" (Default)
    // Result: GET /api/v1/Users
    [HttpGet]
    public IActionResult GetAll()
    {
        return Ok("List of users");
    }

    // Result: GET /api/v1/Users/5
    [HttpGet("{id}")]
    public IActionResult GetById(int id)
    {
        return Ok($"User {id}");
    }
}

Important Rule: "Inherit or Override"

ASP.NET Core routing attributes generally do not stack (concatenate) if both classes have them.

  • Scenario A (Inheritance): Base has [Route], Child has none.

    • Result: Child uses Base's route. (Works as shown above).
  • Scenario B (Override): Base has [Route], Child also has [Route].

    • Result: Child ignores the Base completely and uses its own.

Example of Overriding:

// This Child ignores the "api/v1" from the base
// It sets its own completely new path
[Route("api/v2/products")] 
public class ProductsController : BaseApiController
{
    // URL is: /api/v2/products (NOT /api/v1/products)
}

More from this blog

.

.Net Core

32 posts