Attribute Reference¶
This page documents the attributes used to define and configure typed IDs.
[TypedId]¶
Marks a partial struct as a strongly-typed ID. The source generator produces a full value-type implementation including equality, comparison, parsing, formatting, and a TypeConverter.
Properties¶
| Property | Type | Default | Description |
|---|---|---|---|
BackingType |
BackingType |
Guid |
The underlying primitive type |
Converters |
IdConverters |
None |
Which serialization converters to generate |
Profile |
string? |
null |
Name of the [TypedIdProfile] to apply |
[TypedId(BackingType = BackingType.Int)]
public readonly partial struct OrderId;
[TypedId(Converters = IdConverters.JsonConverter | IdConverters.EfCoreValueConverter)]
public readonly partial struct CustomerId;
Backing Types¶
| Value | CLR Type | Empty Value |
Factory |
|---|---|---|---|
Guid |
System.Guid |
Guid.Empty |
New() generates a v7 UUID |
Int |
int |
0 |
No parameterless New() |
Long |
long |
0 |
No parameterless New() |
String |
string |
string.Empty |
No parameterless New() |
String null-checking
String-backed IDs validate against null and empty strings in the constructor. On .NET 7+ this uses ArgumentException.ThrowIfNullOrEmpty; on older targets it throws ArgumentNullException.
Converters¶
IdConverters is a flags enum — combine with |:
| Flag | What it generates |
|---|---|
JsonConverter |
System.Text.Json JsonConverter<T> nested class |
EfCoreValueConverter |
EF Core ValueConverter<T, TBacking> nested class |
A System.ComponentModel.TypeConverter is always generated regardless of flags. See the Converters page for details.
[TypedId(Converters = IdConverters.JsonConverter | IdConverters.EfCoreValueConverter)]
public readonly partial struct ProductId;
[TypedIdProfile]¶
Assembly-level attribute that defines a named or default configuration profile for [TypedId] structs. Multiple profiles can coexist in a single assembly. Use [TypedId(Profile = "name")] to select a profile.
An unnamed (default) profile applies to every [TypedId] that does not specify a Profile. Only one unnamed profile is allowed per assembly.
// Default profile — applies to [TypedId] without a Profile
[assembly: TypedIdProfile(Converters = IdConverters.JsonConverter)]
// Named profile for full-stack persistence
[assembly: TypedIdProfile("persistence",
Converters = IdConverters.EfCoreValueConverter | IdConverters.JsonConverter)]
[TypedId]
public readonly partial struct UserId; // gets JsonConverter from default profile
[TypedId(Profile = "persistence")]
public readonly partial struct OrderId; // gets EfCore + Json from named profile
[TypedId(BackingType = BackingType.String, Profile = "persistence")]
public readonly partial struct ExternalId; // String overrides profile's Guid default
| Property | Type | Default | Description |
|---|---|---|---|
Name |
string |
"" |
Profile name (unnamed = default profile) |
BackingType |
BackingType |
Guid |
Default backing type for matching IDs |
Converters |
IdConverters |
None |
Default converters for matching IDs |
[StreamId]¶
Companion attribute for [TypedId] that layers event stream identity members onto a typed ID struct. Generates a StreamName property and FromStreamName static parser for use with event-sourced aggregates.
Requirements
- The struct must also have
[TypedId](diagnostic DSID03). - Only
GuidandStringbacking types are supported (diagnostic DSID04).
Properties¶
| Property | Type | Default | Description |
|---|---|---|---|
Prefix |
string? |
Type name without Id suffix, lowercased |
Stream name prefix (e.g., OrderId → "order") |
Separator |
string |
"-" |
Separator between prefix and value |
Generated Members¶
| Member | Description |
|---|---|
StreamName |
Property formatted as {Prefix}{Separator}{Value} |
FromStreamName(string) |
Static method that parses a stream name back to the typed ID |
Examples¶
Default prefix (derived from type name):
[TypedId]
[StreamId]
public readonly partial struct OrderId;
var id = OrderId.New();
id.StreamName; // "order-550e8400-e29b-41d4-a716-446655440000"
OrderId.FromStreamName("order-550e8400-…"); // parses back to OrderId
Custom prefix and separator:
[TypedId]
[StreamId(Prefix = "ord", Separator = ":")]
public readonly partial struct OrderId;
var id = OrderId.New();
id.StreamName; // "ord:550e8400-e29b-41d4-a716-446655440000"
Diagnostics¶
| ID | Severity | Description | Code Fix |
|---|---|---|---|
| DSID01 | Error | TypedId struct must be partial |
Add partial modifier |
| DSID02 | Warning | TypedId struct should be readonly |
— |
| DSID03 | Error | StreamId requires TypedId | — |
| DSID04 | Warning | StreamId requires Guid or String backing type | — |
| DSID05 | Error | TypedId references unknown profile | — |
| DSID06 | Error | Duplicate default TypedId profile | — |