IDEncoder 0.2.0

There is a newer version of this package available.
See the version list below for details.
dotnet add package IDEncoder --version 0.2.0
                    
NuGet\Install-Package IDEncoder -Version 0.2.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="IDEncoder" Version="0.2.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="IDEncoder" Version="0.2.0" />
                    
Directory.Packages.props
<PackageReference Include="IDEncoder" />
                    
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 IDEncoder --version 0.2.0
                    
#r "nuget: IDEncoder, 0.2.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 IDEncoder@0.2.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=IDEncoder&version=0.2.0
                    
Install as a Cake Addin
#tool nuget:?package=IDEncoder&version=0.2.0
                    
Install as a Cake Tool

IDEncoder

NuGet License

A .NET library that encodes numeric IDs (long) into short, URL-safe Base62 strings — similar to how YouTube, Twitter and other services expose public IDs like dQw4w9WgXcQ instead of raw database numbers.

Uses Blowfish encryption under the hood with no external cryptography dependencies — the cipher is implemented from scratch.

Database:  42
URL:       /video/xK9mQ3bPl2a
JSON:      { "id": "xK9mQ3bPl2a", "title": "..." }

Why

  • Hide sequential IDs — users can't guess or enumerate resource URLs
  • Short output — always exactly 11 characters (vs 20 digits for long.MaxValue)
  • Reversible — decode back to the original number with the same key
  • Salted encoding — same ID produces different strings for different entity types
  • Zero external crypto dependencies — ships its own Blowfish implementation

Install

dotnet add package IDEncoder

Quick start

var encoder = new IDEncoder.IDEncoder("my-secret-key");

string encoded = encoder.Encode(42);       // "xK9mQ3bPl2a"
long decoded = encoder.Decode(encoded);    // 42

Salt

By default, the same numeric ID always encodes to the same string. This means a user who knows a video ID could try it as a gallery ID, a user ID, etc.

Salt solves this — the same number produces different strings for different entity types:

encoder.Encode(42);                // "xK9mQ3bPl2a"
encoder.Encode(42, "video");       // "t7RqN1cWm5z"
encoder.Encode(42, "gallery");     // "p3KmW8vLn9a"

// Decoding requires the same salt
encoder.Decode("t7RqN1cWm5z", "video");    // 42
encoder.Decode("p3KmW8vLn9a", "gallery");  // 42

Salted ciphers are cached internally — no performance penalty for reusing the same salt.

ASP.NET Core integration

Registration

// Key known at startup
services.AddIDEncoder("my-secret-key");

// Key from configuration
services.AddIDEncoder(provider => {
    var config = provider.GetRequiredService<IConfiguration>();
    return config["IDEncoder:SecretKey"]!;
});

// Key loaded later (e.g. from database after startup)
services.AddIDEncoderProvider();

For deferred initialization, call Configure when the key becomes available:

public class AppInitializer(IDEncoderProvider encoderProvider, IMyConfigService config) {
    public async Task InitializeAsync() {
        string secret = await config.GetSecretAsync("ID_ENCODER_SECRET");
        encoderProvider.Configure(secret);
    }
}

EncodedId struct

A long wrapper that automatically encodes/decodes at JSON and route-binding boundaries:

// DTO — JSON output is a Base62 string
public record ChatResult(EncodedId Id, string Title);

// Mapping — implicit conversion from long
return new ChatResult(Id: chat.Id, Title: chat.Title);
// { "id": "xK9mQ3bPl2a", "title": "My chat" }

// Controller — parsed from URL automatically via IParsable
[HttpGet("{id}")]
public async Task<IActionResult> Get(EncodedId id) {
    long dbId = id; // implicit conversion to long
    var chat = await db.Chats.FindAsync(dbId);
    return Ok(new ChatResult(chat.Id, chat.Title));
}

The database stores a plain long. Encoding only happens at the JSON/URL boundary.

Salt via attribute

Use [Salt("...")] on properties to automatically apply per-entity-type salt during JSON serialization:

public record VideoResult(
    [property: Salt("video")] EncodedId Id,
    string Title
);

public record GalleryResult(
    [property: Salt("gallery")] EncodedId Id,
    string Title
);

// Same DB id = 42, but different JSON output:
// VideoResult:   { "id": "t7RqN1cWm5z", "title": "..." }
// GalleryResult: { "id": "p3KmW8vLn9a", "title": "..." }

Enable salt support in JSON options:

services.AddControllers().AddJsonOptions(o => o.JsonSerializerOptions.UseIDEncoderSalts());

JSON behavior

Input Output
Write(42) "xK9mQ3bPl2a"
Read("xK9mQ3bPl2a") 42
Read(42) 42 (raw numbers accepted too)

Zero-alloc API

For high-throughput scenarios, span-based overloads avoid heap allocations:

// Encode into a stack buffer
Span<char> buffer = stackalloc char[IDEncoder.IDEncoder.EncodedLength];
encoder.Encode(42, buffer);

// Decode from a span (no string needed)
long id = encoder.Decode(buffer);

License

MIT

Product 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. 
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
0.3.0 88 3/18/2026
0.2.0 99 3/17/2026
0.1.1 108 3/17/2026