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?}: Elides 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 controladorProductControllera/productos.[Route("detalle/{id:int}")]: Define una ruta específica que acepta un parámetroidentero.
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.