PolishIdentifiers 2.0.0

dotnet add package PolishIdentifiers --version 2.0.0
                    
NuGet\Install-Package PolishIdentifiers -Version 2.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="PolishIdentifiers" Version="2.0.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="PolishIdentifiers" Version="2.0.0" />
                    
Directory.Packages.props
<PackageReference Include="PolishIdentifiers" />
                    
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 PolishIdentifiers --version 2.0.0
                    
#r "nuget: PolishIdentifiers, 2.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 PolishIdentifiers@2.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=PolishIdentifiers&version=2.0.0
                    
Install as a Cake Addin
#tool nuget:?package=PolishIdentifiers&version=2.0.0
                    
Install as a Cake Tool

PolishIdentifiers

NuGet CI License: MIT Targets: netstandard2.0 · net10.0

PolishIdentifiers is a .NET library that exposes PESEL, NIP, and REGON as strong identifier types (Pesel, Nip, Regon) instead of raw strings plus includes their strong validation.

These identifiers are implemented as tightly constrained readonly struct value types, with one unified Parse / TryParse / Validate API shape across the implemented surface, TypeConverter support, DataAnnotations attributes for request validation, generators for valid and intentionally invalid test values, broad unit-test coverage, and ReadOnlySpan<char>-based parsing and validation for low-allocation paths.

In practice, that gives you one package for parsing, validation, formatting, generation, ASP.NET Core MVC and Minimal API parameter binding, and request-model validation while keeping strong identifier types throughout domain code.

Scope

This library covers strongly typed Polish formal identifiers — identity, registration, and business numbers used in Polish administrative and commercial contexts.

Currently implemented: Pesel, Nip, Regon.

Framework support

Targets netstandard2.0 and net10.0.

The net10.0 build adds IParsable<T>, ISpanParsable<T>, and DateOnly-based PESEL members. All targets include TryParse(string?, IFormatProvider?, out T), which enables ASP.NET Core Minimal API route and query parameter binding without any additional configuration. See Framework support for all target-specific differences.

Supported identifiers

Type Identifier Annotation Accepted formats Docs
Pesel PESEL [ValidPesel] 44051401458 PESEL
Nip NIP [ValidNip] 1234563218, 123-456-32-18, PL1234563218, PL 1234563218, PL 123-456-32-18 NIP
Regon REGON [ValidRegon] 123456785, 12345678512347 REGON

Parse, TryParse, Validate

Method Use when
TryParse You want a strong type and a non-throwing failure path; use the out TError? error overload to also receive the first structured validation error on failure
Parse Invalid input is exceptional and should throw an identifier-specific validation exception
Validate You only need a pass-or-fail result with the first structured validation error and do not need the typed identifier instance

Generators

<table> <thead> <tr> <th>Type</th> <th>Kind</th> <th>Outputs</th> <th>Docs</th> </tr> </thead> <tbody> <tr> <td rowspan="2"><code>PeselGenerator</code></td> <td>Valid</td> <td>PESEL with random or specified birth date and gender</td> <td rowspan="2"><a href="./docs/pesel-generator.md">PESEL generator</a></td> </tr> <tr> <td>Invalid</td> <td>invalid characters, wrong checksum, wrong date, wrong length</td> </tr> <tr> <td rowspan="2"><code>NipGenerator</code></td> <td>Valid</td> <td>canonical valid NIP</td> <td rowspan="2"><a href="./docs/nip-generator.md">NIP generator</a></td> </tr> <tr> <td>Invalid</td> <td>invalid characters, wrong checksum, wrong length, unrecognized format</td> </tr> <tr> <td rowspan="2"><code>RegonGenerator</code></td> <td>Valid</td> <td>REGON-9 and REGON-14</td> <td rowspan="2"><a href="./docs/regon-generator.md">REGON generator</a></td> </tr> <tr> <td>Invalid</td> <td>invalid characters, wrong checksum for REGON-9, wrong checksum for REGON-14, wrong length</td> </tr> </tbody> </table>

TypeConverters

Each identifier type registers a TypeConverter; ASP.NET Core MVC and Minimal APIs support binding through different mechanisms.

Scenario netstandard2.0 net10.0 Uses TypeConverter?
MVC route/query/form binding Supported Supported Yes
Minimal API binding Supported Supported No

Minimal API binding uses public static TryParse(string?, IFormatProvider?, out T) rather than TypeConverter.

Examples

Parse

using PolishIdentifiers;

var nip = Nip.Parse("1234563218");

Console.WriteLine(nip);                              // 1234563218
Console.WriteLine(nip.ToString(NipFormat.VatEu));   // PL1234563218

TryParse

using PolishIdentifiers;

if (!Pesel.TryParse("44051401458", out var pesel, out var error))
{
    Console.WriteLine($"Rejected: {error}"); // e.g. InvalidChecksum
    return;
}

Console.WriteLine(pesel.BirthDate.ToString("yyyy-MM-dd")); // 1944-05-14
Console.WriteLine(pesel.Gender);                           // Male
using PolishIdentifiers;

// Other accepted NIP inputs: "1234563218", "123-456-32-18", "PL1234563218", "PL 1234563218"
if (!Nip.TryParse("PL 123-456-32-18", out var nip, out var error))
{
    Console.WriteLine($"Rejected: {error}");
    return;
}

Console.WriteLine(nip);                                   // 1234563218
Console.WriteLine(nip.ToString(NipFormat.DigitsOnly));    // 1234563218
Console.WriteLine(nip.ToString(NipFormat.Hyphenated));    // 123-456-32-18
Console.WriteLine(nip.ToString(NipFormat.VatEu));         // PL1234563218
using PolishIdentifiers;

if (!Regon.TryParse("12345678512347", out var regon, out var error))
{
    Console.WriteLine($"Rejected: {error}");
    return;
}

Console.WriteLine(regon.Kind);       // Regon14
Console.WriteLine(regon.BaseRegon9); // 123456785

Validate

using PolishIdentifiers;

var result = Nip.Validate("123-456-32-18");

Console.WriteLine(result.IsValid); // True

var bad = Pesel.Validate("44051401459");

Console.WriteLine(bad.IsValid); // False
Console.WriteLine(bad.Error);   // InvalidChecksum

DataAnnotations attributes

using System.ComponentModel.DataAnnotations;
using PolishIdentifiers;

public sealed class InvoiceRequest
{
    [ValidNip]
    public string SellerNip { get; init; } = string.Empty;

    [ValidPesel]
    public string? BuyerPesel { get; init; }

    [ValidRegon]
    public string? SellerRegon { get; init; }
}

Generators

using PolishIdentifiers;

// Valid values for seeding test data
var pesel = PeselGenerator.Generate(Gender.Female, new DateTime(1990, 6, 15));
var nip   = NipGenerator.Generate();
var regon = RegonGenerator.Generate(RegonKind.Regon14);

Console.WriteLine(pesel); // e.g. 90061512345
Console.WriteLine(nip);   // e.g. 5261040828
Console.WriteLine(regon); // e.g. 12345678512347

// Intentionally invalid strings for negative test cases
string badPesel = PeselGenerator.Invalid.WrongChecksum();
string badNip   = NipGenerator.Invalid.WrongChecksum();
string badRegon = RegonGenerator.Invalid.WrongChecksumRegon9();

MVC / Controllers

using Microsoft.AspNetCore.Mvc;
using PolishIdentifiers;

var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllers();

var app = builder.Build();

app.MapControllers();
app.MapGet("/companies/{regon}", (Regon regon) => Results.Ok(regon));

app.Run();

[ApiController]
[Route("api/identifiers")]
public sealed class IdentifiersController : ControllerBase
{
    [HttpGet("nips/{nip}")]
    public IActionResult GetNip(Nip nip) => Ok(nip);

    [HttpGet("persons")]
    public IActionResult Find([FromQuery] Pesel pesel) => Ok(pesel);
}

For route, query-string, and form binding, the types bind from a single string via TypeConverter / TryParse. For JSON request bodies, add JSON converters in your application.

Product Compatible and additional computed target framework versions.
.NET net5.0 was computed.  net5.0-windows was computed.  net6.0 was computed.  net6.0-android was computed.  net6.0-ios was computed.  net6.0-maccatalyst was computed.  net6.0-macos was computed.  net6.0-tvos was computed.  net6.0-windows was computed.  net7.0 was computed.  net7.0-android was computed.  net7.0-ios was computed.  net7.0-maccatalyst was computed.  net7.0-macos was computed.  net7.0-tvos was computed.  net7.0-windows was computed.  net8.0 was computed.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed.  net9.0 was computed.  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 is compatible.  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. 
.NET Core netcoreapp2.0 was computed.  netcoreapp2.1 was computed.  netcoreapp2.2 was computed.  netcoreapp3.0 was computed.  netcoreapp3.1 was computed. 
.NET Standard netstandard2.0 is compatible.  netstandard2.1 was computed. 
.NET Framework net461 was computed.  net462 was computed.  net463 was computed.  net47 was computed.  net471 was computed.  net472 was computed.  net48 was computed.  net481 was computed. 
MonoAndroid monoandroid was computed. 
MonoMac monomac was computed. 
MonoTouch monotouch was computed. 
Tizen tizen40 was computed.  tizen60 was computed. 
Xamarin.iOS xamarinios was computed. 
Xamarin.Mac xamarinmac was computed. 
Xamarin.TVOS xamarintvos was computed. 
Xamarin.WatchOS xamarinwatchos was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

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
2.0.0 0 4/7/2026
1.0.0 82 3/22/2026
0.2.0 92 3/11/2026
0.1.1 83 3/8/2026
0.1.0 90 3/6/2026

v2.0.0 contains two breaking changes: Nip.IssuingTaxOfficePrefix now returns string (zero-padded, e.g. "012") instead of int, and the out parameter names on TryParse overloads for Pesel, Nip, and Regon were renamed from identifier-specific names to result. It also adds TypeConverter support for Pesel, Nip, and Regon, TryParse(string?, IFormatProvider?, out T) overloads for ASP.NET Core Minimal API binding on all supported targets, and NipGenerator.Invalid.UnrecognizedFormat(). See CHANGELOG.md for details.