👩‍🏠This is a WIP version!
For the sake of simplicity, everything exists inside Docker Compose. Run to build and start the system:
docker-compose up --build
All methods are available through this API gateway.
http://localhost:4000
http://localhost:48500
http://localhost:46379
| Service | Description |
|---|---|
| Identity | Issues JWT tokens. Stores users in an MongoDB database. |
| Carsharing | Provides methods for searching, booking and returning cars. Stores cars in a MongoDB database. Requires JWT authentication. Does not provide methods for creating or removing cars from the database, i.e., cars simply exist. Does not have any payment mechanism, i.e., cars are free. |
| Geocoding | Provides methods for converting an address to coordinates and vice versa. |
| Method | Description |
|---|---|
POSTÂ api/v1/identity/create Query parameters: username: string, required, unique password: string, required |
Creates a user with the specified username and password. |
GETÂ api/v1/identity/jwt Query parameters: username: string, required password: string, required |
Issues a JWT for the specified user. |
| Method | Description |
|---|---|
GETÂ api/v1/cars/available Query parameters: latitude: double, required longitude: double, required radius: double (meters), 500 meters by default |
Searches for available cars in the specified area. Only offers mock functionality, i.e., ignores coordinates and returns all available cars. |
POSTÂ api/v1/cars/book { CarId: string } |
Books a car with the specified Id. Accepts JSON. Not thread-safe. |
POSTÂ api/v1/cars/return { CarId: string, Latitude: double, Longitude: double } |
Marks a car with the specified Id as available and updates its location. Accepts JSON. |
Requires JWT authentication:
Authorization: Bearer <token>
Tokens are issued by api/v1/identity/jwt.
| Method | Description |
|---|---|
GETÂ api/v1/geocode/forward Query parameters: address: string, required |
Returns coordinates of the specified location. Only works for Uusimaa. |
GETÂ api/v1/geocode/reverse Query parameters: latitude: double, required longitude: double, required |
Returns an address of the specified location. |
Source: HERE Geocoder API.
API gateway exposes with their original routes, e.g., api/v1/cars/available is mapped to api/v1/cars/available.
(1) Services register themselves in Consul on startup:
var ip = Dns.GetHostEntry(Dns.GetHostName()).AddressList.FirstOrDefault(x => x.AddressFamily == AddressFamily.InterNetwork);
var port = 80;
...
consulClient.Agent.ServiceRegister(serviceRegistration).Wait();
(2) Services also register their api/v1/health methods so that Consul can run health checks.
(3) API Gateway is implemented with Ocelot that offers a support for Consul service discovery:
"ServiceDiscoveryProvider": {
"Type": "Consul",
"Host": "consul",
"Port": 8500
}
Consul is only used to discover service IPs. MongoDB, Redis and Consul itself are accessed through their container names.
consul-template daemon is used for dynamic configuration. At this point, only Carsharing mircoservice includes support for dynamic configuration.
In order to change a configuration, a file with Carsharing/appsettings.json key must be created in http://localhost:48500/ui/dc1/kv. This will replace original service configuration file.
consul-template is started in a Dockerfile and runs alongside with Carsharing.dll:
./consul-template -consul-addr "consul:8500" -template "appsettings.tpl:appsettings.json"
dotnet Carsharing.dll
Geocoding mircoservice caches the data retrieved from HERE Geocoder API in a Redis distributed cache:
services.AddDistributedRedisCache(options =>
{
options.Configuration = "redis:6379";
});
Identity mircoservice stores users in a MongoDB:
public class User
{
[BsonId]
[BsonRepresentation(BsonType.ObjectId)]
public string Id { get; set; }
[BsonElement("Username")]
public string Username { get; set; }
[BsonElement("Salt")]
public string Salt { get; set; }
[BsonElement("Hash")]
public string Hash { get; set; }
}
It validates username+password combinations and issues JWT tokens. Identity and Carsharing mircoservices share the symmetric security key.
services
.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(x =>
{
...
x.TokenValidationParameters = new TokenValidationParameters
{
...
ValidateIssuerSigningKey = true,
IssuerSigningKey = new SymmetricSecurityKey(Encoding.ASCII.GetBytes("secret")),
};
});
- Microsoft – Designing a microservice-oriented application
- Microsoft – Implement the microservice application layer using the Web API
- .NET Application Architecture: Reference Apps – eShopOnContainers
- Microsoft – Data considerations for microservices
- Microsoft – The API gateway pattern versus the Direct client-to-microservice communication
- Pitstop – Garage Management System
- Building Microservices with ASP.NET Core by Kevin Hoffman – Chapter 8. Service Discovery*
- GoogleCloudPlatform – Hipster Shop: Cloud-Native Microservices Demo Application
- Make secure .NET Microservices and Web Applications
