Free tools Windows power users keep installed

One-click scans. No signup required.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

iTechGuides is reader-supported. When you buy through links on our site, we may earn an affiliate commission. As an Amazon Associate I earn from qualifying purchases. Learn more

Sí: un slice de ASP.NET Core puede organizarse alrededor de una funcionalidad, usar un handler sin una interfaz propia y acceder a EF Core directamente mediante DbContext. Ninguna de esas decisiones es una regla universal. El diseño funciona cuando el límite del caso de uso está claro; conviene añadir repositorios si protegen invariantes del dominio, y separar los eventos de dominio de los mensajes que deben salir del proceso.

Qué hace que un slice sea un slice

Un slice agrupa el código que participa en una acción o funcionalidad, en vez de repartirlo necesariamente entre carpetas genéricas como controladores, servicios y repositorios. La frontera de entrada recibe la petición y la delega en el handler de esa acción; el código relacionado queda cerca de la funcionalidad que resuelve.

En su guía sobre desarrollo de aplicaciones ASP.NET Core MVC, Microsoft describe los handlers y los feature slices, y señala que se pueden obtener beneficios similares sin MediatR. Por tanto, MediatR es una opción de implementación, no un requisito para organizar el código por funcionalidades.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

El handler no necesita una interfaz por defecto

Una interfaz como IUpdateOrderHandler puede ser útil si el diseño necesita esa abstracción. Pero añadirla a cada handler también crea otro contrato que mantener. Si el handler solo tiene una implementación y el límite de sustitución no aporta valor al caso de uso, una clase concreta puede bastar.

Al prescindir de la interfaz, hay que decidir explícitamente cómo se crea y se invoca el handler. Por ejemplo, la capa de entrada puede invocar una clase concreta, o un mecanismo de despacho puede resolverla. En ambos casos, sus dependencias —como el contexto de EF Core— deben suministrarse mediante la configuración de dependencias de la aplicación. La clase concreta simplifica el código de adaptación, pero vincula el punto que la consume a ese tipo específico; no es una mejora automática para todas las pruebas ni para todos los cambios futuros.

Qué queda en la frontera de entrada

La frontera de entrada debe traducir la petición y delegar la operación, no convertirse en el lugar donde se acumula la lógica del caso de uso. El handler, a su vez, debería recibir solo las dependencias que necesita. Eso permite que el slice mantenga cerca la validación propia de la acción, la operación de persistencia y la respuesta, sin exigir un mediador ni una interfaz por handler.

¿Se puede usar EF Core sin repositorios?

Sí. DbContext ya proporciona seguimiento de cambios y comportamiento de Unit of Work; Microsoft también indica que EF Core cumple los patrones Repository y Unit of Work en eShopOnContainers. Un repositorio personalizado puede duplicar parte de esas capacidades. La guía de Microsoft sobre la capa de persistencia presenta los repositorios como una opción válida, pero aclara que no son obligatorios.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

La decisión útil no es «repositorio o arquitectura correcta», sino qué frontera necesita el caso de uso. Si el handler puede expresar la operación con EF Core sin filtrar detalles de persistencia fuera de la aplicación, inyectar el contexto directamente reduce capas y permite aprovechar su seguimiento de cambios y SaveChanges.

Cuándo el acceso directo al contexto encaja

  • La operación es sencilla y no requiere una frontera adicional para hacer cumplir reglas del dominio.
  • El acceso a EF Core queda dentro de la capa de aplicación o del slice, en lugar de propagarse por toda la interfaz o el dominio.
  • Las pruebas se diseñan según el comportamiento que se necesita verificar, en vez de asumir que el contexto se sustituye de forma equivalente a una abstracción propia.

Cuándo tiene sentido un repositorio

  • El repositorio protege invariantes y operaciones de escritura de un agregado, haciendo explícito el límite que no debe romperse.
  • Se necesita aislar una dependencia de persistencia volátil o definir reglas de acceso a datos que el caso de uso debe cumplir.
  • La abstracción aporta una frontera útil para el dominio o la aplicación, en vez de limitarse a repetir métodos de EF Core tabla por tabla.

En DDD, el repositorio suele corresponder a un agregado raíz, no a cada tabla. Las consultas de lectura pueden tener un tratamiento separado, por ejemplo en un diseño CQRS, sin que todas las lecturas deban atravesar el mismo repositorio de escritura.

La guía de arquitectura de aplicaciones .NET sitúa normalmente DbContext y las migraciones en Infrastructure, y el modelo y las interfaces de Application Core en esa capa central. Es una forma de dirigir dependencias en una arquitectura por capas; no significa que cada handler de un slice deba llamar a la base exclusivamente mediante un repositorio.

La elección en una tabla

Necesidad Acceso directo a DbContext Repositorio por agregado
Operación simple con EF Core Menos código de adaptación; el handler usa el contexto directamente. Añade una capa que puede no aportar una frontera de dominio útil.
Invariantes de escritura del agregado El handler debe respetar por sí mismo el límite de escritura. Puede hacer explícita la frontera del agregado y sus operaciones válidas.
Aislamiento y sustitución El handler queda vinculado a EF Core. La abstracción puede aislar una dependencia, aunque no sustituye por sí sola una estrategia de pruebas.
Consultas de lectura El handler puede expresar la consulta con EF Core. En CQRS, las lecturas pueden separarse de los repositorios de escritura.

Cómo probar el slice sin confundir tipos de pruebas

Una interfaz de repositorio permite sustituir la persistencia en determinadas pruebas unitarias aisladas, pero eso no demuestra que la consulta o la escritura funcione con la base de datos real. Microsoft distingue esas pruebas unitarias de las pruebas contra una base de datos, que son pruebas de integración. La prueba adecuada depende de lo que se quiera comprobar: reglas de negocio aisladas, o el comportamiento conjunto del handler, EF Core y la persistencia.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Al usar DbContext directamente, se acepta de forma consciente que el handler conoce EF Core. Al introducir un repositorio, se obtiene una abstracción adicional que solo es valiosa si aclara el dominio, protege una regla o aísla una dependencia relevante; no basta con poder simularla en una prueba.

La guía de persistencia de Microsoft reproduce comentarios de Jimmy Bogard a favor de aprovechar la capacidad de la capa de persistencia y conservar el comportamiento de dominio en los agregados. Esos comentarios forman parte del feedback incorporado en la guía; son un punto de vista atribuible, no una demostración de que los repositorios sean siempre inconvenientes.

Eventos de dominio y eventos de integración no son intercambiables

Un evento de dominio registra algo que ocurrió y que interesa a otras partes del mismo dominio. Por lo general, se atiende dentro del proceso, y puede tener varios handlers. En cambio, un evento de integración comunica una transacción confirmada a otros microservicios, bounded contexts o sistemas externos; Microsoft lo describe como comunicación asíncrona.

  • Evento de dominio: reacción interna a un hecho del dominio, dentro de la aplicación.
  • Evento de integración: comunicación de un hecho confirmado a otros sistemas mediante un mecanismo asíncrono.

Despachar un evento de dominio en memoria no garantiza que un broker externo reciba el mensaje. Si el requisito es comunicar con fiabilidad un commit fuera del proceso, hace falta diseñar esa publicación como una preocupación aparte: no se debe inferir una garantía de entrega o atomicidad entre base de datos y broker solo por tener eventos en memoria.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Despachar eventos antes o después de SaveChanges

El momento del despacho determina cómo se relacionan los handlers del evento con la transacción de persistencia. Microsoft describe un enfoque en el que el agregado acumula eventos y el despacho se realiza alrededor de SaveChanges. La decisión depende de las garantías de consistencia y del manejo de fallos que requiera la aplicación.

Despacho antes de guardar

Si los handlers de dominio comparten el mismo DbContext y se ejecutan antes de guardar, sus cambios pueden participar en la misma transacción relacional. Si SaveChanges falla, la transacción puede revertir en conjunto los cambios asociados. Para una aplicación relacional con EF Core, este es el punto de partida más sencillo descrito por Microsoft.

Despacho después de guardar

Si el evento se despacha después de confirmar la escritura original, los cambios que hagan sus handlers pertenecen a transacciones separadas. Así se acepta consistencia eventual: puede ocurrir que el commit inicial tenga éxito y que un handler falle después. La aplicación debe contemplar cómo detectar ese fallo y, cuando corresponda, cómo compensar sus efectos.

Momento Relación con la transacción inicial Implicación principal
Antes de SaveChanges Los handlers que comparten el contexto pueden guardar en la misma transacción relacional. Los cambios pueden revertirse juntos si falla el guardado.
Después de SaveChanges El trabajo de los handlers ocurre en transacciones separadas. Hay consistencia eventual y se necesita tratar los fallos posteriores.

Ninguna opción es universalmente correcta: Microsoft considera ambas válidas según los requisitos, la escalabilidad y la complejidad que el equipo esté dispuesto a operar. La decisión debe reflejar si el caso de uso necesita una única frontera transaccional o acepta trabajo posterior con sus propios fallos.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Una forma práctica de decidir el diseño

  1. Define la acción: identifica qué petición o funcionalidad representa el slice y qué responsabilidad debe permanecer en su handler.
  2. Elige cómo se invoca: usa una clase concreta si una interfaz propia no añade una frontera necesaria; registra y resuelve sus dependencias de manera explícita.
  3. Evalúa la escritura: empieza con DbContext directo si el caso de uso no necesita proteger una frontera de agregado mediante otro contrato.
  4. Añade un repositorio solo por una razón del dominio o de la aplicación: delimita el agregado o la regla que protege y evita crear uno mecánico por tabla.
  5. Clasifica cada evento: decide si los consumidores pertenecen al mismo dominio y proceso o si el hecho debe comunicarse a otros sistemas después del commit.
  6. Fija la política de fallos: elige el despacho respecto de SaveChanges de acuerdo con la transacción requerida y el trabajo de recuperación aceptable.

El diseño resultante puede ser deliberadamente pequeño: un slice con un handler concreto, acceso directo a EF Core y eventos de dominio despachados dentro de la transacción. Si aparecen invariantes de agregado o requisitos de comunicación entre sistemas, esas necesidades justifican introducir fronteras específicas; no hace falta anticiparlas con capas genéricas.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.