SoftCurrency 1.0.0

dotnet add package SoftCurrency --version 1.0.0
                    
NuGet\Install-Package SoftCurrency -Version 1.0.0
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="SoftCurrency" Version="1.0.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="SoftCurrency" Version="1.0.0" />
                    
Directory.Packages.props
<PackageReference Include="SoftCurrency" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add SoftCurrency --version 1.0.0
                    
#r "nuget: SoftCurrency, 1.0.0"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package SoftCurrency@1.0.0
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=SoftCurrency&version=1.0.0
                    
Install as a Cake Addin
#tool nuget:?package=SoftCurrency&version=1.0.0
                    
Install as a Cake Tool

SoftCurrency

A lightweight .NET 9 library for currency conversion backed by ExchangeRate-API. Supports single conversions, batch conversions, and rate lookups — with built-in in-memory caching to minimise API calls.

Installation

dotnet add package SoftCurrency

Requirements

  • .NET 9.0 or later
  • A free or paid API key from exchangerate-api.com (free tier: 1,500 requests/month)

Quick Start

using SoftCurrency;

var fx = new SoftCurrency("YOUR_API_KEY");

// Convert 100 USD to EUR
double euros = await fx.ConvertAsync(100, "USD", "EUR");
Console.WriteLine($"100 USD = {euros:F2} EUR");

API Reference

Constructor

var fx = new SoftCurrency(string apiKey, SoftCurrencyOptions? options = null);
Parameter Type Description
apiKey string Your ExchangeRate-API key.
options SoftCurrencyOptions? Optional. Cache TTL and/or a custom HttpClient.

Throws SoftCurrencyException (code: "invalid-argument") if the key is null or empty.


GetRatesAsync

Fetches all conversion rates for a base currency. Results are cached in memory for the duration of CacheTtl (default 1 hour).

Task<IReadOnlyDictionary<string, double>> GetRatesAsync(
    string baseCurrency,
    CancellationToken cancellationToken = default)
IReadOnlyDictionary<string, double> rates = await fx.GetRatesAsync("USD");
Console.WriteLine(rates["EUR"]);  // e.g. 0.92
Console.WriteLine(rates["JPY"]);  // e.g. 149.50

GetRateAsync

Returns the exchange rate between two specific currencies.

Task<double> GetRateAsync(
    string baseCurrency,
    string targetCurrency,
    CancellationToken cancellationToken = default)
double rate = await fx.GetRateAsync("USD", "GBP");
Console.WriteLine($"1 USD = {rate} GBP");

ConvertAsync

Converts an amount from one currency to another.

Task<double> ConvertAsync(
    double amount,
    string baseCurrency,
    string targetCurrency,
    CancellationToken cancellationToken = default)
double result = await fx.ConvertAsync(250.00, "GBP", "JPY");
Console.WriteLine($"250 GBP = {result:F2} JPY");

ConvertManyAsync

Converts an amount into multiple target currencies with a single API request.

Task<IReadOnlyDictionary<string, double>> ConvertManyAsync(
    double amount,
    string baseCurrency,
    IEnumerable<string> targetCurrencies,
    CancellationToken cancellationToken = default)
var results = await fx.ConvertManyAsync(1000, "USD", ["EUR", "GBP", "JPY", "CAD"]);

foreach (var (currency, amount) in results)
    Console.WriteLine($"1000 USD = {amount:F2} {currency}");

SupportedCurrenciesAsync

Returns all currency codes available for a given base currency.

Task<IReadOnlyList<string>> SupportedCurrenciesAsync(
    string baseCurrency = "USD",
    CancellationToken cancellationToken = default)
IReadOnlyList<string> codes = await fx.SupportedCurrenciesAsync();
Console.WriteLine($"{codes.Count} currencies supported");
// e.g. USD, EUR, GBP, JPY, AUD, CAD, CHF, CNY, ...

ClearCache

Drops all cached rates. The next call to any method will fetch fresh data from the API.

void ClearCache()
fx.ClearCache();
var freshRates = await fx.GetRatesAsync("USD"); // always hits the API

Configuration

Pass a SoftCurrencyOptions object to the constructor to customise behaviour.

Cache TTL

By default, fetched rates are cached for 1 hour. Adjust with CacheTtl:

// Cache for 15 minutes
var fx = new SoftCurrency("YOUR_API_KEY", new SoftCurrencyOptions
{
    CacheTtl = TimeSpan.FromMinutes(15),
});

// Always fetch fresh rates (no caching)
var fx = new SoftCurrency("YOUR_API_KEY", new SoftCurrencyOptions
{
    CacheTtl = TimeSpan.Zero,
});

Custom HttpClient

Provide your own HttpClient — useful for setting timeouts, base headers, or plugging into your application's existing IHttpClientFactory:

var httpClient = new HttpClient
{
    Timeout = TimeSpan.FromSeconds(10),
};

var fx = new SoftCurrency("YOUR_API_KEY", new SoftCurrencyOptions
{
    HttpClient = httpClient,
});

When you supply your own HttpClient, you are responsible for its lifetime. When the library creates one internally it is disposed automatically when SoftCurrency is disposed.


Dependency Injection

SoftCurrency implements ISoftCurrency, making it straightforward to register and mock in DI-based applications.

Registration

// Program.cs
builder.Services.AddSingleton<ISoftCurrency>(_ =>
    new SoftCurrency("YOUR_API_KEY", new SoftCurrencyOptions
    {
        CacheTtl = TimeSpan.FromMinutes(30),
    }));

Usage in a service

public class PricingService(ISoftCurrency fx)
{
    public async Task<decimal> GetPriceInEurAsync(decimal usdPrice)
    {
        double rate = await fx.GetRateAsync("USD", "EUR");
        return usdPrice * (decimal)rate;
    }
}

Mocking in tests

Because your code depends on ISoftCurrency, you can substitute any mock:

// Using NSubstitute
var fx = Substitute.For<ISoftCurrency>();
fx.GetRateAsync("USD", "EUR").Returns(0.92);

// Using Moq
var fx = new Mock<ISoftCurrency>();
fx.Setup(x => x.GetRateAsync("USD", "EUR", default)).ReturnsAsync(0.92);

Error Handling

All failures throw SoftCurrencyException, which carries a machine-readable Code property alongside the human-readable Message.

try
{
    double rate = await fx.GetRateAsync("USD", "EUR");
}
catch (SoftCurrencyException ex)
{
    Console.WriteLine($"[{ex.Code}] {ex.Message}");
}
Code Cause
invalid-argument Bad currency code (not 3 letters), non-finite amount, or empty API key.
network-error HTTP request could not be sent (no internet, DNS failure, timeout, etc.).
invalid-key The API key is not recognised by ExchangeRate-API.
inactive-account The API account email address has not been confirmed.
quota-reached The monthly request quota has been exhausted.
unsupported-code The target currency code is not in the returned rate set.
malformed-request The request URL was malformed (should not occur in normal use).
http-{status} An unexpected HTTP status code was returned (e.g. http-500).

Disposal

SoftCurrency implements IDisposable. When you let the library manage the HttpClient internally, dispose the instance when you are done:

await using var fx = new SoftCurrency("YOUR_API_KEY");
double rate = await fx.GetRateAsync("USD", "EUR");
// fx is disposed here — internal HttpClient is released

When using DI with a singleton lifetime, the DI container handles disposal on application shutdown.


License

MIT © Sachindu Kavishka

Product Compatible and additional computed target framework versions.
.NET net9.0 is compatible.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 was computed.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.
  • net9.0

    • No dependencies.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
1.0.0 1,198 6/16/2026