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

Published: (December 12, 2025 at 05:41 AM EST)
2 min read
Source: Dev.to

Source: Dev.to

Overview

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 can silently break your logic. Common pitfalls include:

if (currencyCode == "usd" || currencyCode == "Usd" || currencyCode == "USD")
{
    // ...
}

or the “improved” version:

if (string.Equals(currencyCode, "usd", StringComparison.OrdinalIgnoreCase))
{
    // ...
}

and even worse:

if (currency == "XXX") { /* ??? */ }
if (currency == "BYR") { /* replaced by BYN */ }

All of this happens because currencies are treated as plain strings. ISO 4217 is a standard, so we should be able to consume it in a strongly‑typed way.

The Idea

Generate ISO currency types at compile time with a Source Generator. The result is the HawkN.Currency.Reference.Iso4217 library.

  • NuGet:
  • GitHub:

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

Installation

CLI

dotnet add package HawkN.Currency.Reference.Iso4217 --version 8.0.1

Package Manager

Install-Package HawkN.Currency.Reference.Iso4217 -Version 8.0.1

Registration

services.AddCurrencyService();

Basic Usage

Console Application

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

var currencyService = host.Services.GetRequiredService<ICurrencyService>();

Minimal API Injection

app.MapGet("/currencies", ([FromServices] ICurrencyService svc) => svc.Query().Build());

Querying Currencies

Include Specific Types

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

Currency Types

  • Fiat – e.g., USD, EUR, JPY
  • SpecialUnit – e.g., SDR, IMF units
  • SpecialReserve
  • PreciousMetal – e.g., XAU, XAG, XPT, XPD

Filter Only Fiat Currencies

var fiat = currencyService.Query()
    .Includes.Type(CurrencyType.Fiat)
    .Build();

Exclude Specific Codes

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

Conditional Selection

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

Validation

var ok = currencyService.TryValidate("AFN", out var result);

Or using the strongly‑typed enum:

var ok = currencyService.TryValidate(CurrencyCode.AFN, out var result);

Retrieval

By String

var afn = currencyService.Get("AFN");

By Enum

var afn = currencyService.Get(CurrencyCode.AFN);

Historical Currencies

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

Benefits

  • Compile‑time safety instead of raw string literals.
  • ISO‑compliant data without manual maintenance.
  • Extremely fast lookups.
  • Great developer experience (IntelliSense everywhere).
  • AOT‑ready and reflection‑free.
  • Static, deterministic data.
  • Automatic updates via CI workflows.

Project Background

This project started as a small experiment: “Can I generate all ISO 4217 currencies with a Source Generator?”

  • GitHub:
  • NuGet:

Happy coding!

Back to Blog

Related posts

Read more »

Domina el uso de paquetes NuGet en .NET

¿Qué es realmente NuGet? Imagina que NuGet es el Amazon o Mercado Libre de .NET. Tú no fabricas cada tornillo de tu mueble; los pides a la tienda. - El Package...