The CA-ESP 7.0 embraces the microservice pattern and the generated back-end will be comprised of many independent microservices.

A microservice is defined by a set of characteristics. A microservice should be:

  • Small: it is simple enough that can be comprehended with low effort; as a rule of thumb, it should be rewritable in a few weeks.
  • Focused on one task: when viewed from the outside, a microservice should tackle a single concern of the problem domain; however, when viewed from the inside, it may accomplish that task by performing complex operations.
  • Aligned with a Bounded Context (BC): each microservice has its share of the problem domain and its internal representation should be independent of other microservices.
  • Autonomous: it can change its implementation and grow without coordinating and interfering with the others.
  • Independently deployable: it can be built, tested and deployed regardless of the others.
  • Loosely coupled: its internal model representation does not leak outside; communication with other microservices is done by public APIs and contracts.

These characteristics make the microservice pattern a great decoupling strategy for distributed applications.

For reference:

Folder structure

If you follow DDD, you may be familiar with the idea of separating domain, infrastructure and application in your service. A single service normally contains the Domain and the Infrastructure folders, that can potentially be extracted in separate projects. Let’s take a closer look at the ShoppingCart.Store microservice solution structure.

Ca.ShoppingCart.Store/
├─ src/
│  ├─ Ca.ShoppingCart.Store.API/
│  │  ├─ Contracts/
│  │  ├─ Controllers/
│  │  ├─ Mappings/
│  │  ├─ Validation/
│  │  └─ Ca.ShoppingCart.Store.API.csproj
│  ├─ Ca.ShoppingCart.Store.Domain/
│  │  ├─ Abstractions/
│  │  ├─ Handlers/
│  │  ├─ Messaging/
│  │  ├─ Model/
│  │  ├─ Services/
│  │  └─ Ca.ShoppingCart.Store.Domain.csproj
│  └─ Ca.ShoppingCart.Store.Infrastructure/
│     ├─ Data/
│     ├─ Migrations/
│     ├─ Repositories/
│     └─ Ca.ShoppingCart.Store.Infrastructure.csproj
├─ tests/
│  ├─ Ca.ShoppingCart.Store.API.UnitTests/
│  ├─ Ca.ShoppingCart.Store.Domain.UnitTests/
│  └─ Ca.ShoppingCart.Store.Infrastructure.UnitTests/
└─ Ca.ShoppingCart.Store.sln

Domain

The Domain project (Ca.ShoppingCart.Store.Domain) contains all the domain-related knowledge, e.g, business concepts and rules. This is the core of the project and should not depend on other layers, that is, this project should not reference the other two.

Three folders are automatically generated for this project.

Model

This folder contains domain entities, value objects, etcetera. The model should follow the persistence ignorance and infrastructure ignorance principles: the entities should not have dependencies on the data access layer (e.g., implementing any type defined by the persistence framework). You normally want to design your model regardless of the persistence layer, but this is not always possible: there can be constraints that can be due both to the storage technology and the ORM technology.

Messaging

Hosts the message classes, i.e, the contracts that represent the information exchanged among the microservices when messaging (pub/sub). Each microservice defines its own messages and, for effective communication, those contracts must agree. Having separate classes instead of defining them in a common project is crucial in a microservice-based architecture in order to let each microservice evolve independently. Developers are responsible to keep the contracts in sync throughout the microservices while the application grows.

Repositories

If you use the repository pattern, repository interfaces will be generated automatically. This folder contains the interfaces of the generated repositories.

Infrastructure

The Infrastructure project (Ca.ShoppingCart.Store.Infrastructure) is mostly about data persistence. It will contain the ORM-related logic and repositories implementations, in case the repository pattern is being used. The CA-ESP and Dapr take care of most of the infrastructure, but this layer may contain custom infrastructure-related utilities. This project may also contain the implementations of the service classes if you are using a service layer; however, those implementations can also be defined in the Domain project, if they need not depend on the infrastructure implementations. For example, if you are using the repository pattern along with EntityFramework Core, you will use abstract repositories, which are defined inside the Domain project, instead of the DbContext directly: in this case, the service implementations can live inside the Domain project as well; conversely, if you reference the application DbContext directly inside your service layer, it must be implemented in the Infrastructure project, to keep the correct dependencies among the projects.

Only the Repositories folder is automatically generated by default.

Repositories

This folder will contain the repository implementations and the UnitOfWork implementation. The default implementations are based on Entity Framework Core, but this folder may contain other implementations as well.

Application

The Application project (Ca.ShoppingCart.Store.API) contains the application layer. It defines the public API that the service exposes to the outside world. This layer should not contain business or domain logic: it is responsible to delegate the work in response to interactions with other systems and should be kept thin.

Three folders are automatically generated for this project.

Contracts

This folder contains all the Data Transfer Objects (DTOs) that a client could use to communicate with the service. A DTO is a data structure which sole purpose is to carry data between the client and the server. A DTO is a POCO object which only contains properties (getters and setters) and has no behavior.

Controllers

This folder hosts the ASP.NET Core controller classes and SignalR hubs. The methods of a controller are generated from the microservice’s yaml file. An abstract base controller class will contain the abstract method definitions, so they can be implemented in the concrete controller.

Mappings

This folder contains the mapping classes. By default, AutoMapper profiles are generated here, but this folder may also contain custom mapping classes and functions.