A Clean Architecture shop API that puts CQRS and event sourcing in C#
ASP.NET Core, C#, CQRS Event Sourcing, REST API, DDD, SOLID Principles and Clean Architecture
At a glance
- What is it?
- This ASP.NET Core reference solution splits a shop domain into application, domain, infrastructure and presentation layers, with MediatR handling commands and queries, Ardalis.Result carrying outcomes, and MongoDB and SQL Server alongside Redis in Docker Compose. It is MIT licensed, targets .NET 10, and is a teaching structure rather than a library you can drop into an existing app.
- Who is it for?
- Adopt this repository as a reference for how a .NET 10 team can lay out a CQRS and event sourcing solution, with the layers, the result type and the test projects already arranged in a working shape. Do not adopt it as a starting point for a product, since it is a demonstration solution with a shop domain, three datastores and a distroless image to inherit whether you need them or not.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 15 days ago.
- What is it written in?
- Mainly C#, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 22, 2026, and from our analysis. They are not legal advice.
Editorial analysis
A four layer solution, split by dependency direction
The project presents itself as an open source reference implementation of ASP.NET Core using Clean Architecture, CQRS and Event Sourcing, with the stated aim of showing how to structure a production ready solution around separation of concerns, testability and maintainability. The organisation is described as layered and domain first.
The layering breaks into four responsibilities: application, domain, infrastructure and presentation, with the project documentation emphasising a clear separation of responsibilities across them. Inside the domain layer sit entities, value objects and aggregates, plus domain events and notifications. The application layer carries the CQRS split, with command and query responsibilities separated, and adds the Repository and Unit of Work patterns. The result based handling is described as covering predictable application outcomes.
The top level of the repository matches that story. There is a Shop.slnx solution file, a src directory, a tests directory, a global.json, Directory.Build.props, Directory.Packages.props for central package versions, a nuget.config, an .editorconfig and an img directory holding the CQRS pattern diagram referenced in the documentation.
The naming is worth pausing on. A file extension of .slnx is the newer XML style solution format, and the documentation uses it consistently in the build and test commands, so the tooling assumed here is recent .NET rather than a long-lived legacy solution layout.
The stack is wide, and every layer has a named library
The technology list is long enough that the architecture is really a set of decisions about which library owns which concern. On the framework side, ASP.NET Core 10 and Entity Framework Core 10, with EF Compiled Queries called out separately as a performance-oriented feature. On the messaging and mapping side, MediatR for in-process messaging, AutoMapper for object mapping, FluentValidation for input validation, and Ardalis.Result for result based error handling. Resilience comes from Polly, which provides the retry and circuit-breaker policies.
The API surface is documented with OpenAPI and Scalar, and health checks are part of the setup, so the running service exposes the endpoints you need to see whether it is up. Storage is deliberately plural: Microsoft SQL Server, MongoDB and Redis all appear, which lines up with a solution that uses a relational store for one kind of data, a document store for another, and a cache for a third.
Testing is not an afterthought here. xUnit runs the tests, FluentAssertions makes the assertions readable, NSubstitute handles dependency mocking, and Coverlet reports coverage. The repository also carries CI workflows for a .NET build, SonarCloud, CodeQL and DevSkim analysis, with a SonarCloud badge set covering lines of code, coverage, maintainability rating, security rating, vulnerabilities, bugs and code smells. That is a large amount of tooling, and it is a signal about what kind of team this structure is aimed at.
The local run needs .NET 10, Docker and three credentials
Running the thing locally is the part that tells you what the dependencies really cost. The prerequisites are the .NET SDK 10, Docker Desktop or a Docker Engine with Compose support, and a terminal in the repository root. The sequence is clone, build, configure, compose up.
The build step cleans and builds the solution in one command:
dotnet clean Shop.slnx --nologo /tl && dotnet build Shop.slnx --nologo /tlThen the environment file, which the documentation asks you to create with the passwords and ports for the three services:
MSSQL_SA_PASSWORD=YOUR_STRONG_!Passw0rd
REDIS_PASSWORD=YOUR_STRONG_!Passw0rd
MSSQL_PORT=1433
MONGO_PORT=27017
REDIS_PORT=6379
ASPNETCORE_ENVIRONMENT=DevelopmentWith that in place, one command starts everything:
docker compose up --buildThe API documentation is then served by Scalar, and the documentation points you at:
http://localhost:{port}/scalar/v1Note the placeholder in that URL. The port is not fixed in the documentation, which means it comes from the launch configuration or the compose mapping rather than a constant, so the exact address has to be read from the running container rather than assumed.
The compose file wires three datastores and one API container
The compose file is where the dependency shape becomes concrete. The SQL Server service runs the mcr.microsoft.com/mssql/server:2022-latest image, sets ACCEPT_EULA and MSSQL_PID to Express, fixes the collation to SQL_Latin1_General_CP1_CI_AS, and keeps its data in a named volume mounted at /var/opt/mssql. MongoDB runs the mongo:latest image with a volume at /data/db, and Redis runs redis:latest with a command that requires a password:
command: redis-server --requirepass ${REDIS_PASSWORD}Each service publishes its port from an environment variable rather than a hard-coded number, and each has a JSON file log driver capped at ten megabytes and three files. All of them share a network called shop-network, so the API container reaches them by service name rather than by IP, and the SQL Server connection string in the API service is written with the service host and the sa user, matching the port that comes from the environment.
The API service itself is built from a Dockerfile in the public API project, named shop-api:latest, and it reads the .env file through env_file. It also sets ASPNETCORE_ENVIRONMENT from the environment, and the compose file is paired with an override file, which is where the local development settings live. The technology list mentions distroless .NET images, so the runtime container is built without a full distribution base, which is the right default for something that will be published to a registry.
Two test projects, and a split between domain logic and infrastructure
The testing strategy is layered in the same way as the code. Unit tests live in tests/Shop.UnitTests and focus on domain entities, value objects, validators, handlers, queries and mapping logic, so the pure logic is checked without a database or a network call. Integration tests live in tests/Shop.IntegrationTests and cover API and infrastructure behaviour, which is the part that needs the containers.
The unit test project carries a specific stack: xUnit for execution, FluentAssertions for the assertions, NSubstitute for mocking, Coverlet for coverage, and Microsoft.EntityFrameworkCore.Sqlite for database backed tests. The SQLite provider is the detail that makes the unit tier practical, since it lets repository behaviour be exercised against a real relational engine without standing up the SQL Server container.
Running them is either the whole solution or a single project:
dotnet test tests/Shop.UnitTests/Shop.UnitTests.csprojdotnet test Shop.slnxThe project documentation also describes running a subset of tests by name, though the command for that is cut off in the section reproduced here, so the flag to pass is not something you can copy from what is available. The distinction between the two tiers is the part worth copying into your own work, since the failure mode of a reference solution is a test suite that cannot run without the entire infrastructure, and this one is built to avoid that.
Event sourcing and CQRS as a commitment, not a decoration
It is worth being blunt about what this solution assumes. Event Sourcing for persisting state transitions and CQRS for separating command and query responsibilities are listed as core elements of the architecture rather than optional patterns, and the domain layer is described as carrying domain events and notifications. That is a serious commitment for a team to inherit. Rebuilding state from a stream of events is a different operational model from updating rows, and it changes how you debug, how you correct mistakes and how you talk about consistency.
The two libraries that carry the application layer's everyday vocabulary are MediatR, for in-process messaging, and Ardalis.Result, for result based error handling. Together they determine how a handler communicates. MediatR means handlers are resolved through a mediator and requests travel as messages, which is a large part of the test surface, since NSubstitute and FluentAssertions are pointed at handlers and queries. Ardalis.Result means a handler returns a result type rather than throwing, and the domain documentation names result based handling as one of the things the layer is responsible for.
The honest read is that this repository is a demonstration of how the pieces fit, not a small library. There is no package to install and no NuGet package to reference. The value is in the arrangement, and the cost of adopting that arrangement is inheriting MediatR, Ardalis.Result, AutoMapper, FluentValidation, Polly, EF Core, MongoDB and Redis at once.
MIT licensed, released quarterly, pushed to recently
The licence is MIT, with a LICENSE file at the top of the repository and a licence badge in the documentation, so the code can be copied into a commercial project without the obligations that copyleft would impose. The project metadata also lists ASP.NET Core, C#, REST API, DDD, SOLID principles and Clean Architecture in the repository topics, alongside the net10 tag, which tells you the intended runtime.
On the release rhythm, the tags are v2.2.0 from 2026-07-10, v2.1.0 from 2026-04-30 and v2.0.0 from 2025-11-19. That is a v2 line with roughly quarterly tags, and the version numbering has moved past 1.x, which suggests the structure itself has changed over time rather than the project just accumulating features. The last push was on 2026-10-08, which is more recent than the newest tag, so the branch contains work that has not been cut into a release.
The repository also carries a .dockerignore, a .gitattributes, a .gitignore and a nuget.config, and the CI workflows for build, SonarCloud, CodeQL and DevSkim are the visible proof that the analysis claims are enforced on every push rather than aspirational.
Editorial conclusion
Adopt this repository as a reference for how a .NET 10 team can lay out a CQRS and event sourcing solution, with the layers, the result type and the test projects already arranged in a working shape. Do not adopt it as a starting point for a product, since it is a demonstration solution with a shop domain, three datastores and a distroless image to inherit whether you need them or not. Before you borrow the structure, check three things: whether your team is comfortable with MediatR and Ardalis.Result as the vocabulary of the codebase, whether the EF Core and MongoDB split matches the persistence you actually need, and whether the repository root .env file and the docker-compose credentials are replaced rather than copied into your own environment.
Frequently asked questions
How do I run the ASP.NET Core Clean Architecture CQRS sample locally?
You need the .NET SDK 10 and Docker. Build the solution with dotnet clean Shop.slnx --nologo /tl && dotnet build Shop.slnx --nologo /tl, create a .env file with the SQL Server, Redis and MongoDB passwords and ports, then run docker compose up --build and open the Scalar documentation endpoint.
Which databases does this Clean Architecture CQRS solution use?
Microsoft SQL Server, MongoDB and Redis. The compose file runs the mssql/server:2022-latest image, mongo:latest and redis:latest, and the API container connects to them over a shared shop-network with a connection string that names the service host.
What testing libraries does the solution use?
xUnit for execution, FluentAssertions for assertions, NSubstitute for mocking, Coverlet for coverage and Microsoft.EntityFrameworkCore.Sqlite for database backed tests. Unit tests sit in tests/Shop.UnitTests and integration tests in tests/Shop.IntegrationTests.
Is this Clean Architecture CQRS repository an installable library?
No. It is described as an open source reference implementation and a demo of how to structure a solution, so you read and copy from it rather than reference a package. The result handling is built on Ardalis.Result and the in-process messaging on MediatR, which are the dependencies a team would inherit along with the structure.
How do I remove the deployed infrastructure for this solution?
The documentation in the repository does not include a teardown command for the compose stack. The services are defined in docker-compose.yml with named volumes for the SQL Server, MongoDB and Redis data, so those volumes persist after the containers stop and need to be removed separately.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/jeangatto-asp-net-core-clean-architecture-cqrs-event-sourcing)