architecture - Dónde implementar Automapper en una arquitectura de capas DDD+
domain-driven-design layer (1)
Para responder a su pregunta específica, hablaré más generalmente acerca de su arquitectura. La arquitectura que ha ideado para su proyecto es sutilmente diferente de una arquitectura típica utilizada con DDD. Si bien la forma en que ha dividido las responsabilidades es típica, en DDD, las clases de dominio no son responsables de su propia persistencia. De hecho, un mantra de DDD es la persistencia de la ignorancia . Básicamente, esto significa que las clases de dominio son ignorantes de la persistencia, no tienen un método Save
. En cambio, los servicios de aplicación (capa de fachada de la aplicación en su arquitectura) se coordinan con los repositorios para reconstituir y persistir las entidades de dominio.
A continuación, al implementar repositorios, generalmente no hay necesidad de un DTO explícito entre la tecnología de persistencia subyacente y las clases de dominio. Con los ORM, como NHibernate y EF, las asignaciones entre clases de dominio y tablas relacionales se expresan con clases de asignación o configuraciones basadas en XML. Como resultado, sus clases de dominio se asignan implícitamente, sin necesidad de DTO. Algunos casos requieren una DTO, en cuyo caso la asignación del repositorio debe encapsular la asignación entre la DTO y la clase de dominio. Este es un lugar donde puedes invocar AutoMapper.
Finalmente, es una práctica común comunicarse entre la capa de presentación y la capa de aplicación / dominio con DTO. Para determinar exactamente dónde debe realizarse la asignación, debe profundizar más en la arquitectura que mejor se adapte a su proyecto. La mayoría de las arquitecturas modernas de DDD se basan en la arquitectura hexagonal . En una arquitectura hexagonal, su dominio está en el centro y todas las demás "capas" adaptan el dominio a tecnologías específicas. Por ejemplo, un repositorio puede verse como un adapter entre el dominio y una tecnología de base de datos específica. ASP.NET WebAPI puede verse como un adaptador entre el dominio y HTTP / REST. Del mismo modo, la capa de presentación se puede ver como un adaptador entre el dominio y un específico. Los DTO se pueden manifestar dentro de cada uno de estos adaptadores y es responsabilidad del adaptador mapear desde y hacia estos DTO.
Un ejemplo típico sería usar los servicios de aplicación para establecer una fachada sobre su dominio. No hay DTO en juego todavía. A continuación, creará una capa de servicio (servicio de host abierto en DDD) con ASP.NET WebAPI, un adaptador. Usted crea las DTO específicas de ASP.NET WebAPI y depende de este adaptador asignarlas a estas DTO y desde ellas. Por lo tanto, si usa AutoMapper, debería invocarse en esta capa. Esto se puede hacer de forma explícita o aspect-oriented con filtros de acción. Lo mismo vale para la capa de presentación. La capa de presentación se podría acoplar directamente a los servicios de aplicación, o a un servicio de host abierto de ASP.NET WebAPI. En cualquier caso, es responsabilidad de la capa de presentación mapear entre las clases de dominio (desde el servicio de aplicación o DTO desde WebAPI) y sus propias primitivas, como ViewModel.
Antecedentes : Para mi propia claridad / autoeducación, estoy tratando de implementar una aplicación de entrada de pedidos simple utilizando TDD + DDD. Mi objetivo principal es mantener la arquitectura limpia separando las preocupaciones.
Tengo cuatro capas (por ahora) ...
Persistencia / DAL con una clase CustomerRepository que puede realizar operaciones GetById, Save, en la "raíz agregada", un Cliente y sus Pedidos y Artículos relacionados. Para permitir la "inyección de dependencia del hombre pobre"
La capa de dominio / BLL que contiene clases de "entidad de negocios" que realizan operaciones de grano fino para ayudar a crear nuevos pedidos, aplicando impuestos, descuentos, lógica de envío según el tamaño del pedido y la ubicación del cliente.
Application Facade (servicios de aplicaciones / orquestación) que contiene clases complejas y de mayor complejidad para organizar las "entidades comerciales" y reducir la charla con la presentación (y potencialmente una capa de servicios web).
Capa de presentación
Además, quiero pasar los DTO de POCO entre capas clave ... particularmente entre Persistence => Domain layers, y ApplicationFacade => Presentation layers. Por lo tanto, tengo CustomerDto, OrderDto, OrderItemDto con las relaciones adecuadas definidas en un paquete compartido.
Quiero inyectar una implementación de ICustomerRepository en la clase de "entidad de negocios" del Cliente utilizando Inyección de Constructor, luego llamar a un Cliente.Guardar () en la "entidad de negocios" para iniciar el proceso de creación / actualización, finalmente llamando al método Guardar El repositorio del cliente. Después de todo, el Cliente es la "raíz agregada" y tiene toda la información necesaria para guardar ... también es el "custodio" del CustomerRepository inyectado.
Problema: Aquí es donde encuentro un obstáculo. Quiero mantener la capa Dominio / BLL lo más pura posible y evitar que se vincule a cualquier framework y API de terceros, pero el método Customer.Save () necesita traducir la "raíz agregada" del Cliente y todos sus Pedidos y Artículos en. sus versiones DTO para el transporte a la capa de persistencia CustomerRepository ... y eso es un trabajo para Automapper.
El problema es ... Si no pongo Automapper en la capa Dominio / BLL, no estoy realmente seguro de dónde debería ir.
No se siente bien ponerlo en ApplicationFacade, aunque su trabajo es la orquestación.
Definitivamente no se siente bien ponerlo en la capa Dominio / BLL porque quiero mantenerlo impecable.
Por lo tanto, siento que me he perdido algo ... que me estoy aproximando a esto con un malentendido fundamental de cómo todas las partes trabajadoras deberían unirse para completar esta tarea. ¿Alguna sugerencia? (Por favor sea amable, soy nuevo en todo esto, y nuevo en SO. Déjeme saber si necesito mostrar algún código de lo que tengo hasta ahora).