Un point de départ pour une architecture propre avec ASP.NET Core. L'architecture propre n'est que la dernière d'une série de noms pour la même architecture inversée à couplage lâche. Vous le trouverez également nommé hexagonal, ports et adaptations ou architecture d'oignon.
En savoir plus sur l'architecture propre et ce modèle dans le cours d'architecture Clean de Nimblepros. Utilisez le code Ardalis pour économiser 20%.
Cette architecture est utilisée dans le cours Fundamentals DDD par Steve Smith et Julie Lerman.
? Contactez la société de Steve, Nimblepros, pour une architecture propre ou une formation DDD et / ou une aide à la mise en œuvre pour votre équipe.
Découvrez comment mettre en œuvre l'architecture propre des entraîneurs de Nimblepros Sarah "Sadukie" Dutkiewicz et Steve "Ardalis" Smith.
Si vous aimez ou utilisez ce projet pour apprendre ou démarrer votre solution, veuillez lui donner une étoile. Merci!
Ou si vous vous sentez vraiment généreux, nous soutenons maintenant les parrainages GitHub - voyez le bouton ci-dessus.
Je suis s'il vous plaît d'annoncer que le fonds FOSS d'Amazon AWS a choisi d'accorder un parrainage de 12 mois à ce projet. Merci et merci à tous mes autres sponsors passés et actuels!
Par défaut, le site utilise HTTPS et s'attend à ce que vous ayez un certificat de développeur auto-signé pour une utilisation locale. Si vous obtenez une erreur avec Chrome, consultez cette réponse pour les instructions d'atténuation.
La branche principale utilise désormais .NET 9 . Cela correspond à la version 10.x du package NuGet. Des versions précédentes sont disponibles - voir nos versions.
Pour utiliser ce modèle, il existe quelques options:
dotnet new (recommandé)Tout d'abord, installez le modèle de Nuget (https://www.nuget.org/packages/ardalis.cleanarchitecture.template/):
dotnet new install Ardalis.CleanArchitecture.Template Vous pouvez voir des options disponibles en exécutant la commande avec le -? option:
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 Vous devriez voir le modèle dans la liste des modèles de dotnet new list après cette installation avec succès. Recherchez "ASP.net Clean Architecture Solution" avec le nom court de "Clean-Arch".
Accédez au répertoire parent dans lequel vous souhaitez que le dossier de la solution soit créé.
Exécutez cette commande pour créer la structure de la solution dans un nom de sous-dossier Your.ProjectName :
dotnet new clean-arch -o Your.ProjectName
Le répertoire et le fichier de solution Your.ProjectName seront créés, et à l'intérieur de cela sera tout votre nouveau contenu de solution, correctement des noms de noms et prêts à s'exécuter / tester!
Exemple: 
Merci @dahlsailrunner pour votre aide pour que cela fonctionne!
Problèmes connus :
À partir de la version 9, ce modèle de solution inclut uniquement la prise en charge des points de terminaison de l'API à l'aide de la bibliothèque Fasendpoints. Si vous souhaitez utiliser ma bibliothèque apiendpoints, mes pages de rasoir et / ou mes contrôleurs, vous pouvez utiliser le dernier modèle qui les incluait, version 7.1. Alternativement, ils sont facilement ajoutés à ce modèle après l'installation.
Pour utiliser ardalis.apiendpoints au lieu de (ou en plus) de points de fin des Fastend, ajoutez simplement la référence et utilisez les classes de base à partir de la documentation.
dotnet add package Ardalis.ApiEndpointsVous devrez ajouter la prise en charge des contrôleurs au fichier programme.cs. Vous avez besoin:
builder . Services . AddControllers ( ) ; // ControllersWithView if you need Views
// and
app . MapControllers ( ) ;Une fois ceux-ci en place, vous devriez être en mesure de créer un dossier de contrôleurs et (éventuellement) un dossier de vues et tout devrait fonctionner comme prévu. Personnellement, je trouve que les pages de rasoirs sont bien meilleures que les contrôleurs et les vues, donc si vous n'avez pas pleinement enquêté sur les pages de rasoir, vous voudrez peut-être le faire maintenant avant de choisir les vues.
Vous devrez ajouter la prise en charge des pages de rasoir au fichier programme.cs. Vous avez besoin:
builder . Services . AddRazorPages ( ) ;
// and
app . MapRazorPages ( ) ;Ensuite, vous ajoutez simplement un dossier de pages dans la racine du projet et allez à partir de là.
Pour commencer en fonction de ce référentiel, vous devez obtenir une copie localement. Vous avez trois options: fourche, clone ou téléchargement. La plupart du temps, vous voulez probablement simplement télécharger.
Vous devez télécharger le référentiel , débloquer le fichier zip et l'extraire dans un nouveau dossier si vous souhaitez simplement jouer avec le projet ou si vous souhaitez l'utiliser comme point de départ pour une application.
Vous devez déborder ce référentiel uniquement si vous prévoyez de soumettre une demande de traction. Ou si vous souhaitez conserver une copie d'un instantané du référentiel dans votre propre compte GitHub.
Vous devez cloner ce référentiel si vous êtes l'un des contributeurs et que vous y avez accès. Sinon, vous voulez probablement l'une des autres options.
Vous ne devriez pas avoir besoin de le faire pour utiliser ce modèle, mais si vous souhaitez que les migrations soient correctement configurées dans le projet d'infrastructure, vous devez spécifier le nom du projet lorsque vous exécutez la commande Migrations.
Dans Visual Studio, ouvrez la console du gestionnaire de package et exécutez Add-Migration InitialMigrationName -StartupProject Your.ProjectName.Web -Context AppDbContext -Project Your.ProjectName.Infrastructure .
Dans un terminal avec la CLI, la commande est similaire. Exécutez-le à partir du répertoire du projet Web:
dotnet ef migrations add MIGRATIONNAME - c AppDbContext - p .. / Your.ProjectName.Infrastructure / Your.ProjectName.Infrastructure.csproj - s Your.ProjectName.Web.csproj - o Data / Migrations Pour utiliser SQLServer, modifiez options.UseSqlite(connectionString)); aux options.UseSqlServer(connectionString)); Dans le fichier Your.ProjectName.Infrastructure.StartupSetup . N'oubliez pas non plus de remplacer la SqliteConnection par DefaultConnection dans le fichier Your.ProjectName.Web.Program , qui pointe vers votre serveur de base de données.
Pour mettre à jour la base de données, utilisez cette commande à partir du dossier du projet Web (remplacez Clean.Architecture par le nom de votre projet):
dotnet ef database update - c AppDbContext - p .. / Clean .Architecture.Infrastructure / Clean .Architecture.Infrastructure.csproj - s Clean .Architecture.Web.csprojL'objectif de ce référentiel est de fournir une structure de solution de base qui peut être utilisée pour créer des applications solides basées sur le domaine (DDD) ou tout simplement bien facturées utilisant .NET Core. En savoir plus sur ces sujets ici:
Si vous avez l'habitude de créer des applications comme un seul projet ou comme un ensemble de projets qui suivent l'interface utilisateur traditionnelle -> Couche commerciale -> Architecture de couche d'accès aux données "N-Tier", je vous recommande de consulter ces deux cours (idéalement avant les fondamentaux DDD):
Steve Smith maintient également l'application de référence de Microsoft, EshoponWeb, et son ebook gratuit associé. Vérifiez-les ici:
Notez que l'objectif de ce projet et de ce référentiel n'est pas de fournir un échantillon ou une application de référence. Il est censé être juste un modèle, mais avec suffisamment de pièces en place pour vous montrer où les choses appartiennent à la configuration de votre solution réelle. Au lieu de "classe 1.cs" inutile, il y a quelques classes réelles en place. Supprimez-les dès que vous comprenez pourquoi ils sont là et où vous devriez mettre vos propres fichiers similaires. Il y a un exemple d'application dans le dossier /sample , si vous recherchez cela.
J'ai utilisé ce kit de démarrage pour enseigner les bases du noyau ASP.NET en utilisant des concepts et des modèles de conception axés sur le domaine depuis un certain temps maintenant (à partir du moment où ASP.NET Core était toujours en pré-libération). En règle générale, j'enseigne un atelier pratique d'un ou deux jours avant des événements tels que Devittersection ou des ateliers privés sur place pour les entreprises qui cherchent à mettre leurs équipes à la vitesse avec les dernières technologies et techniques de développement. N'hésitez pas à me contacter si vous souhaitez des informations sur les prochains ateliers.
L'objectif de ce modèle de solution est de fournir un kit de démarrage assez nu pour les nouveaux projets. Il n'inclut pas tous les framework, outil ou fonctionnalité possibles dont une application d'entreprise particulière pourrait bénéficier. Ses choix de technologie pour des choses comme l'accès aux données sont enracinés dans la technologie la plus courante et accessible pour la plupart des développeurs de logiciels d'entreprise à l'aide de la pile technologique de Microsoft. Il n'inclut pas (actuellement) un soutien étendu à des choses comme la journalisation, la surveillance ou l'analyse, bien que celles-ci puissent toutes être ajoutées facilement. Vous trouverez ci-dessous une liste des dépendances technologiques qu'elle comprend et pourquoi elles ont été choisies. La plupart d'entre eux peuvent facilement être échangés par votre technologie de choix, car la nature de cette architecture est de soutenir la modularité et l'encapsulation.
La validation de la saisie de l'utilisateur est une exigence de toutes les applications logicielles. La question est: où est-il logique de le mettre en œuvre de manière concise et élégante? Ce modèle de solution comprend 4 projets distincts, dont chacun pourrait être responsable de la validation ainsi que de l'application des invariants commerciaux (qui, étant donné la validation, aurait déjà eu lieu, sont généralement modélisés comme des exceptions).
Le modèle de domaine lui-même doit généralement s'appuyer sur la conception orientée objet pour s'assurer qu'elle est toujours dans un état cohérent. Il exploite l'encapsulation et limite l'accès à la mutation de l'état public à y parvenir, et il suppose que tous les arguments qui lui ont été transmis ont déjà été validés, donc nul ou d'autres valeurs incorrectes donnent des exceptions, et non des résultats de validation, dans la plupart des cas.
Le projet de cas d'utilisation / d'application comprend l'ensemble de toutes les commandes et interroge le système prend en charge. Il est souvent responsable de la validation de ses propres objets de commande et de requête. Cela se fait le plus facilement en utilisant un modèle de chaîne de responsabilité via les comportements Mediatr ou un autre pipeline.
Le projet Web comprend tous les points de terminaison de l'API, qui incluent leurs propres types de demande et de réponse, en suivant le modèle de Rep. La bibliothèque Fastendpoints comprend la prise en charge intégrée pour la validation à l'aide de FluentValidation sur les types de demande. Il s'agit également d'un endroit naturel pour effectuer la validation des entrées.
La validation se produit à la fois dans les points d'extrémité de l'API, puis à nouveau au niveau du cas d'utilisation peut être considéré comme redondant. Il y a des compromis pour ajouter essentiellement la même validation à deux endroits, un pour les demandes d'API et un autre pour les messages envoyés aux gestionnaires de cas d'utilisation. Après le codage défensif, il est souvent logique d'ajouter la validation dans les deux endroits, car les frais généraux sont minimes et la tranquillité d'esprit de l'esprit et une plus grande robustesse d'application en valent la peine.
Le projet de base est le centre de la conception de l'architecture propre, et toutes les autres dépendances du projet devraient pointer vers elle. En tant que tel, il a très peu de dépendances externes. Le projet de base devrait inclure le modèle de domaine, y compris des choses comme:
Vous pouvez en savoir plus sur ces modèles et comment les appliquer ici:
Un projet facultatif, je l'ai inclus parce que de nombreuses personnes l'exigeaient et c'est plus facile à supprimer que d'ajouter plus tard. Ceci est également souvent appelé la couche d'application ou de services d'application . Le projet des cas d'utilisation est organisé en suivant CQRS en commandes et requêtes (j'ai envisagé d'avoir des dossiers pour Commands et Queries mais j'ai estimé qu'il a ajouté peu - les dossiers par commande ou requête réel sont suffisants sans nidification supplémentaire). Les commandes mutent le modèle de domaine et doivent donc toujours utiliser des abstractions de référentiel pour leur accès aux données (les référentiels sont la façon dont on récupére et persiste les types de modèles de domaine). Les requêtes sont en lecture et n'ont donc pas besoin d'utiliser le modèle de référentiel , mais peuvent plutôt utiliser le service ou l'approche de requête le plus pratique.
Étant donné que le projet des cas d'utilisation est configuré pour dépendre du noyau et ne dépend pas de l'infrastructure, il sera encore des abstractions définies pour son accès aux données. Et il peut utiliser des choses comme les spécifications, qui peuvent parfois aider à encapsuler la logique de requête ainsi que la cartographie du type de résultat. Mais il n'a pas besoin d'utiliser le référentiel / spécification - il peut simplement émettre une requête SQL ou appeler une procédure stockée si c'est le moyen le plus efficace d'obtenir les données.
Bien qu'il s'agisse d'un projet facultatif à inclure (sans celui-ci, vos points de terminaison API fonctionneraient directement avec le modèle de domaine ou les services de requête), il fournit un joli endroit indignable pour ajouter des tests automatisés et se prête à appliquer des politiques pour la validation croisée en utilisant un modèle de chaîne de responsabilité autour des gestionnaires de messages (pour des choses telles que la validation, la cache, l'authentification, le loging, le synchronisation, etc.). Le modèle en comprend un exemple pour la journalisation, qui est situé dans le package PartnedKernel Nuget.
La plupart des dépendances de votre application sur les ressources externes doivent être mises en œuvre dans les classes définies dans le projet d'infrastructure. Ces classes doivent implémenter les interfaces définies dans Core. Si vous avez un très grand projet avec de nombreuses dépendances, il peut être logique d'avoir plusieurs projets d'infrastructure (par exemple, infrastructure.data), mais pour la plupart des projets, un projet d'infrastructure avec des dossiers fonctionne bien. Le modèle comprend l'accès aux données et les implémentations d'événements de domaine, mais vous ajouteriez également des choses comme les fournisseurs de messagerie, l'accès aux fichiers, les clients d'API Web, etc. à ce projet afin qu'ils n'ajoutent pas de couplage à vos projets de base ou d'interface utilisateur.
Le point d'entrée de l'application est le projet Web ASP.NET Core (ou peut-être le projet AspireHost, qui à son tour charge le projet Web). Il s'agit en fait d'une application de console, avec une méthode public static void Main dans Program.cs . Il tire parti des points Fastend et du modèle de Rep pour organiser ses points de terminaison API.
Un noyau partagé est utilisé pour partager des éléments communs entre les contextes limités. Il s'agit d'un terme DDD, mais de nombreuses organisations exploitent des projets ou des forfaits communs pour des choses qui sont utiles à partager entre plusieurs applications.
Je recommande de créer un projet et une solution SharedKernel séparés si vous avez besoin de partager du code entre plusieurs contextes limités (voir les fondamentaux DDD). Je recommande en outre que cela soit publié en tant que package NuGet (très probablement en privé au sein de votre organisation) et référencé comme une dépendance NuGet par les projets qui l'exigent.
Auparavant, un projet pour SharedKernel a été inclus dans ce projet. Cependant, pour les raisons ci-dessus, j'en ai fait un package séparé, Ardalis.SharedKernel, que vous devez remplacer par le vôtre lorsque vous utilisez ce modèle .
Si vous souhaitez voir un autre exemple d'un package SharedKernel, celui que j'utilise dans mon cours DDD Pluralsight mis à jour est sur NuGet ici.
Des projets de test peuvent être organisés en fonction du type de test (unité, fonctionnel, intégration, performance, etc.) ou par le projet qu'ils testent (noyau, infrastructure, Web), ou les deux. Pour ce kit de démarrage simple, les projets de test sont organisés en fonction du type de test, avec des projets d'unité, fonctionnel et d'intégration existant dans cette solution. Les tests fonctionnels sont un type spécial de test d'intégration qui effectuent des tests sous-cutanés des API du projet Web, sans héberger un site Web réel ni sur le réseau. J'ai créé un tas d'aideurs de test pour rendre ces types de tests plus courts et plus faciles à entretenir.
Ce modèle de solution a du code intégré pour prendre en charge quelques modèles communs, en particulier les modèles de conception axés sur le domaine. Voici un bref aperçu de la façon dont quelques-uns fonctionnent.
Les événements de domaine sont un excellent modèle pour découpler un déclencheur pour une opération à partir de son implémentation. Ceci est particulièrement utile à partir des entités de domaine, car les gestionnaires des événements peuvent avoir des dépendances alors que les entités elles-mêmes ne le font généralement pas. Dans l'échantillon, vous pouvez le voir en action avec la méthode ToDoItem.MarkComplete() . Le diagramme de séquence suivant montre comment l'événement et son gestionnaire sont utilisés lorsqu'un élément est marqué complet via un point de terminaison de l'API Web.
