To Run the solution:
- Clone the repo.
- Restore the nugget packages.
- You can set multiple projects as startup "API, Identity, and Client" like Below:
- Run the solution.
N.B No need to update the database - this line already does it for you Database.EnsureCreated();
The solution is build using:
- Domain Driven Design
- Repository Patten
- Unit of work
Our API project has connects to our domain layer using reflection as shown by the code below
builder.Services.AddMediatR(cfg =>
{
cfg.RegisterServicesFromAssembly(typeof(Program).Assembly);
cfg.RegisterServicesFromAssembly(typeof(GetExchangeRateQueryHandler).Assembly);
});
In our controller we call the Domain Layer Query Handlers as below.
On GetCurrentCoinMarket we pass the currency we want to get for example USD, ZAR,...
[HttpGet("GetCurrentCoinMarket")]
public async Task GetCurrentCoinMarketAsync(string currency)
{
CoinClassDto result = await _mediator.Send(new GetExchangeRateQuery {Currency = currency });
return Ok(result);
}
[HttpGet("GetCoinMarketHistory")]
public async Task GetCoinMarketHistoryAsync()
{
var result = await _mediator.Send(new GetExchangeRatesQuery { });
return Ok(result);
}
N.B We make sure our API is protected by the [Authorize] attribute.
Our App settings contain our database connection string and AppConfig to get the coin market data • The Key store the API key “This in production is set in env variables” • The Limit is a parameter that we can modify to pass to the coin market API to limit the data we can get
"AppConfig": {
"Key": "xxx-xxx-xxx",
"Limit": "50"
}
- DomainEntitites -these are our database models following the domain-driven design principles.
- DTO allow us to transfer data from the API to the Domain
- IRepositoy and IUnitOfWork are interfaces that are implemented in the Data layer
- QueryHandlers allow follow the CQRS Pattern which stands for Command and Query Responsibility Segregation, a pattern that separates read and update operations for a data store. It can improve performance, scalability, and security of the application.
We use Duende as our identity sever.
We are using Asp.net core MVC project. We authorize our home controller by the [Authorize] attribute and send requests to the API with the JWT token as below
using var client = new HttpClient();
var token = await HttpContext.GetTokenAsync("access_token");
client.SetBearerToken(token);
var currency = "USD";
var result = await client.GetAsync($"https://localhost:5445/api/CoinMarket/GetCurrentCoinMarket?currency={currency}");
if (result.IsSuccessStatusCode)
{
var model = await result.Content.ReadAsStringAsync();
var coinData = JsonConvert.DeserializeObject(model);
...
N.B: var currency = "USD"; the currency can set to any iso currency code.