Un punto de partida para arquitectura limpia con ASP.NET Core. La arquitectura limpia es solo la última de una serie de nombres para la misma arquitectura de dependencia e invertida libremente acoplada. También encontrará que se llama hexagonal, puertos y adaptadores o arquitectura de cebolla.
Obtenga más información sobre la arquitectura limpia y esta plantilla en el curso de arquitectura limpia de NimblePros. Use el código Ardalis para ahorrar 20%.
Esta arquitectura es utilizada en el curso de DDD Fundamentales por Steve Smith y Julie Lerman.
? Póngase en contacto con la compañía de Steve, NimblePros, para obtener arquitectura limpia o asistencia de capacitación y/o implementación de DDD para su equipo.
Aprenda sobre cómo implementar la arquitectura limpia de los entrenadores de NimblePros, Sarah "Sadukie" Dutkiewicz y Steve "Ardalis" Smith.
Si desea o está utilizando este proyecto para aprender o iniciar su solución, dale una estrella. ¡Gracias!
O si te sientes realmente generoso, ahora apoyamos los patrocinios de GitHub; vea el botón de arriba.
Por favor, anunciaré que el fondo Foss de Amazon AWS ha elegido otorgar un patrocinio de 12 meses a este proyecto. ¡Gracias, y gracias a todos mis otros patrocinadores pasados y actuales!
Por defecto, el Sitio usa HTTPS y espera que tenga un certificado de desarrollador autofirmado para el uso de LocalHost. Si recibe un error con Chrome, consulte esta respuesta para las instrucciones de mitigación.
La rama principal ahora está usando .NET 9 . Esto corresponde con el paquete NUGET versión 10.x. Las versiones anteriores están disponibles: vea nuestros lanzamientos.
Para usar esta plantilla, hay algunas opciones:
dotnet new (recomendado)Primero, instale la plantilla de Nuget (https://www.nuget.org/packages/ardalis.cleanarchitecture.template/):
dotnet new install Ardalis.CleanArchitecture.Template Puede ver las opciones disponibles ejecutando el comando con el -? opción:
dotnet new clean - arch - ?
ASP.NET Clean Architecture Solution (C # )
Author: Steve Smith @ardalis , Erik Dahl
Usage:
dotnet new clean - arch [ options ] [ template options ]
Options:
- n , -- name < name > The name for the output being created. If no name is specified , the name of the output
directory is used.
- o , -- output < output > Location to place the generated output.
-- dry - run Displays a summary of what would happen if the given command line were run if it would result
in a template creation.
-- force Forces content to be generated even if it would change existing files.
-- no - update-check Disables checking for the template package updates when instantiating a template.
-- project < project > The project that should be used for context evaluation.
- lang , -- language < C # > Specifies the template language to instantiate.
-- type < project > Specifies the template type to instantiate.
Template options:
-as , -- aspire Include .NET Aspire.
Type: bool
Default : false Debería ver la plantilla en la lista de plantillas de dotnet new list después de que esta se instale correctamente. Busque "Solución de arquitectura de limpieza ASP.NET" con un nombre corto de "Clean-Arch".
Navegue al directorio principal en el que desea que se cree la carpeta de la solución.
Ejecute este comando para crear la estructura de solución en un nombre de subcarpeta Your.ProjectName :
dotnet new clean-arch -o Your.ProjectName
El archivo y el archivo de solución Your.ProjectName se creará, y en el interior será todo su nuevo contenido de la solución, ¡adecuadamente el puesto de nombres y listo para ejecutar/probar!
Ejemplo: 
¡Gracias @dahlsailrunner por su ayuda para que esto funcione!
Problemas conocidos :
A partir de la versión 9, esta plantilla de solución solo incluye soporte para puntos finales de API utilizando la biblioteca FastEndpoints. Si desea utilizar mi biblioteca APiendPoints, páginas de afeitar y/o controladores, puede usar la última plantilla que los incluyó, versión 7.1. Alternativamente, se agregan fácilmente a esta plantilla después de la instalación.
Para usar ardalis.apdpoints en lugar de (o además de) FastEndpoints, simplemente agregue la referencia y use las clases base de la documentación.
dotnet add package Ardalis.ApiEndpointsDeberá agregar soporte para controladores al archivo Program.cs. Necesitas:
builder . Services . AddControllers ( ) ; // ControllersWithView if you need Views
// and
app . MapControllers ( ) ;Una vez que estos estén en su lugar, debería poder crear una carpeta de controladores y (opcionalmente) una carpeta de vista y todo debería funcionar como se esperaba. Personalmente, creo que las páginas de Razor son mucho mejores que los controladores y las vistas, por lo que si no ha investigado completamente las páginas de afeitar, es posible que desee hacerlo ahora antes de elegir vistas.
Deberá agregar soporte para las páginas de Razor al archivo Program.cs. Necesitas:
builder . Services . AddRazorPages ( ) ;
// and
app . MapRazorPages ( ) ;Luego, simplemente agregue una carpeta de páginas en la raíz del proyecto y vaya desde allí.
Para comenzar en función de este repositorio, debe obtener una copia localmente. Tiene tres opciones: bifurcación, clon o descarga. La mayoría de las veces, probablemente solo quieras descargar.
Debe descargar el repositorio , desbloquear el archivo zip y extraerlo a una nueva carpeta si solo desea jugar con el proyecto o desea usarlo como punto de partida para una aplicación.
Debe desembolsar este repositorio solo si planea enviar una solicitud de extracción. O si desea mantener una copia de una instantánea del repositorio en su propia cuenta de GitHub.
Debe clonar este repositorio si es uno de los contribuyentes y tiene acceso a él. De lo contrario, probablemente desee una de las otras opciones.
No debe necesitar hacer esto para usar esta plantilla, pero si desea que las migraciones se configuren correctamente en el proyecto de infraestructura, debe especificar ese nombre del proyecto cuando ejecuta el comando de migraciones.
En Visual Studio, abra la consola del Administrador de paquetes y ejecute Add-Migration InitialMigrationName -StartupProject Your.ProjectName.Web -Context AppDbContext -Project Your.ProjectName.Infrastructure .
En un terminal con la CLI, el comando es similar. Ejecute esto desde el directorio del proyecto web:
dotnet ef migrations add MIGRATIONNAME - c AppDbContext - p .. / Your.ProjectName.Infrastructure / Your.ProjectName.Infrastructure.csproj - s Your.ProjectName.Web.csproj - o Data / Migrations Para usar SQLServer, cambie options.UseSqlite(connectionString)); a options.UseSqlServer(connectionString)); en el archivo Your.ProjectName.Infrastructure.StartupSetup . También recuerde reemplazar la SqliteConnection con DefaultConnection en el archivo Your.ProjectName.Web.Program , que apunta a su servidor de base de datos.
Para actualizar la base de datos, use este comando de la carpeta del proyecto web (reemplace Clean.Architecture con el nombre de su proyecto):
dotnet ef database update - c AppDbContext - p .. / Clean .Architecture.Infrastructure / Clean .Architecture.Infrastructure.csproj - s Clean .Architecture.Web.csprojEl objetivo de este repositorio es proporcionar una estructura de solución básica que se pueda utilizar para construir aplicaciones sólidas basadas en diseño de dominio (DDD) o simplemente factorizadas, bien factorizadas, utilizando el núcleo .NET. Obtenga más información sobre estos temas aquí:
Si está acostumbrado a construir aplicaciones como un solo proyecto o como un conjunto de proyectos que siguen la UI tradicional -> Capa de negocios -> Arquitectura de la capa de acceso de datos "N -Tier", le recomiendo que consulte estos dos cursos (idealmente antes de los fundamentos DDD):
Steve Smith también mantiene la aplicación de referencia de Microsoft, Eshoponweb y su libro electrónico gratuito asociado. Míralos aquí:
Tenga en cuenta que el objetivo de este proyecto y el repositorio no es proporcionar una muestra o aplicación de referencia. Está destinado a ser una plantilla, pero con suficientes piezas en su lugar para mostrarle dónde pertenecen las cosas mientras configuran su solución real. En lugar de inútil "class1.cs", existen algunas clases reales. Eliminelos tan pronto como comprenda por qué están allí y dónde debe poner sus propios archivos similares. Hay una aplicación de muestra en la carpeta /sample , si está buscando eso.
He usado este kit de inicio para enseñar los conceptos básicos del núcleo ASP.NET utilizando conceptos y patrones de diseño basados en el dominio durante algún tiempo (comenzando cuando ASP.NET Core todavía estaba en prelanzamiento). Por lo general, enseño un taller práctico de uno o dos días antes de eventos como Devintersection, o talleres privados en el sitio para empresas que buscan poner al día con sus equipos con las últimas tecnologías y técnicas de desarrollo. No dude en contactarme si desea información sobre los próximos talleres.
El objetivo de esta plantilla de solución es proporcionar un kit de inicio bastante básico para nuevos proyectos. No incluye todos los marcos, herramientas o características posibles de la que podría beneficiarse una aplicación empresarial particular. Sus opciones de tecnología para cosas como el acceso a los datos se basan en lo que es la tecnología más común y accesible para la mayoría de los desarrolladores de software de negocios que utilizan la pila de tecnología de Microsoft. No incluye (actualmente) un amplio soporte para cosas como registro, monitoreo o análisis, aunque todo se puede agregar fácilmente. A continuación se muestra una lista de las dependencias tecnológicas que incluye y por qué fueron elegidos. La mayoría de estos se pueden cambiar fácilmente por su tecnología de elección, ya que la naturaleza de esta arquitectura es apoyar la modularidad y la encapsulación.
La validación de la entrada del usuario es un requisito de todas las aplicaciones de software. La pregunta es, ¿dónde tiene sentido implementarlo de manera concisa y elegante? Esta plantilla de solución incluye 4 proyectos separados, cada uno de los cuales podría ser responsable de realizar la validación, así como hacer cumplir los invariantes comerciales (que, dada la validación, ya debería haber ocurrido, generalmente se modelan como excepciones).
El modelo de dominio en sí mismo generalmente debe confiar en el diseño orientado a objetos para garantizar que siempre esté en un estado consistente. Aprovecha la encapsulación y limita el acceso a la mutación del estado público para lograr esto, y supone que cualquier argumento que se le haya pasado ya haya sido validado, por lo que los valores nulos u otros valores inadecuados producen excepciones, no resultados de validación, en la mayoría de los casos.
El proyecto de casos de uso / aplicación incluye el conjunto de todos los comandos y consultas que admite el sistema. Con frecuencia es responsable de validar su propio comando y objetos de consulta. Esto se hace más fácilmente utilizando un patrón de cadena de responsabilidad a través de comportamientos de medias o alguna otra tubería.
El proyecto web incluye todos los puntos finales de API, que incluyen sus propios tipos de solicitud y respuesta, siguiendo el patrón REP. La biblioteca FastEndpoints incluye soporte incorporado para la validación utilizando FluentValidation en los tipos de solicitudes. Este es un lugar natural para realizar la validación de entrada también.
Tener validación ocurre tanto dentro de los puntos finales de la API como nuevamente en el nivel de caso de uso puede considerarse redundante. Hay compensaciones para agregar esencialmente la misma validación en dos lugares, una para solicitudes de API y otra para los mensajes enviados a los manejadores de casos de uso. Después de la codificación defensiva, a menudo tiene sentido agregar validación en ambos lugares, ya que la sobrecarga es mínima y la tranquilidad de la mente y la mayor robustez de la aplicación a menudo valen la pena.
El proyecto central es el centro del diseño de la arquitectura limpia, y todas las demás dependencias del proyecto deberían apuntar hacia él. Como tal, tiene muy pocas dependencias externas. El proyecto central debe incluir el modelo de dominio que incluye cosas como:
Puede obtener más información sobre estos patrones y cómo aplicarlos aquí:
Un proyecto opcional, lo he incluido porque muchas personas lo exigían y es más fácil de eliminar que agregar más tarde. Esto también a menudo se conoce como la capa de servicios de aplicación o aplicación . El proyecto de casos de uso se organiza después de CQRS en comandos y consultas (consideré tener carpetas para Commands y Queries , pero sentí que agregaba poco: las carpetas por comando o consulta reales son suficientes sin anidar más). Los comandos mutan el modelo de dominio y, por lo tanto, siempre deben usar abstracciones de repositorio para su acceso a datos (los repositorios son cómo se obtiene y persiste los tipos de modelos de dominio). Las consultas son lecturas y, por lo tanto , no necesitan usar el patrón del repositorio , sino que pueden usar cualquier servicio o enfoque de consulta que sea más conveniente.
Dado que el proyecto de casos de uso está configurado para depender del núcleo y no depende de la infraestructura, aún deberá haber abstracciones definidas para su acceso a datos. Y puede usar cosas como especificaciones, lo que a veces puede ayudar a encapsular la lógica de consultas, así como el mapeo de tipo de resultados. Pero no tiene que usar el repositorio/especificación: solo puede emitir una consulta SQL o llamar a un procedimiento almacenado si esa es la forma más eficiente de obtener los datos.
Aunque este es un proyecto opcional para incluir (sin él, los puntos finales de su API solo funcionarían directamente con el modelo de dominio o los servicios de consulta), proporciona un lugar agradable Ui-Ignorant para agregar pruebas automatizadas y se presta para aplicar políticas para las preocupaciones transversales que utilizan una cadena de patrón de responsabilidad alrededor de los manejadores de mensajes (para cosas como la validación, cachorro, autores, autores, registros, tiempos horarios).). La plantilla incluye un ejemplo de esto para el registro, que se encuentra en el paquete SharedKernel Nuget.
La mayoría de las dependencias de su aplicación en los recursos externos deben implementarse en las clases definidas en el proyecto de infraestructura. Estas clases deben implementar interfaces definidas en el núcleo. Si tiene un proyecto muy grande con muchas dependencias, puede tener sentido tener múltiples proyectos de infraestructura (por ejemplo, infraestructura. Data), pero para la mayoría de los proyectos un proyecto de infraestructura con carpetas funciona bien. La plantilla incluye acceso a datos e implementaciones de eventos de dominio, pero también agregaría cosas como proveedores de correo electrónico, acceso a archivos, clientes de API web, etc. a este proyecto para que no agregue un acoplamiento a su núcleo o proyectos de UI.
El punto de entrada de la aplicación es el proyecto web ASP.NET Core (o posiblemente el proyecto Aspirehost, que a su vez carga el proyecto web). Esta es en realidad una aplicación de la consola, con un método public static void Main en Program.cs . Aprovecha FastEndpoints y el patrón REP para organizar sus puntos finales de API.
Se utiliza un núcleo compartido para compartir elementos comunes entre los contextos limitados. Es un término DDD, pero muchas organizaciones aprovechan proyectos o paquetes "comunes" para cosas que son útiles para compartir entre varias aplicaciones.
Recomiendo crear un proyecto y solución compartido separados si necesita compartir código entre múltiples contextos limitados (consulte los fundamentos DDD). Recomiendo además que esto se publique como un paquete Nuget (probablemente en privado dentro de su organización) y referenciado como una dependencia de Nuget por aquellos proyectos que lo requieren.
Anteriormente, se incluyó un proyecto para Sharedkernel en este proyecto. Sin embargo, por las razones anteriores, lo he convertido en un paquete separado, Ardalis.sharedkernel, que debe reemplazar con su cuenta cuando use esta plantilla .
Si desea ver otro ejemplo de un paquete SharedKernel, el que uso en mi curso DDD pluralsight actualizado está en Nuget aquí.
Los proyectos de prueba podrían organizarse en función del tipo de prueba (unidad, funcional, integración, rendimiento, etc.) o por el proyecto que están probando (núcleo, infraestructura, web) o ambos. Para este kit de inicio simple, los proyectos de prueba se organizan en función del tipo de prueba, con proyectos de prueba de unidades, funcionales e integración existentes en esta solución. Las pruebas funcionales son un tipo especial de prueba de integración que realiza pruebas subcutáneas de las API del proyecto web, sin alojar un sitio web real o atravesar la red. He creado un montón de ayudantes de prueba para que este tipo de pruebas sea más corta y más fácil de mantener.
Esta plantilla de solución tiene un código integrado para admitir algunos patrones comunes, especialmente los patrones de diseño basados en el dominio. Aquí hay una breve descripción de cómo funcionan algunos de ellos.
Los eventos de dominio son un gran patrón para desacoplar un desencadenante para una operación de su implementación. Esto es especialmente útil desde las entidades de dominio, ya que los manejadores de los eventos pueden tener dependencias, mientras que las entidades mismas no suelen hacerlo. En la muestra, puede ver esto en acción con el método ToDoItem.MarkComplete() . El siguiente diagrama de secuencia demuestra cómo se usan el evento y su controlador cuando un elemento se completa a través de un punto final de la API web.
