This project uses many development patterns as learning model:
- DDD - Domain Driven Design inspired structure
- SelfValidation - Entities have auto-validation and are responsible for their own business rules validity state.
- Repository - The data layer communication is done through repositories
- Application Services - Data access is done through application services that can be reused by different applications (eg. Web and gRPC Services)
- AutoMapper - Mapping from entities to and from view models and DTOs is handled by AutoMapper
- IoC - Dependency injection is handled by .Net Core DI framework
- Makefile - Easier to remember commands to execute common tasks
- ... (more to come)
This was originally built on .Net Framework 4.5, for Windows only, in 2015 and now ported to .Net Core 6.0 in 2022.
The major changes from the original project, appart from the obvious upgrades related to .Net Core, are:
- Ninject was removed in favor of the existing .Net Core DI framework, as the use case is simple enough to be handled with that
- Added some tests with xUnit to cover main domain logic
- Services layer was changed to gRPC services instead of the previous WPF services
- Added Makefile to streameline most common project tasks
- Added docker-compose.yml for running additional services, like the MySQL 8 database server
The command-line tool make
is your friend here. Make sure to explore the available targets.
The most common ones will be listed bellow.
Tip❗ All make commands need to be run from the project's root folder (where the Makefile file is located).
Dependencies are managed through the dotnet
command-line tool and all of them can be installed with:
make deps
That also includes downloading MySQL 8 docker image to make sure docker is correctly setup and speedup other steps.
This project uses EntityFramework code-first approach and code migrations to generate and update the database.
To run the project for the first time, it is necessary to have a MySQL server running to apply migrations before the application can be started:
# runs a MySQL 8 container in a non-interactive/non-blocking way
make start-database
# generate database schema, tables and seed data
make update-database
The easiest way to see the database contents via command-line is to run the mysql
tool within the container:
$ docker-compose exec -it mysql mysql -uroot -proot
mysql> USE TestePraticoDB;
mysql> SHOW TABLES;
mysql> SELECT * FROM __EFMigrationsHistory;
Tip❗ The database server can be accessed through the localhost port
3306
. Depending on OS version and settings, it may be required to target the localhost IP address127.0.0.1
or the unspecified address IP address0.0.0.0
instad of usinglocalhost
.
There are two ways of running the two applications, Web and gRPC services, and both are available through Makefile targets:
Local development with hot-reload:
# start the web application in watch mode, with hot-reload enabled
make watch-web
# start the gRPC services application in watch mode, with hot-reload enabled
make watch-services
Running them locally in development mode:
# start web application in development mode
make start-web
# start gRPC services in development mode
make start-services
Tip❗ All previous commands are blocking, so you may want to start them in a separate terminal window.
make tests
Application settings are stored in appsettings.json
files, with environment specific settings on appsettings.${environment}.json
(eg: appsettings.Development.json
).
The project structure is inspired on DDD (Domain Driven Design) approach, with layered or onion architecture, having the outer-most layers depending on inner-most layers and never the other way around.
The layers, presented in order of inner-most to outer-most:
The most central layer, where business logic should live, is the Domain
layer. This layer houses business entities, main data interfaces and the domain services, which are responsible for business logic.
This project should't depend on any other layer to have pure domain specific logic.
The Data
layer, where the storage related code lies, with the respository implementations, entity configuration and migrations for EntityFramework.
This layer depends on the Domain
layer and possibly Common
.
The Application
layer contains the common application logic in application services that consume domain services to perform its operations. This layer is meant to be reused by any application that is built on top of the inner layers, like web applications, APIs, gRPC services or command-line interfaces.
This layer depends on the Domain
layer and possibly Common
. Although it works with repositories, it relies on interfaces and not the implementations from the Data
layer.
The Services
layer is an example of gRPC server application that makes use of the Application
services to perform CRUD operations.
In development mode, this server offers server reflection to make it easier to test it with gRPC enalbed tools, like Postman.
It's protobuf definitions are stored in the TestePratico.Services/Protos
folder and can be used to generate client applications for it.
This layer depends on Domain
, Application
and possibly Common
layers.
The Web
application layer is an example of UI application that is built on top of the Application
services layer to perform CRUD operations on entities, using an MVC project structure for proper separation of concerns and easy maintainability.
This layer depends on Domain
, Application
and possibly Common
layers.
The Common
cross-cutting concerns layer, where all logic that is not domain-specific and can be used in multiple layers should reside. Things like custom libraries, IoC/DI mappings, loggers, wrappers for utility tools, etc., must be implemented in this project.
This layer shouldn't depend on other layers, but the Domain
one, to avoid cyclic dependency issues.