Enrutamiento y verbos
En ASP.NET MVC, el enrutamiento de un controlador permite mapear las solicitudes HTTP a acciones específicas en los controladores. Esto se puede configurar de diversas maneras, ya sea a través de convenciones de enrutamiento en el archivo Startup.cs
o mediante atributos directamente en los controladores y acciones. Vamos a explorar las diferentes maneras de enrutar un controlador y sus acciones, así como los verbos HTTP.
1. Convenciones de Enrutamiento en Startup.cs
El enrutamiento por convenciones se configura típicamente en Startup.cs
y sigue la convención /{controller}/{action}/{id?}
, que es el valor predeterminado en ASP.NET Core MVC.
Ejemplo
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
app.UseRouting();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}"); // controlador, acción e id opcional
});
}
{controller=Home}
: Si no se especifica un controlador, usa el controladorHome
.{action=Index}
: Si no se especifica una acción, usa la acciónIndex
.{id?}
: Elid
es opcional y se pasará como parámetro.
Con esta convención, una URL como /Product/Details/5
llamará a la acción Details
en el controlador Product
con id = 5
.
2. Enrutamiento mediante Atributos (Attribute Routing)
El enrutamiento por atributos permite definir rutas directamente en los controladores y acciones, proporcionando un control más fino.
Ejemplo
[Route("productos")] // Base del controlador
public class ProductController : Controller
{
[Route("")] // GET /productos
[HttpGet]
public IActionResult Index()
{
return View();
}
[Route("detalle/{id:int}")] // GET /productos/detalle/5
[HttpGet]
public IActionResult Details(int id)
{
return View();
}
[Route("editar/{id:int}")] // GET /productos/editar/5
[HttpGet]
public IActionResult Edit(int id)
{
return View();
}
[Route("editar/{id:int}")] // POST /productos/editar/5
[HttpPost]
public IActionResult Edit(int id, Product product)
{
// lógica para actualizar el producto
return RedirectToAction("Index");
}
}
[Route("productos")]
: Cambia la URL base del controladorProductController
a/productos
.[Route("detalle/{id:int}")]
: Define una ruta específica que acepta un parámetroid
entero.
3. Uso de Verbos HTTP
Cada acción puede estar decorada con un atributo de verbo HTTP para definir a qué tipo de solicitud responde ([HttpGet]
, [HttpPost]
, [HttpPut]
, [HttpDelete]
, etc.).
Ejemplo
[Route("api/orders")]
public class OrdersController : Controller
{
[HttpGet] // GET /api/orders
public IActionResult GetOrders()
{
// Retorna todos los pedidos
return Ok(new List<Order>());
}
[HttpGet("{id:int}")] // GET /api/orders/5
public IActionResult GetOrder(int id)
{
// Retorna el pedido con ID especificado
return Ok(new Order { Id = id });
}
[HttpPost] // POST /api/orders
public IActionResult CreateOrder([FromBody] Order newOrder)
{
// Crea un nuevo pedido
return CreatedAtAction(nameof(GetOrder), new { id = newOrder.Id }, newOrder);
}
[HttpPut("{id:int}")] // PUT /api/orders/5
public IActionResult UpdateOrder(int id, [FromBody] Order updatedOrder)
{
// Actualiza el pedido
return NoContent();
}
[HttpDelete("{id:int}")] // DELETE /api/orders/5
public IActionResult DeleteOrder(int id)
{
// Elimina el pedido
return NoContent();
}
}
Resumen:
[HttpGet]
: Para acciones de obtención de datos.[HttpPost]
: Para crear datos.[HttpPut]
: Para actualizar datos.[HttpDelete]
: Para eliminar datos.
4. Parámetros en la Ruta
Puedes definir rutas con parámetros opcionales o específicos de tipo, lo cual facilita el control de las rutas y los datos.
Ejemplo de parámetros opcionales y restricción de tipos
[Route("clientes")]
public class ClienteController : Controller
{
// Ruta con parámetro opcional
[Route("{id:int?}")] // GET /clientes o GET /clientes/5
[HttpGet]
public IActionResult Index(int? id)
{
return id.HasValue ? View("Detail", id.Value) : View("List");
}
// Ruta con restricción de tipo string
[Route("buscar/{nombre:alpha}")] // GET /clientes/buscar/jose
[HttpGet]
public IActionResult SearchByName(string nombre)
{
return View("SearchResults", nombre);
}
}
5. Default, Optional, y Catch-All Segments
Los segmentos predeterminados (default
), opcionales ({param?}
), y el “catch-all” (*
o **
) permiten configurar rutas flexibles que admiten URL de estructura variable.
Ejemplo
[Route("articulos")]
public class ArticleController : Controller
{
[Route("{categoria=general}")] // GET /articulos o GET /articulos/tecnologia
public IActionResult Category(string categoria)
{
return View(categoria);
}
[Route("archivos/{*pathInfo}")] // GET /articulos/archivos/folder/subfolder/file
public IActionResult Files(string pathInfo)
{
return Content($"Archivo solicitado: {pathInfo}");
}
}
Notas:
{categoria=general}
: Si no se pasa un valor paracategoria
, se usageneral
.{*pathInfo}
: Captura todo el contenido adicional en la URL.
6. Agrupación de Rutas y Prefijos
ASP.NET Core permite agrupar rutas en una clase base o en un controlador con [Route("base") + [Route("...")]
para simplificar la estructura.
Ejemplo
[Route("api/[controller]")]
public class ProductosController : Controller
{
[HttpGet]
public IActionResult GetAll() => Ok(new List<Product>());
[HttpGet("{id:int}")]
public IActionResult GetById(int id) => Ok(new Product { Id = id });
}
En este caso, api/[controller]
se reemplaza automáticamente con api/productos
en el controlador ProductosController
.
7. Combinación de Atributos y Convenciones
Puedes combinar atributos con el enrutamiento por convenciones en Startup.cs
. El enrutamiento por atributos puede tener precedencia si está habilitado en UseEndpoints
.
public void Configure(IApplicationBuilder app)
{
app.UseRouting();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
endpoints.MapControllerRoute("default", "{controller=Home}/{action=Index}/{id?}");
});
}
Estas opciones de enrutamiento en ASP.NET MVC permiten definir las rutas con flexibilidad, ya sea desde Startup.cs
mediante convenciones, o en los propios controladores usando atributos. Esto es útil tanto para aplicaciones grandes y complejas como para aplicaciones que requieren rutas simplificadas y específicas.