DEV Community

Cover image for ISO 4217 Currency Reference for .NET — Strongly Typed and Production-Ready
Nickolay Selyutin
Nickolay Selyutin

Posted on • Originally published at Medium

ISO 4217 Currency Reference for .NET — Strongly Typed and Production-Ready

Working with currencies in .NET often looks simple — until it becomes a mess. String-based codes, inconsistent casing, withdrawn currencies, special units, and edge cases that silently break your logic. If you’ve ever dealt with payments, rates, accounting, or financial integrations, you’ve likely seen horrors like:

if (currencyCode == "usd" || currencyCode == "Usd" || currencyCode == "USD")
{
    // ...
}
Enter fullscreen mode Exit fullscreen mode

or the "improved" version:

if (string.Equals(currencyCode, "usd", StringComparison.OrdinalIgnoreCase))
{
    // ...
}
Enter fullscreen mode Exit fullscreen mode

or even worse:

if (currency == "XXX") { /* ??? */ }
if (currency == "BYR") { /* replaced by BYN */ }
// ...
Enter fullscreen mode Exit fullscreen mode

All of this happens because currencies are treated as plain strings.
But ISO 4217 is a standard. We should be able to consume it in a strongly typed way.
I explored existing solutions… but most were:

  • too heavy,
  • too dynamic,
  • not strongly typed,
  • outdated,
  • not auto-updated with ISO data. So I asked myself:

What if ISO currency types could be generated at compile time with a Source Generator?

That idea became:

HawkN.Currency.Reference.Iso4217

🔗 NuGet: https://www.nuget.org/packages/HawkN.Currency.Reference.Iso4217
📦 GitHub: https://github.com/HawkN113/Currency.Reference.Iso4217

A lightweight, zero-dependency, source-generated, production-ready ISO 4217 reference library for .NET.

🚀 Features

✔ Strongly typed enum: CurrencyCode (No more "USD" strings. Pure compile-time safety)
✔ Historical & withdrawn currencies included
EUR replacements, old European national currencies, BYR → BYN, and more.
✔ Full ISO 4217 data embedded
Original + friendly names + replacements + special units.
✔ Query builder for filtering
Get exactly the currencies you need.
✔ Fast, static, zero-allocation lookups
Everything is generated at compile time.
✔ No dependencies
Just install & use.
✔ CI-driven updates
GitHub Actions for:

  • auto-publishing,
  • formatting,
  • tests,
  • security validation.

📦 Installation

CLI:

dotnet add package HawkN.Currency.Reference.Iso4217 --version 8.0.1
Enter fullscreen mode Exit fullscreen mode

NuGet Package Manager:

Install-Package HawkN.Currency.Reference.Iso4217 -Version 8.0.1
Enter fullscreen mode Exit fullscreen mode

🧩 Getting Started

Register:

services.AddCurrencyService();
Enter fullscreen mode Exit fullscreen mode

Example in a console app:

using var host = Host.CreateDefaultBuilder(args)
    .ConfigureServices(services =>
    {
        services.AddCurrencyService();
    })
    .Build();
Enter fullscreen mode Exit fullscreen mode

Resolve:

var currencyService = provider.GetRequiredService<ICurrencyService>();
Enter fullscreen mode Exit fullscreen mode

Inject (Minimal API):

app.MapGet("/currencies", ([FromServices] ICurrencyService svc) => svc...);
Enter fullscreen mode Exit fullscreen mode

🔍 Usage Examples

Query currencies

var currencies = currencyService.Query()
    .Includes
        .Type(CurrencyType.Fiat)
        .Type(CurrencyType.SpecialUnit)
        .Type(CurrencyType.SpecialReserve)
        .Type(CurrencyType.PreciousMetal)
    .Build();
Enter fullscreen mode Exit fullscreen mode

Currency Types:

  • Fiat
    Standard government-issued currencies.
    Examples: USD, EUR, JPY

  • SpecialUnit
    Non-sovereign institutional units.
    Examples: SDR, IMF units, etc.

  • SpecialReserve
    Reserve assets used by central banks.

  • PreciousMetal
    Value pegged to metals.
    Examples: XAU, XAG, XPT, XPD

If you only need fiat:

var fiat = currencyService.Query()
    .Includes.Type(CurrencyType.Fiat)
    .Build();
Enter fullscreen mode Exit fullscreen mode

Excluding currencies

var filtered = currencyService.Query()
    .Includes.Type(CurrencyType.Fiat)
    .Without(w => w.Codes(nameof(CurrencyCode.EUR), nameof(CurrencyCode.USD)))
    .Build();
Enter fullscreen mode Exit fullscreen mode

Advanced search

var selected = currencyService.Query()
    .Includes.Type(CurrencyType.Fiat)
    .Where(x => x.Code is "EUR" or "USD")
    .Build();
Enter fullscreen mode Exit fullscreen mode

Validation

var ok = currencyService.TryValidate("AFN", out var result);
Enter fullscreen mode Exit fullscreen mode

or:

var ok = currencyService.TryValidate(CurrencyCode.AFN, out var result);
Enter fullscreen mode Exit fullscreen mode

Lookup

By string:

var afn = currencyService.Get("AFN");
Enter fullscreen mode Exit fullscreen mode

By enum:

var afn = currencyService.Get(CurrencyCode.AFN);
Enter fullscreen mode Exit fullscreen mode

Historical currencies

var historical = currencyService.GetAllHistorical();
foreach (var c in historical)
{
    Console.WriteLine($"{c.Code} - {c.Name} (Withdrawn: {c.WithdrawnOn})");
}
Enter fullscreen mode Exit fullscreen mode

🌟 Why This Library?

Use HawkN.Currency.Reference.Iso4217 if you want:

  • compile-time safety instead of EUR strings
  • ISO-compliant data without manual maintenance
  • extremely fast lookups
  • great developer experience (IntelliSense everything)
  • AOT-ready, reflection-free library
  • static, deterministic data
  • automatic updates via CI workflows

🙌 Final Thoughts

This project started as a small experiment — "Can I generate all ISO 4217 currencies with a Source Generator?"
Then it became a clean, fast, production-ready solution that removes all currency-related pain from .NET apps.
If you deal with payments, rates, financial systems, or even basic validation — this package will save you time and bugs.
🔗 GitHub: https://github.com/HawkN113/Currency.Reference.Iso4217
🔗 NuGet: https://www.nuget.org/packages/HawkN.Currency.Reference.Iso4217

Happy coding!

Top comments (0)