A .NET source generator that emits interceptors for automatic, deterministic, compile-time unique ID generation. Supports HTML IDs, GUIDs, timestamps, short hashes, custom prefixes, and multiple parameters per method.
$ dotnet add package PraefixumPraefixum is a .NET 10 source generator that emits interceptors for automatic unique ID generation. It enables deterministic, human-friendly identifiers to be generated for method parameters marked with the [UniqueId] attribute.
[UniqueId] parameters in a single methodInstall via NuGet Package Manager:
dotnet add package Praefixum
Or via Package Manager Console:
Install-Package Praefixum
using Praefixum;
public static string CreateButton(
string text,
[UniqueId(UniqueIdFormat.HtmlId)] string? id = null)
{
return $"<button id=\"{id}\">{text}</button>";
}
// Each call generates a unique ID via the generated interceptor
var button1 = CreateButton("Click me"); // <button id="a1b2c3d4">Click me</button>
var button2 = CreateButton("Submit"); // <button id="x9y8z1w2">Submit</button>
The source generator emits interceptors that replace null [UniqueId] parameters with generated IDs based on the call location.
| Format | Example | Description |
|---|---|---|
HtmlId | a1b2c3d4 | HTML5-compliant ID (starts with letter, 8 characters) |
Guid | a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6 | 32-character deterministic GUID (no dashes) |
Timestamp | 1735052327842 | Unix timestamp in milliseconds |
ShortHash | YWJjZGVm | 8-character Base64-encoded hash |
public static string Div(
string content,
[UniqueId(UniqueIdFormat.HtmlId, prefix: "div-")] string? id = null)
{
return $"<div id=\"{id}\">{content}</div>";
}
// Usage
var html = Div("Hello World"); // <div id="div-a1b2c3d4">Hello World</div>
NEW: Praefixum now supports multiple [UniqueId] parameters in a single method!
public static string Form(
[UniqueId(UniqueIdFormat.HtmlId, prefix: "form-")] string? formId = null,
[UniqueId(UniqueIdFormat.HtmlId)] string? nameInputId = null,
[UniqueId(UniqueIdFormat.HtmlId)] string? emailInputId = null,
[UniqueId(UniqueIdFormat.Guid)] string? submitId = null)
{
return $@"
<form id=""{formId}"">
<input id=""{nameInputId}"" name=""name"" type=""text"" />
<input id=""{emailInputId}"" name=""email"" type=""email"" />
<button id=""{submitId}"" type=""submit"">Submit</button>
</form>";
}
// Usage - all IDs are automatically generated and unique
var form = Form();
// Generates: form-x1y2z3w4, a5b6c7d8, e9f0g1h2, i3j4k5l6m7n8o9p0q1r2s3t4u5v6w7x8
public static string Input(
[UniqueId(UniqueIdFormat.HtmlId, prefix: "input-")] string? id = null)
{
return $"<input id=\"{id}\" type=\"text\" />";
}
public static string Widget(
[UniqueId(UniqueIdFormat.HtmlId)] string? elementId = null,
[UniqueId(UniqueIdFormat.Timestamp)] string? timestampId = null,
[UniqueId(UniqueIdFormat.Guid)] string? uuid = null)
{
return $@"
<div id=""{elementId}"" data-timestamp=""{timestampId}"" data-uuid=""{uuid}"">
Widget Content
</div>";
}
[UniqueId] parameters[UniqueId] parametersFor this source code:
var form = CreateFormWithMultipleIds(); // Line 42, Column 12
The generator creates an interceptor that:
[UniqueId] parameters are provided[InterceptsLocation(1, "D:\\MyProject\\Program.cs(42,12)")]
public static string CreateFormWithMultipleIds_0(
string? formId = null,
string? nameInputId = null,
string? emailInputId = null,
string? submitButtonId = null)
{
// Check if all parameters provided
if (formId != null && nameInputId != null && emailInputId != null && submitButtonId != null)
return OriginalClass.CreateFormWithMultipleIds(formId, nameInputId, emailInputId, submitButtonId);
// Generate IDs for null parameters
var formIdFinal = formId ?? GenerateId("key:0", 1, UniqueIdFormat.HtmlId, "form-");
var nameInputIdFinal = nameInputId ?? GenerateId("key:1", 1, UniqueIdFormat.HtmlId, null);
var emailInputIdFinal = emailInputId ?? GenerateId("key:2", 1, UniqueIdFormat.HtmlId, null);
var submitButtonIdFinal = submitButtonId ?? GenerateId("key:3", 1, UniqueIdFormat.Guid, null);
return OriginalClass.CreateFormWithMultipleIds(formIdFinal, nameInputIdFinal, emailInputIdFinal, submitButtonIdFinal);
}
The project includes a comprehensive test suite covering:
[UniqueId] parameters[UniqueId] attributesRun tests with:
dotnet test
<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
<LangVersion>preview</LangVersion>
<EnablePreviewFeatures>true</EnablePreviewFeatures>
<InterceptorsNamespaces>$(InterceptorsNamespaces);Praefixum</InterceptorsNamespaces>
</PropertyGroup>
We welcome contributions! Please see CONTRIBUTING.md for guidelines.
dotnet restoredotnet build to build all projectsdotnet test to execute the test suitePraefixum/
├── Praefixum/ # Main source generator project
│ ├── UniqueIdGenerator.cs # Core source generator logic
│ └── UniqueIdAttribute.cs # Attribute definitions
├── Praefixum.Demo/ # Demo application
│ ├── Program.cs # Console demo
│ └── Html.cs # HTML generation examples
├── Praefixum.Tests/ # Comprehensive test suite
│ ├── UniqueIdGeneratorBasicTests.cs
│ ├── UniqueIdGeneratorEdgeCaseTests.cs
│ ├── UniqueIdFormatTests.cs
│ ├── UniqueIdGeneratorPerformanceTests.cs
│ └── TestHelpers.cs
└── docs/ # Documentation
Q: IDs are not being generated A: Ensure you're using .NET 10 and have enabled preview features and interceptors in your project.
Q: Duplicate ID errors A: This indicates the same call site is generating multiple IDs. Check your code structure.
Q: Build errors with interceptors
A: Verify your project targets .NET 10, LangVersion is preview, and preview features are enabled.
This project is licensed under the Apache License 2.0 - see the LICENSE file for details.
Made with ❤️ for the .NET community