The Crypto-Exchange web application sample obtains the top 100 crypto currencies from https://coinmarketcap.com/api and converts their values to USD, EUR, BRL, GBP, and AUD (rates obtained from https://exchangeratesapi.io/).
TaskScheduler is in charge of scheduling two tasks:
- UpdateRates: Get rates from https://exchangeratesapi.io/
- UpdateListings: Get listing from https://coinmarketcap.com/api
Because these free APIs have a monthly request limit, we must compute the number of times we can fetch the data (in days, hours, and minutes). The app schedules tasks based on the times.
sequenceDiagram
TaskSchedulerOptions->>CalculateRateLimit: Read MonthlyRequestLimit
CalculateRateLimit->>TaskScheduler: Convert MonthlyRequestLimit to the times
TaskScheduler->>ScheduleJobs: Schedule UpdateRates, UpdateListings recurring jobs based on API request limit
sequenceDiagram
participant TaskScheduler
participant UpdateRates
participant Notify
participant CqsCommandBus
participant RateRepository
TaskScheduler->>UpdateRates: Run the job
UpdateRates->>CqsQueryBus: Send FetchRatesQuery
CqsQueryBus->>CqsQueryHandler: Handle the FetchRatesQuery
CqsQueryHandler->>RateService: GetRates
RateService->>RestQueryBus: Send GetRates request query
RestQueryBus->>+api.apilayer.com: Get /exchangerates_data/latest
alt OK
api.apilayer.com-->>RestQueryBus: RatesResponse
RestQueryBus-->>RateService: RatesResponse
RateService-->>CqsQueryHandler: RatesResponse
CqsQueryHandler-->>UpdateRates: RatesResponse
UpdateRates-->>CqsCommandBus: Send UpdateRatesCommand
CqsCommandBus-->>RateRepository: Upsert RatesResponse
CqsCommandBus-->>UpdateRates: Upserted
UpdateRates-->>Notify: Notify all of clients
else ERROR
api.apilayer.com-->>-RestQueryBus: Exception
RestQueryBus-->>RestQueryBus: Catch Exception, Fill the exception in the ExternalCommandResult
RestQueryBus-->>RateService: RatesResponse with Exception
RateService-->>RateService: Throw Exception
end
The sequence is same as UpdateRates
App uses SignalR to send the updates to the clients. SignalR first attempts to establish a WebSocket connection if possible.
sequenceDiagram
participant WebBrowser
participant WebServer(Notify)
WebBrowser->>WebServer(Notify): Subscribe
WebServer(Notify)->SignalR: Send the updates to clients
SignalR->WebBrowser: Updates
The app adheres to Clean Architecture.
Explanation:
-
Core.Abstraction: The innermost layer is free of dependencies.
-
Domain: Implements the entity interface using
Core.Abstraction
. -
Application:
Domain
is used for entities (input) andIntegration
is used for DTOs (output). -
Integration: Makes use of
Core
to implement IMediatR commands and queries, as well as DTOs. -
Core: Implements technologies using
Core.Abstraction
and registers IMediatR commands and queries usingCore.Infrastructure
:-
IMediatR: For the
CQS
pattern (at the class or component level). -
Newtonsoft: To serialize
-
RestSharp: For rest requests
-
FluentValidation: This is used for DTO validations.
-
-
Core.Infrastructure: Contains an assembly helper that allows us to register all classes using a single interface to IoC.
-
Application.TaskScheduler: This layer uses
Core.Abstraction
andIntegration
to schedule a task. It also uses 'HangFire' as the technology. -
Data.InMemory: For entity access, uses
Core.Abstraction
andDomain
. -
Application.ExchangeRatesApi:
Application
andIntegration
are used. It contains theExchangeRatesApiService
, which is in charge of retrieving rates fromapi.apilayer.com
. -
Application.CoinMarketCap:
Application
andIntegration
are used. It includes theCoinMarketCapService
component, which is in charge of retrieving listings fromhttps://pro-api.coinmarketcap.com
. -
Web:
-
Application.TaskScheduler: For job registration.
-
Data.InMemory: This method is used to register
InMemory
repositories. -
Application.ExchangeRatesApi: To register the
ExchangeRatesApiService
class. -
Application.CoinMarketCap: To register
CoinMarketCapService
-
Integration: Using DTOs for the end-points.
-