StrictId 2.0.2

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

StrictId

Strongly-typed, ergonomic, fun to use identifiers for your entities without any magic

StrictId EFCore


What

public class Person {
    public Id<Person> Id { get; init; } // Strongly typed ID, lexicographically sortable, and round-trip convertible to Guid, Ulid, and string
    public Id<Dog> BestFriendId { get; set; } // No confusion about what ID we are looking for here
    public List<Id> Friends { get; set; } // Non-strict/non-generic version also included
}
  • Strongly-typed IDs for your entities and everything else you care to identify
  • Ulid as the underlying value, which can easily be converted to and from Guid, string, or byte arrays
  • Ergonomic, developer-friendly usage without ceremony, boilerplate, or annoyance
  • Helps cure primitive obsession by giving you DDD-friendly value objects for IDs
  • Built-in JSON conversion support for System.Text.Json
  • Plug-and-play support for Entity Framework Core incl. value converters and value generators, with StrictId.EFCore
  • Easy to create your own integrations and converters - it's just a generic struct, no source generation magic
  • Tiny footprint and highly efficient, with only one dependency (Ulid)

How

Recommended, but optional
In your global usings file, add the following to save yourself a few keystrokes:

global using StrictId;

Create

Id<Person>.NewId(); // Generate a new random ID
new Id<Person>("01HV9AF3QA4T121HCZ873M0BKK"); // Create from ULID string
new Id<Person>("018ED2A7-8EEA-2682-20C5-9F41C7402E73"); // Create from GUID string
new Id<Person>(Ulid.NewUlid()); // Create from ULID
new Id<Person>(Guid.NewGuid()); // Create from GUID
new Id<Person>(Id.NewId()); // Create from non-typed ID

Id<Person> id = Ulid.NewUlid(); // Convert implicitly from Ulid
Id<Person> id = Guid.NewGuid(); // Convert implicitly from Guid
Id<Person> id = Id.NewId(); // Convert implicitly from non-typed Id
var id = (Id<Person>)"01HV9AF3QA4T121HCZ873M0BKK"; // Cast from string

Id<Person> id = Id<Person>.Parse("018ED2A7-8EEA-2682-20C5-9F41C7402E73"); // Parse from Guid or Ulid
bool success = Id<Person>.TryParse("01HV9AF3QA4T121HCZ873M0BKK", out Id<Person> id); // Safely parse from Guid or Ulid

Usage of the non-typed Id is identical.

Convert

var id = new Id<Person>("01HV9AF3QA4T121HCZ873M0BKK");

id.ToString(); // "01HV9AF3QA4T121HCZ873M0BKK"
id.ToUlid(); // Same as Ulid.Parse("01HV9AF3QA4T121HCZ873M0BKK");
id.ToGuid(); // Same as Guid.Parse("018ED2A7-8EEA-2682-20C5-9F41C7402E73");
id.ToByteArray(); // byte[]
id.ToId() // Id("018ED2A7-8EEA-2682-20C5-9F41C7402E73")

Benefit

StrictId will prevent you from accidentally doing bad things, and lets you do nice things instead:

var personId = Id<Person>.NewId();
var dogId = Id<Dog>.NewId();

if (personId == dogId) Console.Write("Uh oh"); // Compiler error

public void Feed(Id<Dog> id) { 
    GetDog(id).FeedLeftovers();
}

Feed(personId); // Compiler error

// But:
public class Diet {
    public void Feed(Id<Dog> id) { 
        GetDog(id).FeedLeftovers();
    }
    
    public void Feed(Id<Person> id) { 
        GetPerson(id).FeedMichelinStarMeal();
    }
}

Feed(personId); // We eat well tonight. Better method overloads!

With Entity Framework Core

Install StrictId.EFCore via NuGet

In your DbContext:

using StrictId.EFCore;

public class MyDatabase (DbContextOptions<MyDatabase> options) : DbContext(options)
{
    protected override void ConfigureConventions (ModelConfigurationBuilder builder)
    {
        // ...
        
        builder.ConfigureStrictId();
    }
}

To generate values:

using StrictId.EFCore;

// ...

builder.Property(e => e.Id)
    .ValueGeneratedOnAdd()
    .HasStrictIdValueGenerator();
Notes

Id values are stored as fixed-length Ulid strings in the database (e.g. "01HV9AF3QA4T121HCZ873M0BKK"). An alternative value converter for storing them as Guid is also included (StrictId.EFCore.ValueConverters.IdToGuidConverter). Keep in mind that storing the IDs as Guid makes the database representation visually different from the normal string representation, which can be inconvenient. If you prefer to store IDs as byte arrays or any other format, it's only a few lines of code to create your own value generator and converter based on the ones included. Keep in mind, though, that the small improvement you gain in database performance and storage by using byte arrays is most likely not worth the loss of readability and clarity.

Why

  • Using primitives such as Guid or Ulid as the type for IDs can easily lead to mixing up method arguments and assignments
  • Using value objects makes your code easier to read and more DDD-friendly (see primitive obsession)
  • Other similar packages are cumbersome, non-compatible, and full of magic™, while StrictId's Id is just a simple generic type, no source generation or other hocus-pocus needed
  • Ulid as the underlying type provides neat benefits over simple Guids, as they are ordered, making databases less fragmented, and look nicer as strings

Acknowledgements

  • Ulid - Library for ULID in C#, used for much of the underlying functionality
  • StronglyTypedId - For doing this first, but in a much more convoluted, non-ergonomic way

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.
  • net10.0

NuGet packages (4)

Showing the top 4 NuGet packages that depend on StrictId:

Package Downloads
StrictId.EFCore

Support for StrictId in Entity Framework Core.

StrictId.HotChocolate

Support for StrictId in Hot Chocolate.

Olve.Grids

Setting up a TileAtlas for generating tile-based art

StrictId.AspNetCore

ASP.NET Core integration for StrictId: OpenAPI schema generation with per-type patterns and examples, route constraints, legacy TypeConverter support, and ProblemDetails mapping for parse-failure binding errors. Route binding is free via ISpanParsable<T> in .NET 7+; this package adds the polish.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
3.0.0-preview.2 45 4/6/2026
2.0.2 93 4/5/2026
2.0.1 94 4/5/2026
2.0.0 88 4/5/2026
1.2.0 7,874 12/28/2024
1.1.0 16,846 6/6/2024
1.0.5 377 4/21/2024 1.0.5 is deprecated.
1.0.4 314 4/16/2024 1.0.4 is deprecated.
1.0.3 292 4/14/2024 1.0.3 is deprecated.
1.0.2 222 4/12/2024 1.0.2 is deprecated.
1.0.1 434 4/12/2024 1.0.1 is deprecated.
1.0.0 1,379 4/12/2024 1.0.0 is deprecated.