Table of Contents

PairWebRateProvider<TSeries> Class

Definition

Namespace
Bodu.Financial.ExchangeRates
Assembly
Bodu.Financial.ExchangeRates.dll
Package
Bodu.Financial.ExchangeRates 1.0.0
Source
PairWebRateProvider{T}.cs

Provides the shared machinery for a WebRateProvider that fetches one currency pair per request from a remote feed - per-pair coverage tracking, single-flight request coalescing, the fetch-and-accumulate orchestration, and the diagnostic logging - leaving a derived type to supply only the feed identity and the feed-specific exception text. The actual fetch and parse are delegated to an IPairRateSource<TSeries>.

public abstract class PairWebRateProvider<TSeries> : WebRateProvider, IDatedRateProvider, IRateProvider, IPairRateLoader, IHistoricalRateProvider, IDisposable

Type Parameters

TSeries

The source-specific series-metadata type surfaced through GetAvailablePairs().

Inheritance
PairWebRateProvider<TSeries>
Implements
Derived
Inherited Members
Extension Methods

Remarks

This base sits between WebRateProvider (which owns the in-memory accumulator, the immutable snapshot, and the full lookup matrix) and a concrete pair-based source such as Yahoo Finance or OFX. It implements EnsureLoadedAsync(CurrencyPair, DateOnly, DateOnly, CancellationToken) and IsLoaded(CurrencyPair, DateOnly, DateOnly) with a gap-respecting per-pair DateRangeCoverage set so a request that straddles an unfetched interior gap is correctly treated as uncovered and re-fetched, and coalesces concurrent fetches of the same pair-and-window so only one request is in flight.

A derived type supplies ProviderId and may override CreateRangeInvertedException(DateOnly, DateOnly), FormatRateNotFound(string, string, DateOnly), and FormatPairForLog(CurrencyPair) to present feed-specific exception types, messages, and log labels.

using Bodu.Financial.ExchangeRates;

// A concrete pair-based source: the fetch/parse lives in an IPairRateSource<TSeries>;
// this type contributes only the feed identity. Coverage tracking, single-flight
// coalescing, and the full lookup surface come from the base classes.
public sealed class MyFeedRateProvider : PairWebRateProvider<MyFeedSeriesInfo>
{
    public MyFeedRateProvider(MyFeedRateProviderOptions options, HttpClient httpClient)
        : base(new MyFeedSource(httpClient, options), options, logger: null, ownedHttpClient: null, timeProvider: null)
    {
    }

    protected override string ProviderId => "MyFeed";
}

Constructors

PairWebRateProvider(IPairRateSource<TSeries>, WebRateProviderOptions, ILogger?, HttpClient?, TimeProvider?)

Initializes a new instance of the PairWebRateProvider<TSeries> class.

protected PairWebRateProvider(IPairRateSource<TSeries> source, WebRateProviderOptions options, ILogger? logger, HttpClient? ownedHttpClient, TimeProvider? timeProvider)

Parameters

source IPairRateSource<TSeries>

The source that fetches and parses a pair's observations.

options WebRateProviderOptions

The provider options.

logger ILogger

The logger that records pair downloads and on-demand network fetches. null selects Instance.

ownedHttpClient HttpClient

The HTTP client this provider should own and dispose, or null when the client is caller-supplied.

timeProvider TimeProvider

The time source used to resolve the current instant for the undated surfaces. null selects System.

Exceptions

ArgumentNullException

Thrown when source or options is null.

ArgumentException

Thrown when options fails validation.

Properties

AllowSynchronousNetworkAccess

Gets a value indicating whether a synchronous lookup may block to fetch a missing window on demand.

protected override sealed bool AllowSynchronousNetworkAccess { get; }

Property Value

bool

true when synchronous getters may block on the network; otherwise false.

Remarks

When enabled, the synchronous getters block on the async fetch, which can deadlock if invoked on a thread carrying a captured SynchronizationContext (classic ASP.NET, a WPF/WinForms UI thread). The synchronous path guards against this by throwing InvalidOperationException when Current is non-null; enable this only for code that calls the getters from a thread-pool thread (or use the asynchronous API).

DefaultLookback

Gets the look-back window used when a single-rate lookup must fetch on demand; the provider fetches the window ending on the requested date and spanning this duration.

protected override sealed TimeSpan DefaultLookback { get; }

Property Value

TimeSpan

The look-back window.

HistoryAvailability

Gets the history depth this provider advertises: how far back it can serve rates.

public override RateHistoryAvailability HistoryAvailability { get; }

Property Value

RateHistoryAvailability

The advertised availability; the base reports Unbounded. A derived type whose feed publishes only a bounded window overrides this to declare it.

Methods

EnsureLoadedAsync(CurrencyPair, DateOnly, DateOnly, CancellationToken)

Ensures the inclusive window for a pair has been fetched and accumulated, idempotently. Implementations perform their own coverage check, request coalescing, fetch, and accumulation (via AddObservations(IEnumerable<ExchangeRate>, DateTimeOffset?) and RebuildSnapshot() under SyncRoot).

protected override sealed ValueTask EnsureLoadedAsync(CurrencyPair pair, DateOnly startDate, DateOnly endDate, CancellationToken cancellationToken)

Parameters

pair CurrencyPair

The currency pair to ensure data for. Feeds that fetch by range, feed, or file may ignore it.

startDate DateOnly

The inclusive start of the window.

endDate DateOnly

The inclusive end of the window.

cancellationToken CancellationToken

A token to observe while awaiting the fetch.

Returns

ValueTask

A task that completes when the window has been loaded.

FormatPairForLog(CurrencyPair)

Formats the label used for a pair in the download log messages. The default returns the FROM/TO ISO-code pair; a derived type may override it to log a feed-specific identifier such as a ticker.

protected virtual string FormatPairForLog(CurrencyPair pair)

Parameters

pair CurrencyPair

The pair being logged.

Returns

string

The label to log.

GetAvailablePairs()

Gets the currency pairs fetched so far.

public IReadOnlyCollection<TSeries> GetAvailablePairs()

Returns

IReadOnlyCollection<TSeries>

A snapshot of the discovered series, one per currency pair.

IsLoaded(CurrencyPair, DateOnly, DateOnly)

Reports whether the inclusive window for a pair has already been fetched, so the synchronous lookup path can skip a redundant blocking fetch.

protected override sealed bool IsLoaded(CurrencyPair pair, DateOnly startDate, DateOnly endDate)

Parameters

pair CurrencyPair

The currency pair to test.

startDate DateOnly

The inclusive start of the window.

endDate DateOnly

The inclusive end of the window.

Returns

bool

true when the window is already covered; otherwise false.

OnObservationIngested(ExchangeRate)

Called once per observation as it is ingested, for derived-type diagnostics. The default does nothing.

protected override sealed void OnObservationIngested(ExchangeRate rate)

Parameters

rate ExchangeRate

The observation being ingested.

OnSynchronousNetworkFetch(DateOnly)

Called after a synchronous lookup blocks to fetch on demand, for derived-type diagnostics. The default does nothing.

protected override sealed void OnSynchronousNetworkFetch(DateOnly date)

Parameters

date DateOnly

The date around which the fetch was performed.

Applies to

ProductVersions
.NET8, 10