- General info
- Technologies
- Architecture
- Setup
- MongoDB
- Jwt Authentication
- Unit Tests
- Jenkins and SonarQube
- Test API
This project is intended to provide core functionality for a .NET Core Web API using sound (albeit opinionated) architecture and popular NuGet packages used in modern .NET Core API development.
Project is created with:
- .NET Core 5.0 (based on ApiBoilerPlate)
- AutoWrapper
- AutoMapper
- FluentValidation
- Scrutor
- Serilog
- Swashbuckle
This starter template follows the onion architecture, although it is opionated in structure.
The onion architecture promotes loose coupling and abstracting between domain, repository, and service layers.
From the API, the hierarchy is as follows:
API --> Service --> Repository --> Domain
We can describe the advantage of this architecture by spelling out the hierarchy from bottom up:
Domain objects represent the database objects.
The Repository layer has intimate knowledge of the objects and the data access rules necessary to translate the objects from the underlying data source.
The Service layer interacts with the Repository layer (via interfaces) to perform business logic on the data to then present upward. The Service layer may also call other services (via interfaces).
The API Controllers serve as the Infrastructure layer, and generally call the Service layer (via interfaces). The API Controllers can call the Repository layer (via interfaces) but this is only if there is little to no business logic applied. General rule of thumb is to keep controller logic as light as possible... handle request, prepare response and status code.
For more information on the onion architecture, see Understanding Onion Architecture
Build the template on your local machine, from the root project
$ dotnet new -i .
The template is installed with shortname 'vbswebapi'
Now you can create your own project with your own namespace (based on the -n name). All folders, projects, and namespaces will use the name specified as the prefix.
$ dotnet new vbswebapi --help
VandenBrink Software Starter Web (C#)
Author: Steve VandenBrink
Options:
-mdb|--useMongoDB Sets up MongoDB with structured logging and boilerplate
bool - Optional
Default: false / (*) true
-jwt|--useJwt Sets up Jwt middleware and hash/salt utilities boilerplate
bool - Optional
Default: false / (*) true
For example, if you want to create a new project with the RootNamepace as 'MyProject', run the following
$ dotnet new vbswebapi -n MyProject
Then navigate to the MyProject folder created, inspect the code, and now all files are prefixed with the given namespace.
For example, Startup.cs in the API project is in namespace MyProject.API.
Make sure that after the project is created you perform:
$ dotnet restore
If you want to create a project that contains infrastructure for MongoDB, both for the backing data store AND structured logging, then use the --useMongoDB flag.
Example
$ dotnet new vbswebapi -n MyProject --useMongoDB
Example of Structured Logging in logs collection:
Take a look at the different appsettings which now have boilerplate for MongoDBSettings. The name specified in the -n flag will be used as application name, but you can change it to your liking.
"MongoDBSettings": {
"ApplicationName": "MyProject",
"Server": "localhost",
"Port": "27017",
"Timeout": 120,
"Admin": "",
"Password": ""
}
When you specify to use Mongo, then the controller and automapper profiles will use User from MyProject.Entities/Domain/Mongo.
A [MongoDocument("users")] attribute is placed on User so that the collection name in the database is called 'users'.
Also look at the repository (concrete class and interface) to see common CRUD operations utilizing async methods on IMongoDatabase.
Example of 'users' collection:
If you want to create a project that has infrastructure for Jwt authentication, then use the --useJwt flag.
When combined with the --useMongoDB flag, you have access to a full repository implementation that will register a user to the backing Mongo database and when logging in as that user you will receive a token with a few claims.
Please note that when jwt is used the [Authorize] attribute is placed on the UsersController and testing in Swagger will no longer work at this time.
A postman collection is contained in the repo so that you can import and use to test endpoints with authentication (using Bearer).
An additional parameter can be specified to include unit tests with xUnit, Moq, and the coverlet.msbuild package to generate coverage reports (can feed into SonarQube).
Presently this flag only works if you are using MongoDB and Jwt.
dotnet new vbswebapi -n MyProject --useMongoDB --useJwt --useTests
Also, since this template includes a preconfigured solution, the tests project will have to be added to the solution. Dotnet templates do not currently support conditionals for .sln files based on their documentation.
dotnet sln MyProject.API.sln add MyProject.API.Tests
Additional parameters can be specified to set up Jenkins CI with Code Coverage and Test Results
dotnet new vbswebapi -n MyProject --useJenkinsfile --sonarServer https://<server> --sonarProjectKey <sonar_project_key> --sonarProjectLogin <sonar_project_login>
Run the project
$ dotnet run
Open a web browser at localhost:5000/swagger
Try out and execute GET /api/Users
If you are not using MongoDB: You will get a 200 response with 1 user returned
If you are using MongoDB: You will get a 200 response with the users returned from the 'users' collection (may not yet exist)
Try out and execute POST /api/Users
Update the request JSON body to your liking.
If you are not using MongoDB: You will get a 200 response with 1 user returned including a dummy ID that the server might generate from the backing database.
If you are using MongoDB: You will get a 200 response with the user returned and an ObjectId (_id) set.
Additionally, try empty strings or deleting properties in the JSON body entirely. You will get a 400 type response with a list of validation errors (this is FluentValidation at work!).
Try out and execute GET /api/Users/{id}
If you are not using MongoDB: You will get a 200 response with the desired user returned with that id.
If you are using MongoDB: You will get a 200 response with the desire user returned from the 'users' collection.