Apariencia
Qué API debe usar cada consumidor
La biblioteca tiene una superficie cotidiana y una superficie de extensión. Ambas llegan al mismo evaluador, pero no requieren el mismo conocimiento. Empieza por la primera y pasa a la segunda cuando el problema lo exija.
Validación cotidiana
Para un formulario o un candidato de aplicación, normalmente basta con conocer:
csharp
Validation.For<T>()
Validation.For<T, TContext>()
Field(...)
Required(...)
Email(...)
Must(...)
MustAsync(...)
Sequence(...)
Build()
Validate(...) / ValidateAsync(...)
ValidationReportEjemplo:
csharp
var plan = Validation.For<Customer, CustomerContext>()
.Field(x => x.Email, field => field.Sequence(sequence => sequence
.Required("El correo es obligatorio.")
.Email("El correo no es válido.")
.MustAsync((email, context, token) => context.IsAvailableAsync(email!, token),
"El correo ya está registrado.")))
.Build();
var report = await plan.ValidateAsync(customer, context);El consumidor solo decide tres cosas: qué campo validar, qué orden necesita y qué mensaje mostrar. El builder genera identidades internas y los diagnósticos reciben códigos predeterminados, que pueden fijarse con el parámetro code.
Reglas reutilizables
Usa ValidationRule.For, ForAsync, WithEvidence o WithEvidenceAsync cuando una regla:
- aparece en más de un plan;
- necesita una identidad lógica reutilizable además del código público;
- necesita evidencia tipada para el mensaje;
- pertenece a un catálogo de reglas de la aplicación o del dominio;
- debe recibir un contexto propio.
csharp
public static class CustomerRules
{
public static ValidationDefinition<string?, CustomerContext> UniqueEmail { get; } =
ValidationRule.ForAsync<string?, CustomerContext>(
"email.unique",
(email, context, token) => context.IsAvailableAsync(email!, token),
"customer.email.duplicate",
"El correo ya está registrado.");
}Después se incorpora con .Add(CustomerRules.UniqueEmail) dentro de una secuencia. La secuencia establece la dependencia; la definición no captura el contexto de un formulario concreto.
Contratos para autores de reglas
Implementa IRule<T> cuando quieres publicar una condición síncrona reutilizable en platform.rules. Implementa IAsyncRule<T> para una condición asíncrona sin contexto y IContextRule<T, C> para una condición asíncrona que recibe contexto por ejecución.
Puedes pasar IRule<T> directamente a ValidationRule.For. IAsyncRule<T> e IContextRule<T, C> se pasan a ValidationRule.ForAsync. El consumidor no necesita construir RuleDefinition manualmente.
Motor avanzado
Usa directamente RuleDefinition, RuleNode, RuleTree, RuleEvaluator y RuleEvaluationOptions cuando necesites:
- construir árboles fuera del builder fluido;
- inspeccionar estados
Skippedy razones de omisión; - conservar una traza completa;
- adaptar una composición a otra infraestructura;
- controlar identidades de aparición de forma explícita.
El motor avanzado produce RuleEvaluation, que es neutral y no contiene mensajes. Para una API de aplicación, suele ser más conveniente construir un ValidationPlan, porque este asocia diagnósticos y devuelve ValidationReport.
Formularios
Añade FormValidationSession<T, C> cuando necesites debounce, cancelación o publicación en un hilo de UI. No hace falta usarla para validar una petición única en un endpoint.
Usa Options y OptionsSession para cargar opciones dependientes. La sesión de opciones carga datos; las reglas del plan siguen siendo responsables de verificar que la selección sea válida.
Regla de decisión
| Pregunta | API |
|---|---|
| ¿Solo necesito un booleano? | IRule<T> o IAsyncRule<T> |
| ¿Necesito mensaje y código? | ValidationRule |
| ¿Necesito componer campos? | ValidationBuilder |
| ¿Necesito consultar un servicio? | Validation.For<T, C>() y MustAsync |
| ¿Necesito evidencia para el mensaje? | WithEvidence |
| ¿Necesito proteger una consulta con reglas previas? | Sequence |
| ¿Necesito una evaluación para la UI? | FormValidationSession |
| ¿Necesito conocer cada nodo ejecutado? | RuleEvaluator con Trace |
Los tipos avanzados siguen siendo públicos para permitir extensiones, pero no forman parte del primer recorrido de aprendizaje.