AggregatingRateProvider Class
Definition
- Namespace
- Bodu.Financial.ExchangeRates.Caching
- Assembly
- Bodu.Financial.ExchangeRates.Caching.dll
- Package
- Bodu.Financial.ExchangeRates.Caching 1.0.0
Groups several named IDatedRateProvider children behind a single entry point, combining them through a configurable IRateAggregationStrategy with optional per-currency-pair routing.
public sealed class AggregatingRateProvider : IDatedRateProvider, IRateProvider, IHistoricalRateProvider
- Inheritance
-
AggregatingRateProvider
- Implements
- Inherited Members
- Extension Methods
Examples
// Wrap each source in its own cache, then group them with per-FX-pair routing.
var rba = new CachingRateProvider(rbaSource, new TomlFileRateCache(
new FileRateCacheOptions { Provider = "RBA", CacheDirectory = "/var/cache/fx" }), options);
var ecb = new CachingRateProvider(ecbSource, new InMemoryRateCache("ECB"), options);
var aggregation = new RateAggregationOptions();
aggregation.Routes[new CurrencyPair(CurrencyCode.AUD, CurrencyCode.USD)] = new CurrencyPairRoute(new[] { "RBA", "ECB" });
aggregation.Routes[new CurrencyPair(CurrencyCode.USD, CurrencyCode.GBP)] = new CurrencyPairRoute(new[] { "ECB", "RBA" });
aggregation.Routes[new CurrencyPair(CurrencyCode.EUR, CurrencyCode.USD)] = new CurrencyPairRoute(new[] { "ECB", "RBA" }, new AverageStrategy());
IDatedRateProvider provider = new AggregatingRateProvider(
new[]
{
new NamedDatedRateProvider("RBA", rba),
new NamedDatedRateProvider("ECB", ecb),
},
aggregation);
// AUD/USD is routed RBA-then-ECB; EUR/USD is averaged across both.
RateLookupResult aud = provider.GetRate("AUD", "USD", new DateOnly(2024, 1, 3), RateLookupOptions.Exact);
// Reach a specific source directly when the routed result is not what you want.
if (((AggregatingRateProvider)provider).TryGetProvider("ECB", out IDatedRateProvider ecbOnly))
{
RateLookupResult ecbRate = ecbOnly.GetRate("AUD", "USD", new DateOnly(2024, 1, 3), RateLookupOptions.Exact);
}
Remarks
The aggregator is itself a provider on both the dated IDatedRateProvider and timeless IRateProvider surfaces, so it composes anywhere a provider is expected - including wrapping each child in its own CachingRateProvider so the grouping sits above the per-source cache. Same-currency identity is handled here before any strategy is consulted.
Aggregation combines distinct sources - children that differ in who published the rate - for resilience and coverage, and is orthogonal to the tiered read-through that a CachingRateProvider forms by stacking caches over a single source. The two nest: an aggregator child can itself be a stacked cache over a source. Reach for aggregation for fallback, an averaged rate, or per-pair routing across providers; reach for stacking to cut latency and survive restarts on one provider.
To target a specific source rather than the routed result, resolve it by name through TryGetProvider(string, out IDatedRateProvider) (or, under dependency injection, a keyed service); the lookup methods always apply the configured strategy and routing.
When RespectHistoryAvailability is enabled (the default), children that advertise their history depth through IHistoricalRateProvider and have declared they cannot serve any part of the requested date or window are dropped from the candidate set before the strategy runs, so a priority fallback does not waste a call on a source that cannot answer. A non-aware child is treated as unbounded and always kept, and the group's own HistoryAvailability composes the most generous declaration across the children.
Routing is frozen at construction: the per-pair routes and default order are resolved to their candidate sets once, after the constructor validates every referenced name. Mutating the supplied Routes or DefaultProviderOrder after construction has no effect on this instance; construct a new provider to change routing.
Constructors
AggregatingRateProvider(IEnumerable<NamedDatedRateProvider>, RateAggregationOptions?, TimeProvider?, ILogger?)
Initializes a new instance of the AggregatingRateProvider class.
public AggregatingRateProvider(IEnumerable<NamedDatedRateProvider> children, RateAggregationOptions? options = null, TimeProvider? timeProvider = null, ILogger? logger = null)
Parameters
childrenIEnumerable<NamedDatedRateProvider>The named children to group, in default priority order.
optionsRateAggregationOptionsThe aggregation options, or null for priority-fallback defaults.
timeProviderTimeProviderThe time source used by the timeless surface. null selects System .
loggerILoggerThe logger that records routing and aggregation outcomes. null selects Instance.
Exceptions
- ArgumentNullException
Thrown when
childrenis null, or whenoptionshas a null DefaultStrategy.- ArgumentException
Thrown when
childrenis empty, contains a blank name, a null provider, or a duplicate name, or whenoptionsreferences a child name that was not supplied.
Properties
HistoryAvailability
Gets the history depth this group advertises: the most generous availability across the grouped children, because a date any single child can serve is a date the group can serve.
public RateHistoryAvailability HistoryAvailability { get; }
Property Value
- RateHistoryAvailability
Unbounded when any child is Unbounded or does not implement IHistoricalRateProvider (a non-aware child declares no floor); otherwise the child availability whose earliest available date, evaluated against the current date, reaches furthest back.
ProviderNames
Gets the names of the grouped children.
public IReadOnlyCollection<string> ProviderNames { get; }
Property Value
- IReadOnlyCollection<string>
The child names, in no particular order.
Methods
GetRate(string, string, RateLookupOptions?)
Resolves the most recent available exchange rate from fromIsoCode to
toIsoCode under options, throwing if no rate is available.
public RateLookupResult GetRate(string fromIsoCode, string toIsoCode, RateLookupOptions? options = null)
Parameters
fromIsoCodestringThe source-currency ISO-style code.
toIsoCodestringThe destination-currency ISO-style code.
optionsRateLookupOptionsThe lookup rules to apply. null selects the implementation's default most-recent policy.
Returns
- RateLookupResult
The resolved RateLookupResult.
Exceptions
- ArgumentNullException
Thrown if
fromIsoCodeortoIsoCodeis null.- ArgumentException
Thrown if either ISO code is not a three-character uppercase ASCII code, or if
optionsis invalid.- KeyNotFoundException
Thrown if no rate is available for the request.
GetRate(string, string, DateOnly, RateLookupOptions?)
Resolves the exchange rate from fromIsoCode to toIsoCode on
date under options, throwing if no rate is available.
public RateLookupResult GetRate(string fromIsoCode, string toIsoCode, DateOnly date, RateLookupOptions? options = null)
Parameters
fromIsoCodestringThe source-currency ISO-style code.
toIsoCodestringThe destination-currency ISO-style code.
dateDateOnlyThe calendar date for which a rate is required.
optionsRateLookupOptionsThe lookup rules to apply, including date-resolution policy and tolerance. null is treated as Exact.
Returns
- RateLookupResult
The resolved RateLookupResult.
Exceptions
- ArgumentNullException
Thrown if
fromIsoCodeortoIsoCodeis null.- ArgumentException
Thrown if either ISO code is not a three-character uppercase ASCII code, or if
optionsis invalid (for example, Exact with non-zero tolerance).- ArgumentOutOfRangeException
Thrown if
optionscontains a negative tolerance or an undefined enum value.- KeyNotFoundException
Thrown if no rate is available for the request under the supplied options.
GetRateAsync(string, string, RateLookupOptions?, CancellationToken)
Asynchronously resolves the most recent available exchange rate from fromIsoCode to
toIsoCode under options, throwing if no rate is available.
public ValueTask<RateLookupResult> GetRateAsync(string fromIsoCode, string toIsoCode, RateLookupOptions? options = null, CancellationToken cancellationToken = default)
Parameters
fromIsoCodestringThe source-currency ISO-style code.
toIsoCodestringThe destination-currency ISO-style code.
optionsRateLookupOptionsThe lookup rules to apply. null selects the implementation's default most-recent policy.
cancellationTokenCancellationTokenA token to observe while awaiting the operation.
Returns
- ValueTask<RateLookupResult>
A task that yields the resolved RateLookupResult.
Exceptions
- ArgumentNullException
Thrown if
fromIsoCodeortoIsoCodeis null.- ArgumentException
Thrown if either ISO code is not a three-character uppercase ASCII code, or if
optionsis invalid.- KeyNotFoundException
Thrown if no rate is available for the request.
GetRateAsync(string, string, DateOnly, RateLookupOptions?, CancellationToken)
Asynchronously resolves the exchange rate from fromIsoCode to toIsoCode
on date under options, throwing if no rate is available.
public ValueTask<RateLookupResult> GetRateAsync(string fromIsoCode, string toIsoCode, DateOnly date, RateLookupOptions? options = null, CancellationToken cancellationToken = default)
Parameters
fromIsoCodestringThe source-currency ISO-style code.
toIsoCodestringThe destination-currency ISO-style code.
dateDateOnlyThe calendar date for which a rate is required.
optionsRateLookupOptionsThe lookup rules to apply, including date-resolution policy and tolerance. null is treated as Exact.
cancellationTokenCancellationTokenA token to observe while awaiting the operation.
Returns
- ValueTask<RateLookupResult>
A task that yields the resolved RateLookupResult.
Exceptions
- ArgumentNullException
Thrown if
fromIsoCodeortoIsoCodeis null.- ArgumentException
Thrown if either ISO code is not a three-character uppercase ASCII code, or if
optionsis invalid.- ArgumentOutOfRangeException
Thrown if
optionscontains a negative tolerance or an undefined enum value.- KeyNotFoundException
Thrown if no rate is available for the request under the supplied options.
GetRates(string, string, DateOnly, DateOnly)
Returns every available rate from fromIsoCode to toIsoCode whose
observation date falls within the inclusive range startDate to endDate.
public RateRangeResult GetRates(string fromIsoCode, string toIsoCode, DateOnly startDate, DateOnly endDate)
Parameters
fromIsoCodestringThe source-currency ISO-style code.
toIsoCodestringThe destination-currency ISO-style code.
startDateDateOnlyThe inclusive start of the range.
endDateDateOnlyThe inclusive end of the range.
Returns
- RateRangeResult
An RateRangeResult carrying the rates in the range ordered by date, the requested window, and the observed span; the result is empty when no rates are available.
Remarks
The lookup is range-based and does not apply a date-resolution policy: it returns the observations that exist within the window rather than resolving a single date. An implementation backed by a remote feed may block to fetch on demand, or serve only already-loaded data; use GetRatesAsync(string, string, DateOnly, DateOnly, CancellationToken) to fetch without blocking.
Exceptions
- ArgumentNullException
Thrown if
fromIsoCodeortoIsoCodeis null.- ArgumentException
Thrown if either ISO code is not a three-character uppercase ASCII code, or if
endDateprecedesstartDate.
GetRatesAsync(string, string, DateOnly, DateOnly, CancellationToken)
Asynchronously returns every available rate from fromIsoCode to
toIsoCode whose observation date falls within the inclusive range
startDate to endDate.
public ValueTask<RateRangeResult> GetRatesAsync(string fromIsoCode, string toIsoCode, DateOnly startDate, DateOnly endDate, CancellationToken cancellationToken = default)
Parameters
fromIsoCodestringThe source-currency ISO-style code.
toIsoCodestringThe destination-currency ISO-style code.
startDateDateOnlyThe inclusive start of the range.
endDateDateOnlyThe inclusive end of the range.
cancellationTokenCancellationTokenA token to observe while awaiting the operation.
Returns
- ValueTask<RateRangeResult>
A task that yields an RateRangeResult carrying the rates in the range ordered by date, the requested window, and the observed span; the result is empty when no rates are available.
Remarks
The lookup is range-based and does not apply a date-resolution policy: it returns the observations that exist within the window rather than resolving a single date. Implementations backed by a remote feed may fetch on demand, which is why the method is asynchronous.
Exceptions
- ArgumentNullException
Thrown if
fromIsoCodeortoIsoCodeis null.- ArgumentException
Thrown if either ISO code is not a three-character uppercase ASCII code, or if
endDateprecedesstartDate.
TryGetProvider(string, out IDatedRateProvider)
Attempts to resolve a grouped child by name, for callers that need a specific source rather than the routed result.
public bool TryGetProvider(string name, out IDatedRateProvider provider)
Parameters
namestringThe child name.
providerIDatedRateProviderWhen this method returns true, the matching child provider.
Returns
Exceptions
- ArgumentNullException
Thrown when
nameis null.
TryGetRate(string, string, DateOnly, RateLookupOptions?, out RateLookupResult)
Attempts to resolve the exchange rate from fromIsoCode to toIsoCode on
date under options, returning a flag indicating whether a rate was
found.
public bool TryGetRate(string fromIsoCode, string toIsoCode, DateOnly date, RateLookupOptions? options, out RateLookupResult result)
Parameters
fromIsoCodestringThe source-currency ISO-style code.
toIsoCodestringThe destination-currency ISO-style code.
dateDateOnlyThe calendar date for which a rate is required.
optionsRateLookupOptionsThe lookup rules to apply, including date-resolution policy and tolerance. null is treated as Exact.
resultRateLookupResultWhen this method returns true, contains the resolved RateLookupResult; otherwise, contains default.
Returns
Exceptions
- ArgumentNullException
Thrown if
fromIsoCodeortoIsoCodeis null.- ArgumentException
Thrown if either ISO code is not a three-character uppercase ASCII code, or if
optionsis invalid.- ArgumentOutOfRangeException
Thrown if
optionscontains a negative tolerance or an undefined enum value.
Explicit Interface Implementations
IRateProvider.GetRate(string, string)
Returns the exchange rate that converts one unit of fromIsoCode to units of
toIsoCode.
decimal IRateProvider.GetRate(string fromIsoCode, string toIsoCode)
Parameters
fromIsoCodestringThe source currency's ISO 4217 code.
toIsoCodestringThe destination currency's ISO 4217 code.
Returns
- decimal
The rate.
Exceptions
- KeyNotFoundException
No rate is available for the requested pair.
Applies to
| Product | Versions |
|---|---|
| .NET | 8, 10 |