ASP.NET Core 8 Web API -

Routing

Routing in ASP.NET Core 8 Web API is a critical aspect of building web applications. It determines how HTTP requests are mapped to specific actions within your controllers. This tutorial will cover routing in detail, including best practices, examples, demonstrations, explanations, and comparisons.


1. Introduction to Routing

Routing is the mechanism that ASP.NET Core uses to match incoming HTTP requests to corresponding actions in your controllers. The routing system in ASP.NET Core is flexible and supports various routing patterns.


2. Basic Routing

In ASP.NET Core, routing is configured in the Program.cs file using the MapControllers method:

        
            var builder = WebApplication.CreateBuilder(args);

builder.Services.AddControllers();

var app = builder.Build();

app.UseRouting();

app.MapControllers();

app.Run();
        
    

app.MapControllers(): This method is a shorthand that maps attribute-routed controllers. It's simpler and more straightforward for applications that use attribute routing exclusively. When app.MapControllers() is called, it automatically configures the endpoints based on the attributes defined in your controllers.


3. Alternative Routing Configuration

Another way to configure routing is by using the UseEndpoints method:

        
            var builder = WebApplication.CreateBuilder(args);

builder.Services.AddControllers();

var app = builder.Build();

app.UseRouting();

app.UseEndpoints(endpoints =>
{
    endpoints.MapControllers();
});

app.Run();
        
    

app.UseEndpoints(endpoints => { endpoints.MapControllers(); }): This method provides more flexibility and is part of the endpoint routing system introduced in ASP.NET Core 3.0. It allows you to configure multiple types of endpoints, not just controllers. This is useful if you need to add additional endpoints, such as those for SignalR, gRPC, or custom middleware.


4. Conventional Routing

Conventional routing uses predefined patterns to match URLs to controller actions. This is less flexible than attribute routing but can be simpler to set up for basic applications.

        
            var builder = WebApplication.CreateBuilder(args);

builder.Services.AddControllersWithViews();

var app = builder.Build();

app.UseRouting();

app.UseEndpoints(endpoints =>
{
    endpoints.MapControllerRoute(
        name: "default",
        pattern: "{controller=Home}/{action=Index}/{id?}");
});

app.Run();
        
    

5. Attribute Routing

Attribute routing uses attributes to define routes directly on controller actions:

        
            [ApiController]
[Route("api/[controller]")]
public class ProductsController : ControllerBase
{
    [HttpGet]
    public IActionResult GetAll()
    {
        // Retrieve all products
    }

    [HttpGet("{id}")]
    public IActionResult GetById(int id)
    {
        // Retrieve a product by ID
    }

    [HttpPost]
    public IActionResult Create(Product product)
    {
        // Create a new product
    }

    [HttpPut("{id}")]
    public IActionResult Update(int id, Product product)
    {
        // Update an existing product
    }

    [HttpDelete("{id}")]
    public IActionResult Delete(int id)
    {
        // Delete a product by ID
    }
}
        
    

6. Route Parameters

Route parameters can be used to pass data through the URL:

        
            [HttpGet("{category}/{id}")]
public IActionResult GetProductByCategory(string category, int id)
{
    // Retrieve a product by category and ID
}
        
    

7. Default and Optional Parameters

You can define default values and optional parameters in your routes:

        
            [HttpGet("{category}/{id?}")]
public IActionResult GetProductByCategory(string category, int? id)
{
    if (id.HasValue)
    {
        // Retrieve a specific product
    }
    else
    {
        // Retrieve all products in the category
    }
}
        
    

8. Constraints

Constraints can be added to routes to restrict the values that route parameters can take:

        
            [HttpGet("{id:int}")]
public IActionResult GetById(int id)
{
    // This route only matches if the ID is an integer
}

[HttpGet("{date:datetime}")]
public IActionResult GetByDate(DateTime date)
{
    // This route only matches if the date is in a valid datetime format
}
        
    

9. Route Prefixes

Route prefixes can be used to apply a common prefix to all routes in a controller:

        
            [ApiController]
[Route("api/products")]
public class ProductsController : ControllerBase
{
    [HttpGet]
    public IActionResult GetAll()
    {
        // Matches "api/products"
    }

    [HttpGet("{id}")]
    public IActionResult GetById(int id)
    {
        // Matches "api/products/{id}"
    }
}
        
    

10. Custom Route Templates

Custom route templates provide more control over the routing process:

        
            [HttpGet("category/{categoryName}/product/{productId}")]
public IActionResult GetProduct(string categoryName, int productId)
{
    // Retrieve a product by category name and product ID
}
        
    

11. Versioning

API versioning can be implemented using routes:

        
            [ApiVersion("1.0")]
[Route("api/v{version:apiVersion}/products")]
public class ProductsV1Controller : ControllerBase
{
    [HttpGet]
    public IActionResult GetAll()
    {
        // Matches "api/v1/products"
    }
}

[ApiVersion("2.0")]
[Route("api/v{version:apiVersion}/products")]
public class ProductsV2Controller : ControllerBase
{
    [HttpGet]
    public IActionResult GetAll()
    {
        // Matches "api/v2/products"
    }
}
        
    

12. Best Practices


13. Advanced Topics


Comparisons


15. Examples and Demonstrations

Example 1: Simple CRUD Operations
        
            [ApiController]
[Route("api/[controller]")]
public class OrdersController : ControllerBase
{
    [HttpGet]
    public IActionResult GetAll()
    {
        // Retrieve all orders
    }

    [HttpGet("{id}")]
    public IActionResult GetById(int id)
    {
        // Retrieve an order by ID
    }

    [HttpPost]
    public IActionResult Create(Order order)
    {
        // Create a new order
    }

    [HttpPut("{id}")]
    public IActionResult Update(int id, Order order)
    {
        // Update an existing order
    }

    [HttpDelete("{id}")]
    public IActionResult Delete(int id)
    {
        // Delete an order by ID
    }
}
        
    

Example 2: Route Prefixes and Custom Templates
        
            [ApiController]
[Route("api/orders")]
public class OrdersController : ControllerBase
{
    [HttpGet("customer/{customerId}")]
    public IActionResult GetByCustomer(int customerId)
    {
        // Retrieve orders by customer ID
    }

    [HttpGet("date/{orderDate:datetime}")]
    public IActionResult GetByDate(DateTime orderDate)
    {
        // Retrieve orders by date
    }
}
        
    

Example 3: Versioning
        
            [ApiVersion("1.0")]
[Route("api/v{version:apiVersion}/orders")]
public class OrdersV1Controller : ControllerBase
{
    [HttpGet]
    public IActionResult GetAll()
    {
        // Retrieve all orders for version 1.0
    }
}

[ApiVersion("2.0")]
[Route("api/v{version:apiVersion}/orders")]
public class OrdersV2Controller : ControllerBase
{
    [HttpGet]
    public IActionResult GetAll()
    {
        // Retrieve all orders for version 2.0
    }
}
        
    

Conclusion

Routing in ASP.NET Core 8 Web API is a powerful feature that allows you to define how HTTP requests map to your controller actions. By understanding and utilizing attribute routing, conventional routing, route parameters, constraints, prefixes, and versioning, you can create a robust and maintainable routing system for your web APIs. Following best practices and exploring advanced topics will further enhance your application's routing capabilities.