Nota:
El acceso a esta página requiere autorización. Puede intentar iniciar sesión o cambiar directorios.
El acceso a esta página requiere autorización. Puede intentar cambiar los directorios.
Sugerencia
Este contenido es un extracto del libro electrónico, ".NET Microservices Architecture for Containerized .NET Applications" (Arquitectura de microservicios de .NET para aplicaciones de .NET contenedorizadas), disponible en Documentación de .NET o como un PDF descargable y gratuito que se puede leer sin conexión.
En DDD, las reglas de validación se pueden considerar invariables. La responsabilidad principal de un agregado es aplicar invariantes a lo largo de los cambios de estado para todas las entidades dentro de ese agregado.
Las entidades de dominio siempre deben ser entidades válidas. Hay un número determinado de invariables para un objeto que siempre deben ser verdaderas. Por ejemplo, un objeto de artículo de pedido siempre tiene que tener una cantidad que debe ser un entero positivo, además de un nombre de artículo y un precio. Por lo tanto, la aplicación de invariantes es responsabilidad de las entidades de dominio (especialmente de la raíz agregada) y un objeto de entidad no debe poder existir sin ser válido. Las reglas invariables se expresan simplemente como contratos y se generan excepciones o notificaciones cuando se infringen.
El razonamiento detrás de esto es que muchos errores se producen porque los objetos están en un estado en el que nunca deberían haber estado.
Supongamos que ahora tenemos un servicio de envío de correos electrónicos de creación de usuarios que acepta un perfil de usuario... ¿cómo podemos justificar en ese servicio que el nombre no sea nulo? ¿Lo revisamos de nuevo? O más probable... no te molestas en comprobar y "esperar lo mejor": esperas que alguien se moleste en validarlo antes de enviarlo a ti. Por supuesto, al usar TDD, una de las primeras pruebas que deberíamos escribir es que, si envío un cliente con un nombre nulo, debería generar un error. Pero una vez que empezamos a escribir estos tipos de pruebas de nuevo, nos damos cuenta ... "¿Qué ocurre si nunca permitimos que el nombre se convierta en null? no tendríamos todas estas pruebas!".
Implementación de validaciones en la capa de modelo de dominio
Las validaciones normalmente se implementan en constructores de entidades de dominio o en métodos que pueden actualizar la entidad. Hay varias maneras de implementar validaciones, como comprobar los datos y generar excepciones si se produce un error en la validación. También hay patrones más avanzados, como el uso del patrón de especificación para las validaciones, y el patrón de notificación para devolver una colección de errores en lugar de devolver una excepción para cada validación a medida que se produce.
Validar las condiciones y lanzar excepciones
En el ejemplo de código siguiente se muestra el enfoque más sencillo para la validación en una entidad de dominio mediante la generación de una excepción. En la tabla de referencias al final de esta sección puede ver vínculos a implementaciones más avanzadas basadas en los patrones que hemos analizado anteriormente.
public void SetAddress(Address address)
{
_shippingAddress = address?? throw new ArgumentNullException(nameof(address));
}
Un ejemplo mejor demostraría la necesidad de asegurarse de que el estado interno no cambió o que se produjeron todas las mutaciones de un método. Por ejemplo, la siguiente implementación dejaría el objeto en un estado no válido:
public void SetAddress(string line1, string line2,
string city, string state, int zip)
{
_shippingAddress.line1 = line1 ?? throw new ...
_shippingAddress.line2 = line2;
_shippingAddress.city = city ?? throw new ...
_shippingAddress.state = (IsValid(state) ? state : throw new …);
}
Si el valor del estado no es válido, ya se han modificado la ciudad y la primera línea de dirección. Esto podría hacer que la dirección no sea válida.
Se puede usar un enfoque similar en el constructor de la entidad, lo que genera una excepción para asegurarse de que la entidad es válida una vez creada.
Uso de atributos de validación en el modelo en función de las anotaciones de datos
Las anotaciones de datos, como los atributos Required o MaxLength, se pueden usar para configurar las propiedades del campo de base de datos de EF Core, como se explica en detalle en la sección Asignación de tablas, pero ya no funcionan para la validación de entidades en EF Core (ni para el IValidatableObject.Validate método), como han hecho desde EF 4.x en .NET Framework.
Las anotaciones de datos y la interfaz IValidatableObject todavía se pueden usar para la validación del modelo durante el enlace del modelo, antes de la invocación habitual de las acciones del controlador, pero ese modelo está pensado para ser un ViewModel o DTO, y eso es un problema de MVC o API, no un problema de modelo de dominio.
Después de aclarar la diferencia conceptual, todavía puede usar anotaciones de datos y IValidatableObject en la clase de entidad para la validación si sus acciones reciben un objeto de clase de entidad como parámetro, lo cual no se recomienda. En ese caso, la validación se producirá en el enlace del modelo, justo antes de invocar la acción, y puede comprobar la propiedad ModelState.IsValid del controlador para comprobar el resultado, pero, de nuevo, ocurre en el controlador, no antes de persistir el objeto de entidad en el DbContext, como se hacía desde EF 4.x.
Todavía puede implementar la validación personalizada en la clase de entidad mediante anotaciones de datos y el método IValidatableObject.Validate, sobrescribiendo el método SaveChanges de DbContext.
Puede ver una implementación de ejemplo para validar IValidatableObject entidades en este comentario en GitHub. Ese ejemplo no realiza validaciones basadas en atributos, pero deberían ser fáciles de implementar mediante la reflexión en la misma sobrescritura.
Sin embargo, desde un punto de vista de DDD, es mejor mantener el modelo de dominio sencillo utilizando excepciones en los métodos de comportamiento de la entidad, o implementando el patrón de especificación y notificación para imponer reglas de validación.
Puede tener sentido usar anotaciones de datos en el nivel de aplicación en las clases ViewModel (en lugar de entidades de dominio) que aceptarán la entrada, para permitir la validación del modelo dentro de la capa de interfaz de usuario. Sin embargo, esto no debe realizarse a costa de la validación dentro del modelo de dominio.
Validación de entidades mediante la implementación del patrón de especificación y el patrón de notificación
Por último, un enfoque más elaborado para implementar validaciones en el modelo de dominio es mediante la implementación del patrón de especificación junto con el patrón de notificación, como se explica en algunos de los recursos adicionales enumerados más adelante.
Merece la pena mencionar que también puede usar solo uno de esos patrones, por ejemplo, validar manualmente con instrucciones de control, pero usar el patrón de notificación para apilar y devolver una lista de errores de validación.
Uso de la validación diferida en el dominio
Hay varios enfoques para tratar las validaciones diferidas en el dominio. En su libro Implementación del Diseño Domain-Driven, Vaughn Vernon describe estos en la sección sobre validación.
Validación en dos pasos
Considere también la verificación en dos pasos. Utiliza la validación de nivel de campo en tus Objetos de Transferencia de Datos (DTOs) y la validación de nivel de dominio dentro de tus entidades. Para ello, devuelva un objeto de resultado en lugar de excepciones para facilitar el control de los errores de validación.
El uso de la validación de campos con anotaciones de datos, por ejemplo, no duplica la definición de validación. Sin embargo, la ejecución puede ser del lado servidor y del lado cliente en el caso de DTO (comandos y ViewModels, por ejemplo).
Recursos adicionales
Rachel Appel. Introducción a la validación de modelos en ASP.NET Core MVC
https://dori-uw-1.kuma-moon.com/aspnet/core/mvc/models/validationAdición de validación
https://dori-uw-1.kuma-moon.com/aspnet/core/tutorials/first-mvc-app/validationMartin Fowler. Reemplazar el lanzamiento de excepciones por notificaciones en validaciones
https://martinfowler.com/articles/replaceThrowWithNotification.htmlPatrones de especificación y notificación
https://www.codeproject.com/articles/Specification-and-Notification-PatternsLev Gorodinski. Validación en Diseño Domain-Driven (DDD)
http://gorodinski.com/blog/2012/05/19/validation-in-domain-driven-design-ddd/Colin Jack. Validación del modelo de dominio
https://colinjack.blogspot.com/2008/03/domain-model-validation.htmlJimmy Bogard. Validación en el mundo de DDD
https://lostechies.com/jimmybogard/2009/02/15/validation-in-a-ddd-world/