CleanArchitecture
Provides a starter solution for Clean Architecture with ASP.NET Core, organizing code into Core, Infrastructure, Web, and Test projects.
What this file does
Provides a starter solution for Clean Architecture with ASP.NET Core, organizing code into Core, Infrastructure, Web, and Test projects.
When to use it
- Starting a new.NET Core application following Clean Architecture principles
- Learning Domain-Driven Design with a practical code example
- Building a modular, loosely-coupled ASP.NET Core solution from scratch
- Teaching or demonstrating Clean Architecture patterns in workshops
Assumes this stack
CleanArchitecture
A starting point for Clean Architecture with ASP.NET Core. Clean Architecture is just the latest in a series of names for the same loosely-coupled, dependency-inverted architecture. You will also find it named hexagonal, ports-and-adapters, or onion architecture.
Give a Star! :star:
If you like or are using this project to learn or start your solution, please give it a star. Thanks!
Now available as a project template within Visual Studio.
Learn More
- DotNetRocks Podcast Discussion with Steve "ardalis" Smith
- Fritz and Friends Streaming Discussion with Steve "ardalis" Smith
Goals
The goal of this repository is to provide a basic solution structure that can be used to build Domain-Driven Design (DDD)-based or simply well-factored, SOLID applications using .NET Core. Learn more about these topics here:
If you're used to building applications as single-project or as a set of projects that follow the traditional UI -> Business Layer -> Data Access Layer "N-Tier" architecture, I recommend you check out these two courses:
History and Shameless Plug Section
I've used this starter kit to teach the basics of ASP.NET Core using Domain-Driven Design concepts and patterns for some time now (starting when ASP.NET Core was still in pre-release). Typically I teach a one- or two-day hands-on workshop ahead of events like DevIntersection, or private on-site workshops for companies looking to bring their teams up to speed with the latest development technologies and techniques. Feel free to contact me if you'd like information about upcoming workshops.
Design Decisions and Dependencies
The goal of this sample is to provide a fairly bare-bones starter kit for new projects. It does not include every possible framework, tool, or feature that a particular enterprise application might benefit from. Its choices of technology for things like data access are rooted in what is the most common, accessible technology for most business software developers using Microsoft's technology stack. It doesn't (currently) include extensive support for things like logging, monitoring, or analytics, though these can all be added easily. Below is a list of the technology dependencies it includes, and why they were chosen. Most of these can easily be swapped out for your technology of choice, since the nature of this architecture is to support modularity and encapsulation.
The Core Project
The Core project is the center of the Clean Architecture design, and all other project dependencies should point toward it. As such, it has very few external dependencies. The one exception in this case is the System.Reflection.TypeExtensions package, which is used by ValueObject to help implement its IEquatable<> interface. The Core project should include things like:
- Entities
- Aggregates
- Domain Events
- DTOs
- Interfaces
- Event Handlers
- Domain Services
- Specifications
Many solutions will also reference a separate Shared Kernel project/package. I recommend creating a separate SharedKernel project and solution if you will require sharing code between multiple projects. I further recommend this be published as a nuget package (more likely privately) and referenced as a nuget dependency by those projects that require it. For this sample, in the interest of simplicity, I've added a SharedKernel folder to the Core project which contains types that would likely be shared between multiple projects, in my experience.
The Infrastructure Project
Most of your application's dependencies on external resources should be implemented in classes defined in the Infrastructure project. These classes should implement interfaces defined in Core. If you have a very large project with many dependencies, it may make sense to have multiple Infrastructure projects (e.g. Infrastructure.Data), but for most projects one Infrastructure project with folders works fine. The sample includes data access and domain event implementations, but you would also add things like email providers, file access, web api clients, etc. to this project so they're not adding coupling to your Core or UI projects.
The Infrastructure project depends on Microsoft.EntityFrameworkCore.SqlServer and Autofac. The former is used because it's built into the default ASP.NET Core templates and is the least common denominator of data access. If desired, it can easily be replaced with a lighter-weight ORM like Dapper. Autofac (formerly StructureMap) is used to allow wireup of dependencies to take place closest to where the implementations reside. In this case, an InfrastructreRegistry class can be used in the Infrastructure class to allow wireup of dependencies there, without the entry point of the application even having to have a reference to the project or its types. Learn more about this technique. The current implementation doesn't include this behavior - it's something I typically cover and have students add themselves in my workshops.
The Web Project
The entry point of the application is the ASP.NET Core web project. This is actually a console application, with a public static void Main method in Program.cs. It currently uses the default MVC organization (Controllers and Views folders) as well as most of the default ASP.NET Core project template code. This includes its configuration system, which uses the default appsettings.json file plus environment variables, and is configured in Startup.cs. The one dependency that you'll see used in this project is StructureMap, which is configured in the Startup.cs class. There are two reasons I prefer StructureMap to the built-in container that ships with ASP.NET Core (and which Microsoft states is only a starting point with minimal functionality). First, the above-mentioned technique for avoiding the need for project references between Web and Infrastructure projects. Second, its WithDefaultConventions convention saves a lot of boilerplate coding when you are wiring up implementations to interfaces that follow a simple naming convention. If for instance I have an INotificationService interface that I want to be resolved using an instance of NotificationService, in ASP.NET Core I would need to add a line of code to add this. With StructureMap's WithDefaultConventions convention, this wireup happens automatically. Any interface named IWhatever will be resolved by a class named Whatever.
The Test Project
In a real application I will likely have separate test projects, organized based on the kind of test (unit, functional, integration, performance, etc.) or by the project they are testing (Core, Infrastructure, Web), or both. For this simple starter kit, there is just one test project, with folders representing the projects being tested. In terms of dependencies, there are three worth noting:
-
xunit I'm using xunit because that's what ASP.NET Core uses internally to test the product. It works great and as new versions of ASP.NET Core ship, I'm confident it will continue to work well with it.
-
Moq I'm using Moq as a mocking framework for white box behavior-based tests. If I have a method that, under certain circumstances, should perform an action that isn't evident from the object's observable state, mocks provide a way to test that. I could also use my own Fake implementation, but that requires a lot more typing and files. Moq is great once you get the hang of it, and assuming you don't have to mock the world (which we don't in this case because of good, modular design).
-
Microsoft.AspNetCore.TestHost I'm using TestHost to test my web project using its full stack, not just unit testing action methods. Using TestHost, you make actual HttpClient requests without going over the wire (so no firewall or port configuration issues). Tests run in memory and are very fast, and requests exercise the full MVC stack, including routing, model binding, model validation, filters, etc.
What's inside
4 project descriptions (Core, Infrastructure, Web, Test) with design decisions and dependencies for each.
Change this for your project
- Replace
Microsoft.EntityFrameworkCore.SqlServerwith your preferred database provider if not using SQL Server - Replace
AutofacandStructureMapwith your chosen DI container or the built-in container - Replace
InfrastructureRegistryclass references with your own dependency registration approach - Replace
SharedKernelfolder content with your own shared types or a separate NuGet package
Where it goes
Save in docs/ or the repository root. Gives agents and new contributors a map of the codebase.
Worth borrowing
- Organizing code into Core, Infrastructure, Web, and Test projects to enforce dependency inversion
- Using a separate Infrastructure project to implement interfaces defined in Core, avoiding direct coupling to external resources
- Leveraging a DI container's conventions (e.g.,
WithDefaultConventions) to reduce boilerplate wiring
Related Documents
PCB Design Sources for Industry-Scale Testing
Lists GitHub repos and communities where you can download real PCB designs for testing optimization at scale.
Design Document: BharatSeva AI
Describes a 10-agent AWS system that helps India's informal workers access government schemes via voice-first, serverless architecture.
OpenClaw Enterprise Transformation Plan
Transforms a single-user AI agent into a dual-mode platform supporting both viral open-source and Fortune 500 enterprise deployments through phased security, IAM, audit, multi-tenancy, and Kubernetes features.
Qwen Image and Edit: Open-sourcing and Local GGUF Generations with Lightning
Documents the Qwen-Image and Qwen-Image-Edit models, covering architecture, training, benchmarks, ComfyUI setup, and prompting techniques for local GGUF deployment.