A monolith, built with .Net, DDD, CQRS, Vertical Slice Architecture, Event-Driven Architecture, and the latest technologies.
MIT License
The primary objective of this project is to establish a framework that can facilitate the deployment and operation of a straightforward ECommerce application using cutting-edge technologies and architecture such as Vertical Slice Architecture, CQRS, and DDD in .Net. 🚀
💡 This project is not business-oriented and most of my focus was in the thechnical part for implement a Monolith system with a sample project.
Vertical Slice Architecture
at the architecture level to create a scalable
and maintainable
structure for the application.Domain Driven Design (DDD)
for implementing business processes
and validation rules
.CQRS
implementation with the MediatR
library for better separation of write
and read
operations.MediatR
to reduce coupling
and provide support for managing cross-cutting concerns
within pipelines
, including validation
and transaction handling
for the application.Postgres
as our relational database
management system at the database level.Unit Testing
, Integration Testing
, and End To End Testing
for testing level to ensure the robustness
and reliability
of the application.Fluent Validation
and a Validation Pipeline Behaviour
on top of MediatR
to validate requests and responses and ensure data integrity
.Minimal API
for all endpoints to create a lightweight
and streamlined
API.Docker-Compose
for our deployment
mechanism to enable easy deployment and scaling of the application..NET 8
- .NET Framework and .NET Core, including ASP.NET and ASP.NET CoreMVC Versioning API
- Set of libraries which add service API versioning to ASP.NET Web API, OData with ASP.NET Web API, and ASP.NET CoreEF Core
- Modern object-database mapper for .NET. It supports LINQ queries, change tracking, updates, and schema migrationsMediatR
- Simple, unambitious mediator implementation in .NET.FluentValidation
- Popular .NET validation library for building strongly-typed validation rulesSwagger & Swagger UI
- Swagger tools for documenting API's built on ASP.NET CoreSerilog
- Simple .NET logging with fully-structured eventsScrutor
- Assembly scanning and decoration extensions for Microsoft.Extensions.DependencyInjectionAutoMapper
- Convention-based object-object mapper in .NETNewId
- NewId can be used as an embedded unique ID generator that produces 128 bit (16 bytes) sequential IDsSieve
- Sieve is a framework for .NET Core that adds sorting, filtering, and pagination functionality out of the boxxUnit.net
- A free, open source, community-focused unit testing tool for the .NET FrameworkRespawn
- Respawn is a small utility to help in resetting test databases to a clean stateTestcontainers
- Testcontainers for .NET is a library to support tests with throwaway instances of Docker containersBogus
- Bogus is a simple fake data generator for .NETIn this project I used vertical slice architecture and feature folder structure to structure my files.
To reduce coupling
in our code, we leverage Mediatr
and build pipelines
on top of it to handle validation
, logging
, and transactions
. Our domain
follows Domain-Driven Design
principles and employs value objects
for business logic
. We also incorporate validation into our business processes. When we complete work within our domain, it raises a domain event
. Depending on the requirements, we can then react to this event and take appropriate action to further our business goals.
I treat each request
as a distinct
use case or slice
, encapsulating
and grouping
all concerns
from front-end to back with vertical slice architecture
.
In traditional approach like clean architecture
, When adding
or changing
a feature in an application in n-tire architecture, we are typically touching many layers
in an application. We are changing the user interface, adding fields to models, modifying validation, and so on. Instead of coupling across
a layer in traditional architecture, we couple vertically along a slice
. We minimize coupling
between slices
, and maximize coupling
in a slice
.
With this approach, each of our vertical slices
can decide for itself
how to best fulfill the request. New features only add code, we're not changing shared code and worrying about side effects.
In traditional ASP.net controllers, related action methods are usually grouped in one controller. However, in my recent project, I opted to use the REPR pattern (Route-Endpoint-Presenter-Resource) design pattern instead. With this pattern, each action is given its own small endpoint, consisting of a route, the action, and an IMediator
instance (see MediatR), which is handled by a request-specific IRequestHandler to perform business logic before returning the result. This approach not only separates
the action logic
into individual handlers
, but it also supports the Single Responsibility
, Open Close Principle
and Don't Repeat Yourself
principles, resulting in clean
and thin controllers
.
To achieve better separation of concerns and cross-cutting concerns, I used the Mediator pattern in combination with CQRS
(Command Query Responsibility Segregation) to decompose features
into small
, vertical slices
. Each slice
has a group of classes specific to that feature
, including command
, handlers
, infrastructure
, repository
, and controllers
. By grouping them together, we can easily maximize performance
, scalability
, and simplicity
, as well as maintain and add features without creating breaking changes or side effects.
With CQRS
, we can reduce coupling
between layers and tune down specific methods to not follow general conventions. This is achieved by cutting each business functionality into vertical slices
, where each command/query handler is a separate slice. As a result, each handler can be a separate code unit
, even copy/pasted, allowing us to customize individual methods as needed. In contrast, in a traditional layered
architecture, changing the core generic mechanism
in one layer
can impact all methods
, which can be time-consuming
and challenging
to maintain
.
Overall, by using the REPR
pattern and CQRS
with the Mediator
pattern, we can create a better-structured
and more maintainable
application, with improved separation of concerns
.
For installing our requirement package with .NET cli tools, we need to install dotnet tool manifest
.
dotnet new tool-manifest
And after that we can restore our dotnet tools packages with .NET cli tools from .config
folder and dotnet-tools.json
file.
dotnet tool restore
Run this app in docker using the docker-compose.yml file with the below command at the root
of the application:
docker-compose -f ./deployments/docker-compose/docker-compose.yml up -d
If you like my work, feel free to:
Thanks a bunch for supporting me!
Thanks to all contributors, you're awesome and this wouldn't be possible without you! The goal is to build a categorized, community-driven collection of very well-known resources.
Please follow this contribution guideline to submit a pull request or create the issue.
This project is made available under the MIT license. See LICENSE for details.