Routing is a fundamental concept in ASP.NET Core that enables the framework to map incoming HTTP requests to specific endpoints in your application. It plays a crucial role in defining how URLs are structured and how they correspond to the actions in your application. This article will provide a detailed overview of routing in ASP.NET Core, including its types, configuration, and examples.
What is Routing?
Routing is the process of directing an incoming HTTP request to the appropriate handler based on the URL and HTTP method. In ASP.NET Core, routing is handled by the middleware, which inspects the request and matches it against defined routes.
Which Middleware Handles Routing?
In ASP.NET Core, routing is handled by two key middleware components:
1. UseRouting() Middleware
- Purpose: Matches the incoming HTTP request to the route template (defined via MapControllerRoute, attribute routing, etc.).
- Placement: Must come before UseAuthorization() and UseEndpoints()
- Purpose: Executes the matched route handler (e.g., controller action, Razor page, minimal API).
- It finalizes the routing decision made by UseRouting().
Types of Routing
ASP.NET Core supports two main types of routing:
- Convention-based Routing: This is the default routing mechanism that uses predefined patterns to match incoming requests. It is typically used in MVC applications.
- Attribute Routing: This allows developers to define routes directly on the controller actions using attributes. This method provides more control and flexibility over the routing configuration.
- MapControllers(): Enables attribute routing ([Route("api/[controller]")])
- MapControllerRoute(): Enables convention-based routing (like {controller}/{action}/{id?})
Convention-Based Routing in ASP.NET Core
var builder = WebApplication.CreateBuilder(args); // Add services to the container builder.Services.AddControllersWithViews(); // For MVC builder.Services.AddControllers(); // For Web API var app = builder.Build(); // Configure the HTTP request pipeline if (!app.Environment.IsDevelopment()) { app.UseExceptionHandler("/Home/Error"); app.UseHsts(); } app.UseHttpsRedirection(); app.UseStaticFiles(); app.UseRouting(); app.UseAuthorization(); // Configure endpoints app.UseEndpoints(endpoints => { // MVC Routing endpoints.MapControllerRoute( name: "default", pattern: "{controller=Home}/{action=Index}/{id?}"); // API Routing (attribute routing will be used) endpoints.MapControllers(); }); app.Run();
- controller=Home: default controller
- action=Index: default action
- id?: optional parameter
public class ProductsController : Controller { public IActionResult Details(int id) { return View(); // Returns View for /products/details/5 } }
GET /products/details/5
{controller=Products}/{action=Details}/{id=5}
- Centralized route definitions
- Easier to manage in large MVC apps
- Reduces redundancy
- Less flexible for APIs
- It can become confusing with too many controllers/actions
Attribute Routing in ASP.NET Core
[Route("api/[controller]")] [ApiController] public class ProductsController : ControllerBase { [HttpGet] public IActionResult GetAll() { return Ok("All Products"); } [HttpGet("{id}")] public IActionResult GetById(int id) { return Ok($"Product {id}"); } [HttpPost] public IActionResult Create(Product product) { return Ok("Product Created"); } }
URL | Method | Action Called |
---|---|---|
GET /api/products |
[HttpGet] |
GetAll() |
GET /api/products/2 |
[HttpGet("{id}")] |
GetById(2) |
POST /api/products |
[HttpPost] |
Create() |
- Better suited for RESTful APIs
- Greater clarity and control per action
- Easy to document and maintain
How To Pass Multiple Values in a Request?
https://localhost:5001/api/products?category=electronics&sort=price
using Microsoft.AspNetCore.Mvc; using System.Collections.Generic; using System.Linq; [Route("api/[controller]")] [ApiController] public class ProductsController : ControllerBase { private static readonly List<Product> _products = new() { new Product(1, "Laptop", 999.99m, "electronics"), new Product(2, "Mouse", 25.50m, "accessories"), new Product(3, "Smartphone", 699.99m, "electronics") }; [HttpGet] public IActionResult Get([FromQuery] string category, [FromQuery] string sort) { var products = _products.AsQueryable(); if (!string.IsNullOrEmpty(category)) { products = products.Where(p => p.Category == category); } if (sort == "price") { products = products.OrderBy(p => p.Price); } return Ok(products.ToList()); } }
GET https://localhost:5001/api/products/electronics/1
using Microsoft.AspNetCore.Mvc; [Route("api/[controller]")] [ApiController] public class ProductsController : ControllerBase { // Sample data private static readonly List<Product> _products = new() { new Product(1, "Laptop", "electronics"), new Product(2, "Mouse", "accessories"), new Product(3, "Smartphone", "electronics") }; // Action method to get product by category and ID [HttpGet("{category}/{productId}")] public IActionResult GetProduct(string category, int productId) { var product = _products.FirstOrDefault(p => p.Id == productId && p.Category == category); if (product == null) { return NotFound(); } return Ok(product); } } public record Product(int Id, string Name, string Category);
{ "name": "Laptop", "price": 1500, "category": "Electronics" }
[HttpPost] public IActionResult AddProduct([FromBody] Product product) { // Access product.Name, product.Price, etc. return Ok($"Added: {product.Name}"); }
No comments:
Post a Comment