This post outlines using Clean Architecture with ASP.NET Core 6 Micro Service. One of the main reason to use Clean Architecture template is that you can focus on writing business logic but not to get struck on thinking about infrastructure concerns. It is formerly known by other names like Onion Architecture , Hexagonal Architecture and Ports and Adapters architecture.
What is Clean Architecture?
It is a domain centric Architecture that helps you to organize dependencies in your application. Any application that you build typically broken down into different concerns. User interface concerns , Business Logic building concerns , Data persisting concerns. Clean Architecture provides a way to organize these concerns in a way that it allows you to continue to maintain the application over the period of time. The principles behind the Clean Architecture are SOLID.
Clean Architecture does depend on Domain (business) be the thing that everything else is depends on. UI (user interface ) depend on the domain model. Infrastructure that implements interfaces or abstractions that defined on Domain model. Infrastructure also uses the types that defined in domain model. Infrastructure layer is responsible for persisting the data to database. If you apply clean architecture then you are not coupled to that low level database. Application is free from it. If you are using SQL server right now then in certain environments like in automation you can use SQLlite, may be it is easy to blow it away or resetting something like that , you may want to use no-sql , cosmos db or mongo etc. you can use these pluggable dbs. This perfectly possible without having to change the UI or business layer.
WHY do I need this Architecture?
Picture worth a thousand words – This might not be the way you want to see your refrigerator in kitchen. This is an example how you are mixing the concerns in your code in same place. Avoid mixing different code responsibilities in the same (Method | Class | Project).
Once you go to certain size, you will face problems in managing these applications. There is lots of logic that is in database, the things that you afraid to touch because you don’t know what else is depending on etc, you have got the database that shared by multiple applications that all using similar architecture. you can’t even rename a table or column without the fear that it is going to break some other App.
HOW to implement this in ASP.NET CORE 6?
What is Actually in Core Project?
Core project contains Interfaces , Domain model types – Entities , value objects and Aggregates Domain services. You want to make sure , All business rules , entities and logic – keep it in the Core Project. we don’t want to have business logic in SP’s or JavaScript. You want to make sure all dependencies flow towards the Core Project not the other way around. Good thing in visual studio it does not even allow you to have circular dependencies. Infrastructure project depend on Core Project but not the other way around.
Interfaces – Most of the abstractions that you are going to be defined in your application will be here , Whether those interfaces are related to persistence or some related to business logic that represent domain services.
Aggregates, Entities and Value Objects represents the Modeling the things that have state and persistence. The things that have identity lives in entities . Aggregates is domain design pattern where you group the entities together to make an encapsulation boundary that makes it easier for the persistence. Example: You can construct order and order details as an aggregate , when you want to persist then you do whole order and fetch whole order. Value objects are something that do not have an identity , you compare by just looking at the properties. common value object in .NET is DateTime. Good part of Value Object is validation , you put the validation in constructor of the value object and don’t have to check any where else in the code. Datetime range is an example. Domain Services where your application logic lives. Instead of relying on low-level exceptions you can define custom domain exceptions in core project. example: Customer not found exception or Order not found exception.
Domain Events – Typically will live in core project.
Specifications – Specifications are a way to encapsulate your query into a class. you would have a collection of different specifications corresponds to different types of queries that you typically call against your domain model. Specifications would work with your repository to make sure that your repository doesn’t get huge and overloaded. If you have used this repository pattern , perhaps the complaints you have are overtime it is bigger and bigger where first you have list customers , then you had list customers with orders and then you had list active customers and then list active customers with orders etc
Custom Guards – is a technique for fail fast in a method especially in constructor. More on this can be read from here.
This make right thing easy and wrong thing hard. Define interfaces and abstractions in inner projects usually core and outer projects can implement those interfaces.
Download the git hub project template from here. Typical Core project looks as follows . The reason I suggest you to download this template is, it will save few hours of your project setup time.
How do you organize the folders inside this project totally an individual choice. Feature folder approach is one choice where you group things based on how they likely to change eg: adding feature and behavior. Instead of having Entities folder and having 100 different classes , you will define aggregate folder where you typically group 15 – 20 entities into one aggregate.
What is Actually in Infrastructure Project?
Repositories, DbContext classes , Cached Repositories , Any cloud resources that you are using for persistence eg: Azure Storage.
WHAT IS Actually in Web project?
It will have all your MVC stuff, DTO that go over wire , view models , api models and binding models, In this example I am showing MVC project but works with any UI technology.
What about common building blocks that used across applications?
Domain driven design uses the term Shared Kernel for this that can include the following
- Base Entity
- Base Domain Event
- Base Specification
- Common Exception
- Common Interfaces
- Common Auth
- Common DI
- Common Logging
- Common Guard clauses
- Common Configuration etc
Ideally these are distributed using NuGet packages. Make sure you don’t put any infrastructure dependencies in shared kernel project
Additional information on architecting modern web applications can be referred from here