Applications that use the principles of dependency inversion and problem-oriented design have a similar architecture. Over the years it has had many different names. At first it was the hexagonal architecture, which was succeeded by the ports and adapters architecture. Today, it is called a multilayer or pure architecture. This e-book uses the term “pure architecture”.

The eShopOnWeb reference application uses a pure architecture approach to organize code into projects. The solution template, which you can use as a starting point for your own ASP.NET Core solutions, is in the GitHub ardalis/cleanarchitecture repository. Alternatively, you can install the template from NuGet.

Under a pure architecture, the central elements of an application are its business logic and model. In this case, the business logic does not depend on access to data or other infrastructures, i.e. the standard dependency is inverted: the infrastructure and implementation details depend on the application core. This functionality is achieved by defining abstractions or interfaces in the application kernel that are implemented by types defined in the infrastructure layer. Such an architecture is usually drawn as a series of circles with a common center, which looks like a slice of an onion.
Since the UI layer has no direct dependencies on the types defined in the infrastructure project, it will be just as easy to change implementations for testing purposes or if application requirements change. ASP.NET Core offers built-in support for implementing dependencies, making this architecture the optimal approach for structuring non-trivial monolithic applications.

For monolithic applications, the application core, infrastructure, and user interface projects run as a single application.

Arranging the code within a pure architecture
In a pure architecture solution, responsibilities are clearly defined for each project. In fact, each project will own certain types, and the projects will have folders corresponding to those types.

Application Core
The application core contains the business model, which includes entities, services, and interfaces. Such interfaces include abstractions for operations that will be executed using the architecture, including data or file system access operations, network calls, etc. In some cases, the services or interfaces defined in this layer must handle types that are not entity types that have no dependencies on the user interface or infrastructure. They can be defined as simple data transfer objects.

Application Kernel Types

Entities (retained business model classes)
Aggregates (groups of entities).
Interfaces
Domain services
Specifications
Custom exceptions and condition suggestions.
Domain events and handlers.

Infrastructure
Typically, an infrastructure project includes a data access implementation. In a typical ASP.NET Core web application, this implementation includes the Entity Framework (EF) DbContext, any defined EF Core objects, and the data access implementation classes. The most common approach to abstracting data access implementation code is to use a constructive repository template.

In addition to implementing data access, the infrastructure design should also include implementations of services that need to interact with infrastructure tasks. These services should implement the interfaces defined in the application kernel. Thus, the infrastructure must contain a reference to the application kernel project.

Infrastructure Types

EF Core types (DbContext, Migration)
Data access implementation types (repositories)
Infrastructure related services (e.g. FileLogger or SmtpNotifier)

User interface layer
The user interface layer in an ASP.NET Core MVC application acts as the entry point for the application. This project must reference the application core layer, and its types must interact with the infrastructure strictly through the interfaces defined in the application core. The UI layer should not allow direct instance creation for infrastructure layer types, nor static calls to them.

UI Layer Types
Controllers
Custom filters.
Middleware middleware.
Views
View Models

Startup
The Startup class or Program.cs file is responsible for setting up the application and associating implementation types with interfaces. The location where this logic is executed is called the application composition root. It ensures that dependencies are properly implemented at runtime.