View on GitHub
Clean Architecture Toolkit for .NET
Clean Architecture Toolkit is a clean, modular architecture foundation for .NET applications.
It embraces SOLID principles and focuses on maintainability, testability, and scalability through clear boundaries and pluggable design.

|   HOME   |   MODULE OVERVIEW   |   DEMO   |

Clean Architecture Toolkit for .NET

Table of contents

Getting Started

GitHub Actions Workflow Status nuget

The Clean Architecture Toolkit for .NET contains a set of modules.
Most of the modules can be used independently.
Some modules depend on other modules, in the documentation of each module you can find the list of the dependencies.

About this project

Gert Marginet

A note from the author
I build the Clean Architecture Toolkit in my free time.
Did you find an issue? Please create an issue on GitHub.
I will do my best to fix it as soon as possible, but I can not guarantee a due date.

About me
I’m Gert Marginet, a .NET software architect from Geraardsbergen, Belgium.
I have over twenty years of experience in software development, architecture and team leading.
I studied electronics and started out as a software engineer in 1997. Since then I have designed custom architectures and application frameworks for .NET.
Outside of work you find me hiking in nature or keeping ants, where I design and 3D-print their nests and outworlds myself.

Project Website | Personal Website | LinkedIn | GitHub

Module overview

Modules with the status in development are still being built.
Expect breaking changes in them before they are stable.

Module   Description Plans
Cat.Commands   Change state through one entry point. Describe a change as a command, write one handler for it, and let the processor find the handler. Plans
Cat.Decorators   Wrap handlers in decorators for cross-cutting work like logging, validation or tracing. Plans
Cat.EFCore   Configure Entity Framework Core entities the same way every time, with base classes for regular, temporal and reference data. Plans
Cat.EventAggregators   Let parts of your app talk to each other through in-process events, without direct dependencies.  
Cat.Expressions   Compile member access expressions once and reuse them, so repeated calls stay fast.  
Cat.Extensions   Small extension method libraries for enumerables, expressions, objects, service collections and strings.  
Cat.FluentWorkflows   Describe a business process as a list of steps in plain C#. Plans
Cat.Localizations In development Look up localized strings by key, without tying your app to one localization provider. Plans
Cat.Minimal.Api   Map service requests to minimal API endpoints that document the responses they return and share one error shape.  
Cat.Queries   Read data through one entry point. Describe a read as a query, write one handler for it, and let the processor find the handler.  
Cat.Responses   Return the outcome of an operation as a response, either succeeded with a value or failed with errors. Plans
Cat.ServiceRequests   Run application use cases through one entry point, with validation, logging and tracing decorators.  
Cat.Validators   Check a model against fluent rules and get every problem back in one response.  

Demo

A small bookshop that shows how the modules work together.
It has a Catalog service and an Order service, built with the application architecture and the service project structure described below.
Run them locally, try the endpoints and read the code as a working example.

See the demo README for what is in it and how to run it.

Application Architecture

The modules are built with a certain application architecture in mind.
It is a set of small services behind one entry point, talking to each other through messages.
Every service has a clear job, owns its data and keeps its business logic apart from the technology around it.

You are not required to follow this architecture to use the modules!
Take what fits your application and leave the rest.

Application Architecture

The diagram shows the building blocks and how they talk to each other.
Everything runs as containers in Azure Container Apps.

Clients

Clients are the applications people use, like a web app, a mobile app or a desktop app.
They know nothing about the services behind the gateway.

API gateway

The API gateway is the single front door of the application.
It receives every request from the clients, and every call between services, and forwards it to the right service.

Services

A service is a small, independently deployable application with one clear responsibility.
Services are where the business logic lives.

The Service Project structure chapter explains how the projects of a single service are organized.

Communication between services

Services talk to each other in two ways.

Synchronous
A service calls another service and waits for the answer.
Use it when the caller needs the result to continue.

Asynchronous
A service publishes a message on Azure Service Bus. Other services subscribe and react in their own time.
Use it when the sender should not wait, or when more than one service is interested in what happened.

Prefer messages when you can. They keep the services loosely coupled.

Database

Every service owns its data.
The database is an implementation detail of the service, not a shared integration point.

How a request flows through the system

  1. A client sends a request to the API gateway.
  2. The gateway forwards it to the right service.
  3. The service turns the request into a service request and processes it.
  4. A query reads data from the database. A command changes it.
  5. If the service needs data or an action from another service, it sends a request to the API gateway. The gateway forwards it to that service, and the answer comes back the same way.
  6. The service returns a response to the client, through the gateway.
  7. When something important happened, the service also publishes a message on Azure Service Bus. Other services pick it up and do their own work.

Design principles

How the modules fit in

The modules support the building blocks of a service.

Concern Modules
Handling a use case Cat.ServiceRequests
Writing data Cat.Commands
Reading data Cat.Queries
Consistent outcomes and errors Cat.Responses
Checking input Cat.Validators
Cross-cutting work Cat.Decorators
Business processes as steps Cat.FluentWorkflows
In-process events Cat.EventAggregators

Service Project structure

Every service in the application architecture is built from the same set of projects.
Each project has one job, and the references between them keep the business logic free of technology.

Again you are not obliged to follow this structure to use the modules!
The Cat.Demo.CatalogService projects in the demo folder are a small working example of it.

Service Project structure

The diagram uses ServiceName as a placeholder for the name of your service.

Overview

Project Purpose Required
ServiceName.Api Host that handles HTTP requests and runs the workers Yes
ServiceName.Scheduler Background worker that runs time-based work Optional
ServiceName.EventProcessor Background worker that handles incoming messages Optional
ServiceName.CoreService Business logic Yes
ServiceName.Infrastructure Database and external integrations Yes
ServiceName.Contracts Service requests, contract models and enums Yes
ServiceName.DataModels Entities and query result models Yes
ServiceName.Infrastructure.DataAccessTooling Generates the entities from an existing database Optional
ServiceName.CoreService.Tests Unit tests of the business logic Optional

ServiceName.Api

The API is the one and only host of the service.
It is the executable that runs in the container, and every service has one.

The API contains no business logic.
It sets up the application, registers the modules in the DI container and passes the work on to the core.

The API references the CoreService, Contracts and Infrastructure projects, and the worker projects it runs.

Development endpoints
In debug mode the API has an extra development endpoint group.
It lets you try out the service without the real triggers.

Background workers

Not all work comes in over HTTP.
Background workers handle work that starts on its own, like a timer or a message.

A worker is not a host. It has no executable of its own.
It lives in its own project and runs inside the API.

Like the API, a worker contains no business logic.
Every unit of work becomes a service request that the core handles.

ServiceName.Scheduler

ServiceName.EventProcessor

Both are optional. Add them only when the service needs them.

ServiceName.CoreService

The core is the heart of the service. It holds the business logic.

A handler never talks to the database itself.
It sends a query or a command to its processor, and the infrastructure does the rest.

The core references the Contracts and DataModels projects.

ServiceName.Infrastructure

The infrastructure is everything the core should not know about.

External integrations, like an email provider or a storage account, live here too.
Treat them like a database. The core never calls them directly. It sends a query or a command and a handler talks to the integration.

The infrastructure references the CoreService and DataModels projects.
That way the dependency points inwards. The core defines the queries and commands, the infrastructure implements the handlers.

ServiceName.Contracts

The contracts project holds the contract of the service, the way the outside world talks to it.

It has almost no dependencies, so it is easy to share. Sharing it is a choice, not a rule.

Share it or not
A caller of the service, whether another service or a client, can use the contract in two ways.

Both are fine. Decide per situation, and per caller. A .NET client and a service that change together can share. A client in another technology, or a service owned by another team, probably should not. You can mix both in one application.

ServiceName.DataModels

The data models project holds the data classes that come out of the database.

Both the CoreService and the Infrastructure project use them.
They are internal to the service. Never hand them out through the API. Map them to a contract model first. We suggest the Mapperly NuGet package for this.

ServiceName.Infrastructure.DataAccessTooling

This project is only needed when the service uses a database first approach.
It generates the entities and the database context from an existing database, for example with the Entity Framework Core scaffold command.

Does the service use a code first approach? Then skip this project.
The entities are written by hand in the DataModels project, and the migrations live in the Infrastructure project.

ServiceName.CoreService.Tests

This project holds the unit tests of the business logic.

Reference rules

Future modules

These modules do not exist in this repository yet.
They are ideas to support the application architecture and the service project structure even more.

Module Idea
Cat.Messaging Publish and consume messages on Azure Service Bus with the same handler style as the other modules.
Cat.EventProcessor Worker support that turns incoming messages into service requests.
Cat.Scheduling Worker support that turns schedules into service requests.
Cat.Sagas Long running workflows that send a message, wait for the answer and carry on.
Cat.Api.Gateway The single front door of the application. It routes the calls of clients and services and checks the token in one place.
Cat.Api.Client Typed API clients that call other services through the API gateway.
Cat.Dapper Base query and command handlers for Dapper, including bulk operations.
Cat.Auditing Records who changed what and when.
Cat.Caching A caching decorator for queries.
Cat.Authorization A decorator that checks permissions before a service request runs.
Cat.Resilience Retry and circuit breaker decorators for calls to other services and integrations.
Cat.Telemetry Shared tracing and metrics setup for all services.
Cat.UnitTesting Helpers for unit tests, like test doubles for processors and responses, in small projects you pick from.
Cat.Templates dotnet new templates that create a new service with this project structure.

Other future things

These are not modules, but we plan them too.

Item Idea
CAT skills for developers Claude Code skills, shipped as a plugin, that teach Claude the CAT conventions in the projects of the developers who use the toolkit.