Dosaic.Extensions.NanoIds
1.2.9
dotnet add package Dosaic.Extensions.NanoIds --version 1.2.9
NuGet\Install-Package Dosaic.Extensions.NanoIds -Version 1.2.9
<PackageReference Include="Dosaic.Extensions.NanoIds" Version="1.2.9" />
<PackageVersion Include="Dosaic.Extensions.NanoIds" Version="1.2.9" />
<PackageReference Include="Dosaic.Extensions.NanoIds" />
paket add Dosaic.Extensions.NanoIds --version 1.2.9
#r "nuget: Dosaic.Extensions.NanoIds, 1.2.9"
#:package Dosaic.Extensions.NanoIds@1.2.9
#addin nuget:?package=Dosaic.Extensions.NanoIds&version=1.2.9
#tool nuget:?package=Dosaic.Extensions.NanoIds&version=1.2.9
Dosaic.Extensions.NanoIds
Dosaic.Extensions.NanoIds provides a strongly-typed NanoId value type for use across Dosaic services. It wraps NanoidDotNet to generate compact, URL-safe, unique identifiers and adds first-class support for JSON and YAML serialization, entity decoration via attributes, collision-safe length presets, and implicit conversion to/from string.
Installation
dotnet add package Dosaic.Extensions.NanoIds
Or add a package reference directly to your .csproj:
<PackageReference Include="Dosaic.Extensions.NanoIds" Version="" />
Features
- Strongly-typed ID —
NanoIdis a distinct type, not a plainstring, preventing accidental ID mix-ups across entity types. - No-look-alike alphabet — uses an alphabet that excludes visually ambiguous characters (e.g.
0,O,I,l) for safer human-readable IDs. - Attribute-driven generation — decorate any class with
[NanoId(length)]or[NanoId(length, "prefix_")]and generate correctly-sized, prefixed IDs with a single call. - Pre-calculated safe lengths —
NanoIdConfig.Lengthsdocuments the number of IDs needed to reach a 1 % collision probability for each ID length (L2–L24). - Full serialization support — built-in
JsonConverterandIYamlConvertersoNanoIdserializes as a plain string in both JSON and YAML. - Implicit
stringconversions — assign astringliteral to aNanoIdvariable and vice versa without an explicit cast. - Value semantics — implements
IComparable,IComparable<NanoId>, andIEquatable<NanoId>with==/!=operator support. INanoIdinterface — a lightweight marker interface for entity classes that expose aNanoId Idproperty.
Core Types
NanoId
The central value type. Wraps a string value and exposes factory methods for generating new IDs.
// Construct from a known string (e.g. loaded from a database)
var id = new NanoId("abc123");
// Implicit conversion from string
NanoId id2 = "abc123";
// Implicit conversion to string
string raw = id2;
// Parse (returns null for null input)
var id3 = NanoId.Parse(someNullableString);
INanoId
Implement this interface on any entity class that owns a NanoId primary key:
public class Order : INanoId
{
public NanoId Id { get; set; }
public string Description { get; set; }
}
NanoIdAttribute
Decorate entity classes with [NanoId] to configure the length (and optional prefix) of IDs generated for that type.
| Parameter | Type | Description |
|---|---|---|
length |
byte |
Number of random characters to generate |
prefix |
string |
Optional string prepended to every generated ID (default: "") |
// 12-character ID, no prefix → e.g. "wK3mRpNtVx8q"
[NanoId(NanoIdConfig.Lengths.NoLookAlikeDigitsAndLetters.L12)]
public class Product : INanoId
{
public NanoId Id { get; set; }
}
// 8 random characters with "ord_" prefix → e.g. "ord_Kp4mRx8t"
[NanoId(NanoIdConfig.Lengths.NoLookAlikeDigitsAndLetters.L8, "ord_")]
public class Order : INanoId
{
public NanoId Id { get; set; }
}
The LengthWithPrefix property gives the total stored length:
var attr = typeof(Order).GetCustomAttribute<NanoIdAttribute>();
// attr.Prefix == "ord_"
// attr.Length == 8
// attr.LengthWithPrefix == 12 (8 random + 4 prefix characters)
NanoIdConfig
Static configuration used internally during ID generation.
// The alphabet used for all generated IDs
// (no-look-alike digits + no-look-alike letters)
string alphabet = NanoIdConfig.Alphabet;
NanoIdConfig.Lengths.NoLookAlikeDigitsAndLetters
Pre-calculated constants that map an ID length to the number of IDs required to reach a 1 % collision probability. Use these constants instead of magic numbers.
| Constant | Length | IDs before ~1% collision |
|---|---|---|
L2 |
2 | 6 |
L3 |
3 | 48 |
L4 |
4 | 340 |
L5 |
5 | 2 K |
L6 |
6 | 16 K |
L7 |
7 | 116 K |
L8 |
8 | 817 K |
L9 |
9 | 5 M |
L10 |
10 | 40 M |
L11 |
11 | 280 M |
L12 |
12 | 1 B |
L13 |
13 | 13 B |
L14 |
14 | 96 B |
L15 |
15 | 673 B |
L16 |
16 | 4 T |
L17 |
17 | 32 T |
L18 |
18 | 230 T |
L19 |
19 | 1 616 T |
L20 |
20 | 11 312 T |
L24 |
24 | 27 161 781 T |
Figures are based on zelark.github.io/nano-id-cc.
Usage
Defining entity types
using Dosaic.Extensions.NanoIds;
[NanoId(NanoIdConfig.Lengths.NoLookAlikeDigitsAndLetters.L12)]
public class BlogPost : INanoId
{
public NanoId Id { get; set; }
public string Title { get; set; }
}
[NanoId(NanoIdConfig.Lengths.NoLookAlikeDigitsAndLetters.L8, "usr_")]
public class User : INanoId
{
public NanoId Id { get; set; }
public string Email { get; set; }
}
Generating new IDs
Use the generic overload when the type is known at compile time:
// Generic — type resolved at compile time
NanoId postId = NanoId.NewId<BlogPost>(); // e.g. "wK3mRpNtVx8q"
NanoId userId = NanoId.NewId<User>(); // e.g. "usr_Kp4mRx8t"
Use the Type overload when the type is only known at runtime (e.g. dynamic seeding scripts):
Type entityType = typeof(BlogPost);
NanoId id = NanoId.NewId(entityType);
NewIdthrowsArgumentExceptionif the target type does not have a[NanoId]attribute.
Generating IDs for database seed data
A common pattern is to pre-generate a fixed set of readable IDs for seed data files. The test project ships an [Explicit] helper test for exactly this purpose:
[Test]
[Explicit]
public void GenerateStaticIdsForDatabaseSeedData()
{
var modelType = typeof(BlogPost);
for (var i = 0; i < 10; i++)
{
TestContext.Out.WriteLine($"{modelType.Name}: {NanoId.NewId(modelType)}");
}
}
Run it once with your preferred type, then copy the output into your seed-data files.
Value semantics
NanoId supports all standard equality and comparison operations:
var a = new NanoId("abc");
var b = new NanoId("abc");
var c = new NanoId("xyz");
bool eq = a == b; // true
bool neq = a != c; // true
bool same = a.Equals(b); // true
int cmp = a.CompareTo(c); // negative (a < c lexicographically)
Passing a non-NanoId object to CompareTo(object) throws ArgumentException.
Constructing a NanoId with a null string throws ArgumentNullException.
Implicit string conversions
// string → NanoId
NanoId id = "abc123";
// NanoId → string
string raw = id;
// Works transparently in interpolated strings
Console.WriteLine($"Processing {id}"); // prints "abc123"
Serialization
NanoId serializes as a plain JSON/YAML string out of the box. No extra configuration is required when using Dosaic's default serialization stack.
JSON
public class OrderDto
{
public NanoId Id { get; init; }
}
var dto = new OrderDto { Id = NanoId.Parse("ord_Kp4mRx8t") };
string json = dto.Serialize();
// → {"id":"ord_Kp4mRx8t"}
OrderDto restored = json.Deserialize<OrderDto>();
// restored.Id.Value == "ord_Kp4mRx8t"
YAML
string yaml = dto.Serialize(SerializationMethod.Yaml);
// → id: ord_Kp4mRx8t
OrderDto restoredYaml = yaml.Deserialize<OrderDto>(SerializationMethod.Yaml);
// restoredYaml.Id.Value == "ord_Kp4mRx8t"
ToString and span formatting
var id = new NanoId("abc123");
// Default → returns the raw value; suitable for logging and interpolation
id.ToString(); // "abc123"
// With a format provider → "Value: <raw>"
id.ToString(CultureInfo.InvariantCulture); // "Value: abc123"
// Span-based formatting
Span<char> buf = stackalloc char[64];
id.TryFormat(buf, out int written, default, null);
// new string(buf[..written]) == "Value: abc123"
No plugin configuration required
Dosaic.Extensions.NanoIds is a pure library — it does not register any DI services or middleware and requires no entries in appsettings.yml. Simply reference the package and use the types directly.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | 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. |
-
net10.0
- Dosaic.Hosting.Abstractions (>= 1.2.9)
- Nanoid (>= 3.1.0)
NuGet packages (1)
Showing the top 1 NuGet packages that depend on Dosaic.Extensions.NanoIds:
| Package | Downloads |
|---|---|
|
Dosaic.Plugins.Persistence.EfCore.Abstractions
A plugin-first dotnet framework for rapidly building anything hosted in the web. |
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 1.2.9 | 36 | 3/13/2026 |
| 1.2.8 | 86 | 3/9/2026 |
| 1.2.7 | 83 | 3/4/2026 |
| 1.2.6 | 108 | 2/19/2026 |
| 1.2.5 | 86 | 2/17/2026 |
| 1.2.4 | 99 | 2/13/2026 |
| 1.2.3 | 110 | 1/27/2026 |
| 1.2.2 | 285 | 12/16/2025 |
| 1.2.1 | 284 | 12/16/2025 |
| 1.2.0 | 440 | 12/11/2025 |
| 1.1.21 | 463 | 12/10/2025 |
| 1.1.20 | 432 | 11/18/2025 |
| 1.1.19 | 314 | 11/11/2025 |
| 1.1.18 | 203 | 10/14/2025 |
| 1.1.17 | 207 | 10/1/2025 |
| 1.1.16 | 221 | 9/25/2025 |
| 1.1.15 | 209 | 9/24/2025 |
| 1.1.14 | 215 | 9/24/2025 |
| 1.1.13 | 218 | 9/24/2025 |
| 1.1.12 | 331 | 9/16/2025 |