1. ¿Qué son?
Son etiquetas (Atributos) que colocas encima de las propiedades de tu DTO para definir las reglas del juego.
-
Filosofía: Validación Declarativa (dices qué quieres) en lugar de Imperativa (escribes cómo comprobarlo con
if). -
Objetivo: Garantizar que los datos basura nunca lleguen a tu Controlador ni a tu Base de Datos.
2. La Sintaxis (Ojo con los Records en .NET 10)
Como usamos public record (Constructores Primarios), aprendimos que no debemos usar el prefijo property: si queremos que la validación funcione tanto en el constructor como en el cuerpo.
Ejemplo Correcto (src/UserApi.Web/DTOs/UserDto.cs):
C#
using System.ComponentModel.DataAnnotations; // Namespace obligatorio
public record UserDto(
int Id,
// 1. REGLAS DE TEXTO
[Required(ErrorMessage = "El nombre es obligatorio")]
[StringLength(100, MinimumLength = 3, ErrorMessage = "Mínimo 3 letras")]
string FullName,
// 2. REGLAS DE FORMATO
[Required]
[EmailAddress(ErrorMessage = "Email inválido")]
string Email,
// 3. OTRAS COMUNES (Para que las tengas)
[Range(18, 99)] int Age,
[RegularExpression("^[0-9]*$")] string Phone
);
3. El “Portero de Discoteca”: [ApiController]
Tener las etiquetas en el DTO no sirve de nada si nadie las revisa.
El atributo [ApiController] que pusiste en tu UsersController es quien hace la magia.
-
Cómo funciona:
-
Llega la petición JSON.
-
.NET intenta meter los datos en el
UserDto. -
.NET comprueba si se cumplen las reglas (
[Required], etc.). -
Si falla alguna: .NET corta la ejecución inmediatamente.
-
Tu método
CreateUserNUNCA se llega a ejecutar. -
Devuelve automáticamente un 400 Bad Request.
-
Diferencia con PHP: No tienes que escribir
if ($validacion->fails()) { return error; }. El framework lo hace solo antes de llamarte.
4. La Respuesta Estándar (400)
Cuando la validación falla, .NET genera un JSON detallado (estándar RFC 7807) indicando exactamente qué campo falló y por qué.
JSON
{
"type": "https://tools.ietf.org/html/rfc9110#section-15.5.1",
"title": "One or more validation errors occurred.",
"status": 400,
"errors": {
"Email": [
"Email inválido"
],
"FullName": [
"Mínimo 3 letras"
]
}
}
5. ¿Qué atributos existen? (Tu caja de herramientas)
Los más usados que debes memorizar:
| Atributo | Qué hace |
|---|---|
[Required] | El campo no puede ser null ni vacío. |
[StringLength(max, MinimumLength=min)] | Limita el tamaño del texto. Vital para DB. |
[EmailAddress] | Valida formato de correo (con @ y dominio). |
[Range(min, max)] | Para números (ej: Edad, Precio). |
[RegularExpression("...")] | Para formatos complejos (DNI, Tarjetas, Teléfonos). |
[Compare("Password")] | Útil en registros para “Repetir contraseña”. |
[Url] | Valida que sea una dirección web válida. |
📝 Resumen Mental
“En .NET, la validación se define en el DTO (el contrato), no en el Controlador. Si el dato no cumple el contrato, el Controlador ni se molesta en recibirlo.”