### Basic ULID Usage Example Source: https://github.com/byteaether/ulid/blob/main/src/ByteAether.Ulid/PACKAGE.md Demonstrates basic ULID operations including creation, conversion to and from byte arrays, GUIDs, and strings. ```csharp using System; using ByteAether.Ulid; // Create a new ULID var ulid = Ulid.New(); // Convert to byte array and back byte[] byteArray = ulid.ToByteArray(); var ulidFromByteArray = Ulid.New(byteArray); // Convert to GUID and back Guid guid = ulid.ToGuid(); var ulidFromGuid = Ulid.New(guid); // Convert to string and back string ulidString = ulid.ToString(); var ulidFromString = Ulid.Parse(ulidString); Console.WriteLine($"ULID: {ulid}, GUID: {guid}, String: {ulidString}"); ``` -------------------------------- ### Install Specific Preview Version Source: https://github.com/byteaether/ulid/blob/main/src/ByteAether.Ulid/PACKAGE.md Installs a specific preview version of the ByteAether.Ulid package using the .NET CLI. ```sh dotnet add package ByteAether.Ulid --version ``` -------------------------------- ### Install Latest Stable Package Source: https://github.com/byteaether/ulid/blob/main/src/ByteAether.Ulid/PACKAGE.md Installs the latest stable version of the ByteAether.Ulid package using the .NET CLI. ```sh dotnet add package ByteAether.Ulid ``` -------------------------------- ### Dapper Query Examples with ULID Source: https://github.com/byteaether/ulid/blob/main/_autodocs/integration-guide.md Provides examples of inserting and querying data with ULID using Dapper, demonstrating proper reconstruction of ULID values. ```csharp using (var connection = new SqlConnection(connectionString)) { // Insert var ulid = Ulid.New(); connection.Execute( "INSERT INTO Entities (Id, Name) VALUES (@Id, @Name)", new { Id = ulid, Name = "Test" }); // Query var entity = connection.QuerySingle( "SELECT * FROM Entities WHERE Id = @Id", new { Id = ulid }); // Result has Ulid properly reconstructed } ``` -------------------------------- ### ULID Service Implementation and Usage Example Source: https://github.com/byteaether/ulid/blob/main/_autodocs/integration-guide.md Defines the IIdGenerator interface and UlidGenerator implementation, along with an example of how to use the ID generator within a service to create entities with ULID identifiers. ```csharp public interface IIdGenerator { Ulid Generate(); } public class UlidGenerator : IIdGenerator { private readonly Ulid.GenerationOptions _options; public UlidGenerator(Ulid.GenerationOptions options) { _options = options; } public Ulid Generate() => Ulid.New(_options); } // Usage in a service public class EntityService { private readonly IIdGenerator _idGenerator; private readonly ApplicationDbContext _dbContext; public EntityService(IIdGenerator idGenerator, ApplicationDbContext dbContext) { _idGenerator = idGenerator; _dbContext = dbContext; } public async Task CreateAsync(string name) { var entity = new Entity { Id = _idGenerator.Generate(), Name = name }; _dbContext.Entities.Add(entity); await _dbContext.SaveChangesAsync(); return entity; } } ``` -------------------------------- ### Hardware RNG Integration Example Source: https://github.com/byteaether/ulid/blob/main/_autodocs/api-reference/random-provider.md Integrate hardware-based random number generators for enhanced security. This example uses CryptGenRandom from kernel32.dll. ```csharp using System; using System.Runtime.InteropServices; using ByteAether.Ulid; public class HardwareRngProvider : IRandomProvider { [DllImport("kernel32.dll", SetLastError = true)] private static extern bool CryptGenRandom(IntPtr hProv, uint dwLen, byte[] pbBuffer); public void GetBytes(Span buffer) { if (CryptGenRandom(IntPtr.Zero, (uint)buffer.Length, buffer.ToArray())) { // Process generated bytes } } } ``` -------------------------------- ### Configure Initial Random Source for ULID Generation Source: https://github.com/byteaether/ulid/blob/main/_autodocs/configuration.md Illustrates configuring the InitialRandomSource for ULID generation. Examples include using the CryptographicallySecureRandomProvider for maximum security and PseudoRandomProvider for performance, as well as a custom implementation. ```csharp // Use cryptographic RNG for maximum security var options = new Ulid.GenerationOptions { InitialRandomSource = new CryptographicallySecureRandomProvider() }; // Use pseudo-random for performance var options2 = new Ulid.GenerationOptions { InitialRandomSource = new PseudoRandomProvider() }; // Custom implementation var options3 = new Ulid.GenerationOptions { InitialRandomSource = new MyCustomRandomProvider() }; ``` -------------------------------- ### IRandomProvider GetBytes Method Example Source: https://github.com/byteaether/ulid/blob/main/_autodocs/api-reference/random-provider.md Demonstrates how to use the GetBytes method of an IRandomProvider implementation to fill a byte span with random data. This is a fundamental operation for generating random components of ULIDs. ```csharp var provider = new CryptographicallySecureRandomProvider(); Span buffer = stackalloc byte[10]; provider.GetBytes(buffer); // buffer now contains 10 random bytes ``` -------------------------------- ### Configure ULID Generation Behavior Source: https://github.com/byteaether/ulid/blob/main/_autodocs/api-reference/generation-options.md Instantiate GenerationOptions to customize ULID generation. This example sets specific monotonicity and random sources for ULID creation. ```csharp var options = new Ulid.GenerationOptions { Monotonicity = Ulid.GenerationOptions.MonotonicityOptions.MonotonicRandom2Byte, InitialRandomSource = new CryptographicallySecureRandomProvider(), IncrementRandomSource = new PseudoRandomProvider() }; var ulid = Ulid.New(options); ``` -------------------------------- ### Custom Random Provider Implementation Source: https://github.com/byteaether/ulid/blob/main/_autodocs/api-reference/random-provider.md Implement the IRandomProvider interface to supply your own randomness source. This example uses the built-in Random class. ```csharp using System; using ByteAether.Ulid; public class CustomRandomProvider : IRandomProvider { private static readonly Random _rng = new(); public void GetBytes(Span buffer) { // Custom implementation for (int i = 0; i < buffer.Length; i++) { buffer[i] = (byte)_rng.Next(256); } } } // Usage var options = new Ulid.GenerationOptions { InitialRandomSource = new CustomRandomProvider(), IncrementRandomSource = new CustomRandomProvider() }; var ulid = Ulid.New(options); ``` -------------------------------- ### Convert GUIDs to ULIDs in C# Source: https://github.com/byteaether/ulid/blob/main/_autodocs/integration-guide.md Use these extension methods to convert existing GUIDs to ULIDs for migration purposes. Ensure you have the ULID library installed. ```csharp public static class GuidUlidExtensions { // Convert existing GUIDs to ULIDs public static Ulid ToUlid(this Guid guid) => Ulid.New(guid); // Batch conversion public static IEnumerable ToUlids(this IEnumerable guids) => guids.Select(g => Ulid.New(g)); } // Usage var guidIds = entities.Select(e => e.GuidId); var ulidIds = guidIds.ToUlids(); ``` -------------------------------- ### Ulid.New(Guid) Source: https://github.com/byteaether/ulid/blob/main/_autodocs/api-reference/ulid-struct.md Creates a new ULID instance from an existing GUID. This method is useful for converting between GUID and ULID formats, preserving the underlying byte content. ```APIDOC ## Ulid.New(Guid) ### Description Creates a ULID from an existing GUID, converting between the two identifier formats. ### Method `static Ulid New(Guid guid)` ### Parameters #### Path Parameters - **guid** (Guid) - Required - A GUID value to convert to ULID ### Returns A new `Ulid` instance with the same byte content as the GUID. ### Example ```csharp var guid = Guid.NewGuid(); var ulid = Ulid.New(guid); ``` ``` -------------------------------- ### Create ULID from GUID Source: https://github.com/byteaether/ulid/blob/main/_autodocs/api-reference/ulid-struct.md Creates a new ULID instance by converting an existing GUID. This is useful when you need to represent a GUID as a ULID. ```csharp public static Ulid New(Guid guid) { // Implementation details omitted for brevity throw new NotImplementedException(); } ``` ```csharp var guid = Guid.NewGuid(); var ulid = Ulid.New(guid); ``` -------------------------------- ### Thread-Safe Custom Random Provider Implementation Source: https://github.com/byteaether/ulid/blob/main/_autodocs/api-reference/random-provider.md Example of implementing a custom IRandomProvider that is thread-safe using a static Random instance and a lock. Ensure GetBytes is thread-safe for concurrent use. ```csharp using System; using ByteAether.Ulid; public class ThreadSafeCustomProvider : IRandomProvider { private static readonly Random _rng = new(); private static readonly object _lock = new(); public void GetBytes(Span buffer) { lock (_lock) { _rng.NextBytes(buffer); } } } ``` -------------------------------- ### Generate Monotonic ULID with Random Increments Source: https://github.com/byteaether/ulid/blob/main/README.md This example demonstrates how to generate ULIDs that are monotonically increasing by using a random increment. It configures the `Monotonicity` option to `MonotonicRandom2Byte`. ```csharp using System; using ByteAether.Ulid; using static ByteAether.Ulid.Ulid.GenerationOptions; // Configure options for a 2-byte random increment var options = new Ulid.GenerationOptions { Monotonicity = MonotonicityOptions.MonotonicRandom2Byte }; // Generate a ULID with the specified options var ulid = Ulid.New(options); Console.WriteLine($"ULID with random increment: {ulid}"); ``` -------------------------------- ### ULID Boundary Methods Source: https://github.com/byteaether/ulid/blob/main/_autodocs/MANIFEST.md Methods to get the minimum and maximum possible ULID values at a given point in time. ```APIDOC ## ULID Boundary Methods ### Description These static methods return the earliest possible ULID and the latest possible ULID for a given timestamp. ### Methods - `Ulid.MinAt(DateTimeOffset timestamp)` - `Ulid.MinAt(long unixTimestamp)` - `Ulid.MaxAt(DateTimeOffset timestamp)` - `Ulid.MaxAt(long unixTimestamp)` ### Parameters - `timestamp` (DateTimeOffset) - The point in time. - `unixTimestamp` (long) - The Unix timestamp (seconds since epoch). ### Return Value The minimum or maximum `Ulid` instance for the specified time. ``` -------------------------------- ### Configure Global ULID Generation Options Source: https://github.com/byteaether/ulid/blob/main/_autodocs/quick-reference.md Set default generation options for ULIDs application-wide. This example configures monotonic random generation for 2 bytes. ```csharp // Global config for app Ulid.DefaultGenerationOptions = new() { Monotonicity = Ulid.GenerationOptions.MonotonicityOptions.MonotonicRandom2Byte }; ``` -------------------------------- ### Configure Monotonicity for ULID Generation Source: https://github.com/byteaether/ulid/blob/main/_autodocs/configuration.md Shows how to set the Monotonicity option for ULID generation. The first example configures high security with random increments, while the second sets it to non-ordered for speed and lower security. ```csharp // High security with random increments var options = new Ulid.GenerationOptions { Monotonicity = Ulid.GenerationOptions.MonotonicityOptions.MonotonicRandom4Byte }; // Non-ordered (fast, lowest security) var options2 = new Ulid.GenerationOptions { Monotonicity = Ulid.GenerationOptions.MonotonicityOptions.NonMonotonic }; ``` -------------------------------- ### Configure Increment Random Source for ULID Generation Source: https://github.com/byteaether/ulid/blob/main/_autodocs/configuration.md Demonstrates configuring the IncrementRandomSource for ULID generation, used for monotonic random increments. The first example uses a pseudo-random source for fast increments, while the second uses a cryptographically secure source for slower but more secure increments. ```csharp // Fast increments with pseudo-random source var options = new Ulid.GenerationOptions { Monotonicity = Ulid.GenerationOptions.MonotonicityOptions.MonotonicRandom2Byte, IncrementRandomSource = new PseudoRandomProvider() // Fast }; // Cryptographically secure increments var options2 = new Ulid.GenerationOptions { Monotonicity = Ulid.GenerationOptions.MonotonicityOptions.MonotonicRandom2Byte, IncrementRandomSource = new CryptographicallySecureRandomProvider() // Slower }; ``` -------------------------------- ### ULID String Format Example Source: https://github.com/byteaether/ulid/blob/main/_autodocs/INDEX.md Illustrates the 26-character Crockford's Base32 string format of a ULID, showing the separation between the timestamp and random components. ```text 01ARZ3NDEKTSV4RRFFQ69G5FAV ^^^^^^^^^^ Time (48 bits) ^^^^^^^^^^^^^^^^^^ Random (80 bits) ``` -------------------------------- ### JSON Serialization and Deserialization Source: https://github.com/byteaether/ulid/blob/main/_autodocs/quick-reference.md Shows how to serialize and deserialize ULID values using System.Text.Json. Automatic integration requires no setup, while manual conversion involves registering a custom converter. ```csharp using System.Text.Json; // Automatic (no setup needed) var json = JsonSerializer.Serialize(new { id = ulid }); // Output: {"id":"01ARZ3NDEKTSV4RRFFQ69G5FAV"} var obj = JsonSerializer.Deserialize(json); // Manual converter registration var options = new JsonSerializerOptions { Converters = { new UlidJsonConverter() } }; var json = JsonSerializer.Serialize(ulid, options); ``` -------------------------------- ### ASP.NET Core Integration Example Source: https://github.com/byteaether/ulid/blob/main/_autodocs/types.md Demonstrates how the UlidTypeConverter is automatically applied in an ASP.NET Core API controller. The 'id' route parameter of type Ulid is automatically converted from the URL. ```csharp [ApiController] [Route("api/[controller]")] public class ExampleController : ControllerBase { [HttpGet("{id}")] public ActionResult Get(Ulid id) // Automatically converts route parameter { return Ok(id.ToString()); } } ``` -------------------------------- ### Perform ULID range queries Source: https://github.com/byteaether/ulid/blob/main/_autodocs/quick-reference.md Provides examples for generating minimum and maximum ULIDs for a given timestamp, suitable for database range queries. Demonstrates querying entities within a specific date range. ```csharp // For database range queries with timestamps // Minimum ULID at timestamp (all random bytes = 0x00) var minUlid = Ulid.MinAt(DateTime.UtcNow); // Maximum ULID at timestamp (all random bytes = 0xFF) var maxUlid = Ulid.MaxAt(DateTime.UtcNow); // Example: Query entities from yesterday var startOfYesterday = DateTimeOffset.UtcNow.AddDays(-1).Date; var endOfYesterday = startOfYesterday.AddDays(1).AddTicks(-1); var minUlid = Ulid.MinAt(startOfYesterday); var maxUlid = Ulid.MaxAt(endOfYesterday); var entities = dbContext.Entities .Where(e => e.Id >= minUlid && e.Id <= maxUlid) .ToList(); ``` -------------------------------- ### EF Core Migration for ULID column Source: https://github.com/byteaether/ulid/blob/main/_autodocs/integration-guide.md This C# code snippet shows how to perform an EF Core migration by adding a BINARY(16) column, copying GUID data using SQL, dropping the old column, and renaming the new one. ```csharp protected override void Up(MigrationBuilder migrationBuilder) { migrationBuilder.AddColumn( name: "NewId", table: "Entities", type: "BINARY(16)"); // Copy existing GUID data migrationBuilder.Sql( "UPDATE Entities SET NewId = CAST(OldGuidId AS BINARY(16))"); migrationBuilder.DropColumn("OldGuidId", "Entities"); migrationBuilder.RenameColumn("NewId", "Entities", "Id"); } ``` -------------------------------- ### Implicit ULID to Guid Conversion Source: https://github.com/byteaether/ulid/blob/main/_autodocs/api-reference/ulid-struct.md Allows automatic conversion of a ULID object to a Guid. Useful when integrating with systems that expect Guids. ```csharp public static implicit operator Guid(Ulid ulid) ``` ```csharp Ulid ulid = Ulid.New(); Guid guid = ulid; // Implicit conversion to Guid ``` -------------------------------- ### Convert GUID to ULID Source: https://github.com/byteaether/ulid/blob/main/_autodocs/quick-reference.md Convert an existing GUID to a ULID, often necessary during data migration processes. Ensure the GUID is compatible. ```csharp // Convert GUID to ULID (for migration) var ulid = Ulid.New(existingGuid); ``` -------------------------------- ### Create ULID from GUID Source: https://github.com/byteaether/ulid/blob/main/_autodocs/MANIFEST.md Creates a new ULID from a GUID. The timestamp part will be derived from the GUID's timestamp if available, otherwise it will be zero. ```csharp var guid = Guid.NewGuid(); var ulid = Ulid.New(guid); ``` -------------------------------- ### Implement Custom Random Provider Source: https://github.com/byteaether/ulid/blob/main/_autodocs/MANIFEST.md Demonstrates how to implement the `IRandomProvider` interface to create a custom source of randomness for ULID generation. This allows for integration with hardware RNGs or other custom logic. ```csharp public class HardwareRngProvider : IRandomProvider { public void GetBytes(Span buffer) { // Implementation using hardware RNG // Example: Fill buffer with random data for (int i = 0; i < buffer.Length; i++) { buffer[i] = (byte)Random.Shared.Next(256); } } } var customProvider = new HardwareRngProvider(); var ulid = Ulid.New(new GenerationOptions { InitialRandomSource = customProvider }); ``` -------------------------------- ### Configure ULID generation options Source: https://github.com/byteaether/ulid/blob/main/_autodocs/quick-reference.md Illustrates how to set default generation options for the entire application or create specific options for individual ULID generation calls. Covers monotonicity and random source configuration. ```csharp // Set default options for entire application (do this once at startup) Ulid.DefaultGenerationOptions = new Ulid.GenerationOptions { Monotonicity = Ulid.GenerationOptions.MonotonicityOptions.MonotonicRandom2Byte, InitialRandomSource = new CryptographicallySecureRandomProvider(), IncrementRandomSource = new PseudoRandomProvider() }; // Create specific options for a call var options = new Ulid.GenerationOptions { Monotonicity = Ulid.GenerationOptions.MonotonicityOptions.NonMonotonic }; var ulid = Ulid.New(options); // Modify options using `with` expression var newOptions = existingOptions with { Monotonicity = Ulid.GenerationOptions.MonotonicityOptions.MonotonicIncrement }; ``` -------------------------------- ### Convert ULID to GUID Source: https://github.com/byteaether/ulid/blob/main/_autodocs/MANIFEST.md Converts a ULID to a GUID. Note that this conversion may lose precision or information if the ULID's timestamp is outside the range representable by a GUID's timestamp. ```csharp var ulid = Ulid.New(); Guid guid = ulid.ToGuid(); ``` -------------------------------- ### Configure Initial Random Source with Custom Provider Source: https://github.com/byteaether/ulid/blob/main/_autodocs/api-reference/generation-options.md Use a custom implementation for the InitialRandomSource, such as MyCustomRandomProvider. ```csharp var options2 = new Ulid.GenerationOptions { InitialRandomSource = new MyCustomRandomProvider() }; ``` -------------------------------- ### Implicit GUID Conversion Source: https://github.com/byteaether/ulid/blob/main/_autodocs/MANIFEST.md Allows implicit conversion between ULID and GUID types, simplifying assignments and comparisons. ```csharp Guid guid = Ulid.New(); // Implicit conversion to GUID Ulid ulid = Guid.NewGuid(); // Implicit conversion from GUID ``` -------------------------------- ### Set Default Generation Options for ULID Source: https://github.com/byteaether/ulid/blob/main/README.md Illustrates how to set default generation options for the entire application, such as using a pseudo-random provider for both initial and increment sources. Subsequent calls to `Ulid.New()` will use these defaults. ```csharp using System; using ByteAether.Ulid; using static ByteAether.Ulid.Ulid.GenerationOptions; // Set default generation options for the entire application Ulid.DefaultGenerationOptions = new() { Monotonicity = MonotonicityOptions.MonotonicIncrement, InitialRandomSource = new PseudoRandomProvider(), IncrementRandomSource = new PseudoRandomProvider() }; // Now, any subsequent call to Ulid.New() will use these options var ulid = Ulid.New(); Console.WriteLine($"ULID from pseudo-random source: {ulid}"); ``` -------------------------------- ### Configure Initial Random Source with PseudoRandomProvider Source: https://github.com/byteaether/ulid/blob/main/_autodocs/api-reference/generation-options.md Set the InitialRandomSource to PseudoRandomProvider for potentially faster, non-cryptographic randomness when a new timestamp is encountered. ```csharp var options = new Ulid.GenerationOptions { InitialRandomSource = new PseudoRandomProvider() }; ``` -------------------------------- ### Convert ULID to Guid Source: https://github.com/byteaether/ulid/blob/main/_autodocs/api-reference/ulid-struct.md Converts the ULID to a System.Guid with equivalent byte content. Use this for compatibility with systems expecting GUIDs. ```csharp public Guid ToGuid() ``` ```csharp var ulid = Ulid.New(); Guid guid = ulid.ToGuid(); ``` -------------------------------- ### Compare ULIDs using operators and CompareTo Source: https://github.com/byteaether/ulid/blob/main/_autodocs/quick-reference.md Demonstrates how to compare ULIDs using standard comparison operators (<, <=, >, >=) and the CompareTo method. Useful for sorting or ordering ULIDs. ```csharp var ulid1 = Ulid.New(); var ulid2 = Ulid.New(); // Comparison operators if (ulid1 < ulid2) { } if (ulid1 <= ulid2) { } if (ulid1 > ulid2) { } if (ulid1 >= ulid2) { } // Equality operators if (ulid1 == ulid2) { } if (ulid1 != ulid2) { } // CompareTo int comparison = ulid1.CompareTo(ulid2); // < 0: ulid1 is earlier // = 0: equal // > 0: ulid1 is later // Equals if (ulid1.Equals(ulid2)) { } ``` -------------------------------- ### Default Generation Options Initialization Source: https://github.com/byteaether/ulid/blob/main/_autodocs/configuration.md Illustrates the default values for GenerationOptions, including monotonicity and random sources. ```csharp new Ulid.GenerationOptions { Monotonicity = MonotonicityOptions.MonotonicIncrement, InitialRandomSource = new CryptographicallySecureRandomProvider(), IncrementRandomSource = new PseudoRandomProvider() } ``` -------------------------------- ### Implicit Guid to ULID Conversion Source: https://github.com/byteaether/ulid/blob/main/_autodocs/api-reference/ulid-struct.md Allows automatic conversion of a Guid to a ULID object. Useful for migrating from Guid-based systems to ULID. ```csharp public static implicit operator Ulid(Guid guid) ``` ```csharp Ulid fromGuid = guid; // Implicit conversion from Guid ``` -------------------------------- ### Using PseudoRandomProvider for Fast Increments Source: https://github.com/byteaether/ulid/blob/main/_autodocs/api-reference/random-provider.md Demonstrates how to configure Ulid generation options to use PseudoRandomProvider for fast increments. This is useful when performance is critical and cryptographic security is not required for the increment part of the ULID. ```csharp var provider = new PseudoRandomProvider(); var options = new Ulid.GenerationOptions { Monotonicity = Ulid.GenerationOptions.MonotonicityOptions.MonotonicRandom2Byte, IncrementRandomSource = provider // Fast increments }; var ulid = Ulid.New(options); ``` -------------------------------- ### ULID Implicit Operators Source: https://github.com/byteaether/ulid/blob/main/_autodocs/api-reference/ulid-struct.md Enables seamless conversion between ULID and other data types like string and Guid. ```APIDOC ## Implicit Operators ### Ulid ↔ string Allows automatic conversion between `Ulid` and `string` (to its Base32 representation). **Example:** ```csharp Ulid ulid = Ulid.New(); string ulidString = ulid; // Implicit conversion to string Ulid parsedUlid = "01ARZ3NDEKTSV4RRFFQ69G5FAV"; // Implicit conversion from string ``` ### Ulid ↔ Guid Allows automatic conversion between `Ulid` and `Guid`. **Example:** ```csharp Ulid ulid = Ulid.New(); Guid guid = ulid; // Implicit conversion to Guid Ulid fromGuid = guid; // Implicit conversion from Guid ``` ``` -------------------------------- ### Configuring ULID Generation with Custom Random Providers Source: https://github.com/byteaether/ulid/blob/main/_autodocs/api-reference/random-provider.md Demonstrates how to configure ULID generation using GenerationOptions, specifying both initial and increment random sources. This allows for global or per-call configuration of random providers. ```csharp using ByteAether.Ulid; // Configure via GenerationOptions var options = new Ulid.GenerationOptions { InitialRandomSource = new CryptographicallySecureRandomProvider(), IncrementRandomSource = new PseudoRandomProvider() }; // Use with specific call var ulid = Ulid.New(options); // Or set globally Ulid.DefaultGenerationOptions = options; var ulid2 = Ulid.New(); // Uses the configured providers ``` -------------------------------- ### Configure Monotonicity for ULID Generation Source: https://github.com/byteaether/ulid/blob/main/_autodocs/MANIFEST.md Demonstrates how to configure monotonicity options for ULID generation. Monotonicity ensures that ULIDs generated within the same millisecond are strictly increasing. ```csharp // Use default MonotonicIncrement var ulid1 = Ulid.New(new GenerationOptions { Monotonicity = MonotonicityOptions.MonotonicIncrement }); // Use MonotonicRandom4Byte for increased randomness within the same millisecond var ulid2 = Ulid.New(new GenerationOptions { Monotonicity = MonotonicityOptions.MonotonicRandom4Byte }); // Disable monotonicity (not recommended for most use cases) var ulid3 = Ulid.New(new GenerationOptions { Monotonicity = MonotonicityOptions.NonMonotonic }); ``` -------------------------------- ### ToGuid() Source: https://github.com/byteaether/ulid/blob/main/_autodocs/api-reference/ulid-struct.md Converts the ULID to a System.Guid with equivalent byte content. This is useful for interoperability with systems that use GUIDs. ```APIDOC ## ToGuid() ### Description Converts the ULID to a `System.Guid` with equivalent byte content. ### Returns A `Guid` with the same byte representation as the ULID. ### Example ```csharp var ulid = Ulid.New(); Guid guid = ulid.ToGuid(); ``` ``` -------------------------------- ### Get Maximum ULID Value Source: https://github.com/byteaether/ulid/blob/main/_autodocs/MANIFEST.md Represents the largest possible ULID value. Useful for initialization or comparison. ```csharp var maxUlid = Ulid.MaxValue; ``` -------------------------------- ### Get Minimum ULID Value Source: https://github.com/byteaether/ulid/blob/main/_autodocs/MANIFEST.md Represents the smallest possible ULID value. Useful for initialization or comparison. ```csharp var minUlid = Ulid.MinValue; ``` -------------------------------- ### Configure Default Generation Options Safely Source: https://github.com/byteaether/ulid/blob/main/_autodocs/errors.md Set `Ulid.DefaultGenerationOptions` once at application startup. Wrap this configuration in a try-catch block to handle potential `ArgumentOutOfRangeException` if invalid options are provided. ```csharp // In Main() or Program.cs try { Ulid.DefaultGenerationOptions = new Ulid.GenerationOptions { Monotonicity = Ulid.GenerationOptions.MonotonicityOptions.MonotonicRandom2Byte }; } catch (ArgumentOutOfRangeException) { // Configuration error - log and exit Environment.Exit(1); } ``` -------------------------------- ### Time Property Source: https://github.com/byteaether/ulid/blob/main/_autodocs/api-reference/ulid-struct.md Gets the timestamp component of the ULID as a DateTimeOffset. This property allows easy access to the creation time of the ULID. ```APIDOC ## Time Property ### Description Gets the timestamp component of the ULID as a `DateTimeOffset`. ### Returns A `DateTimeOffset` representing when the ULID was created. ### Example ```csharp var ulid = Ulid.New(); var timestamp = ulid.Time; Console.WriteLine($"Created at: {timestamp:O}"); ``` ``` -------------------------------- ### Get Empty ULID Value Source: https://github.com/byteaether/ulid/blob/main/_autodocs/MANIFEST.md Represents an empty or default ULID value, typically all zeros. Useful for default initialization. ```csharp var emptyUlid = Ulid.Empty; ``` -------------------------------- ### UlidTypeConverter Class Definition Source: https://github.com/byteaether/ulid/blob/main/_autodocs/types.md Defines the UlidTypeConverter class, inheriting from TypeConverter. It declares support for converting to and from string, byte[], and Guid types. ```csharp public class UlidTypeConverter : TypeConverter { private static readonly Type[] _convertibleTypes = [typeof(string), typeof(byte[]), typeof(Guid)]; public override bool CanConvertFrom(ITypeDescriptorContext? context, Type sourceType) public override object? ConvertFrom(ITypeDescriptorContext? context, CultureInfo? culture, object value) public override bool CanConvertTo(ITypeDescriptorContext? context, Type? destinationType) public override object? ConvertTo(ITypeDescriptorContext? context, CultureInfo? culture, object? value, Type destinationType) } ``` -------------------------------- ### Get ULID as Byte Span Source: https://github.com/byteaether/ulid/blob/main/_autodocs/api-reference/ulid-struct.md Returns a read-only span of the ULID's 16 bytes. This is more efficient than ToByteArray() as it avoids allocation. ```csharp public ReadOnlySpan AsByteSpan() ``` ```csharp var ulid = Ulid.New(); ReadOnlySpan bytes = ulid.AsByteSpan(); ``` -------------------------------- ### Benchmark Results Overview Source: https://github.com/byteaether/ulid/blob/main/README.md This table summarizes the performance of various ULID generation methods, including ByteAether's implementation and others, across different configurations. It highlights mean execution time, error margins, and memory allocation. ```text BenchmarkDotNet v0.15.8, Windows 10 (10.0.19044.7417/21H2/November2021Update) AMD Ryzen 7 3700X 3.60GHz, 1 CPU, 12 logical and 6 physical cores .NET SDK 10.0.301 [Host] : .NET 10.0.9 (10.0.9, 10.0.926.27113), X64 RyuJIT x86-64-v3 DefaultJob : .NET 10.0.9 (10.0.9, 10.0.926.27113), X64 RyuJIT x86-64-v3 Job=DefaultJob | Type | Method | Mean | Error | Gen0 | Allocated | |---------------- |------------------- |------------:|----------:|-------:|----------:| | Generate | ByteAetherUlid | 41.0279 ns | 0.0968 ns | - | - | | Generate | ByteAetherUlidR1Bp | 47.2891 ns | 0.1171 ns | - | - | | Generate | ByteAetherUlidR4Bp | 51.9968 ns | 0.0910 ns | - | - | | Generate | ByteAetherUlidR1Bc | 90.0880 ns | 0.1864 ns | - | - | | Generate | ByteAetherUlidR4Bc | 96.0395 ns | 0.2255 ns | - | - | | Generate | NetUlid *(1) | 158.6095 ns | 0.9265 ns | 0.0095 | 80 B | | Generate | NUlid *(2) | 48.7143 ns | 0.0948 ns | - | - | | GenerateNonMono | ByteAetherUlid | 90.1055 ns | 0.3176 ns | - | - | | GenerateNonMono | ByteAetherUlidP | 41.1849 ns | 0.0736 ns | - | - | | GenerateNonMono | Ulid *(3,4) | 39.2001 ns | 0.1008 ns | - | - | | GenerateNonMono | NUlid | 93.0571 ns | 0.1699 ns | - | - | | GenerateNonMono | Guid *(5) | 47.1776 ns | 0.0932 ns | - | - | | GenerateNonMono | GuidV7 *(3,5) | 77.4890 ns | 0.2267 ns | - | - | | FromByteArray | ByteAetherUlid | 0.8044 ns | 0.0070 ns | - | - | | FromByteArray | NetUlid | 1.4115 ns | 0.0111 ns | - | - | | FromByteArray | Ulid | 1.1808 ns | 0.0080 ns | - | - | | FromByteArray | NUlid | 1.1515 ns | 0.0063 ns | - | - | | FromByteArray | Guid | 1.0440 ns | 0.0059 ns | - | - | | FromGuid | ByteAetherUlid | 0.8255 ns | 0.0057 ns | - | - | | FromGuid | NetUlid | 2.0028 ns | 0.0373 ns | - | - | | FromGuid | Ulid | 1.9495 ns | 0.0116 ns | - | - | | FromGuid | NUlid | 0.9240 ns | 0.0183 ns | - | - | | FromString | ByteAetherUlid | 14.4357 ns | 0.0392 ns | - | - | | FromString | NetUlid | 27.2159 ns | 0.0690 ns | - | - | | FromString | Ulid | 16.9972 ns | 0.0311 ns | - | - | | FromString | NUlid | 53.9897 ns | 0.1649 ns | 0.0086 | 72 B | | FromString | Guid | 21.8639 ns | 0.1228 ns | - | - | | ToByteArray | ByteAetherUlid | 4.7470 ns | 0.1274 ns | 0.0048 | 40 B | | ToByteArray | AsByteSpan *(6) | 0.7736 ns | 0.0051 ns | - | - | | ToByteArray | NetUlid | 9.4871 ns | 0.1054 ns | 0.0048 | 40 B | | ToByteArray | Ulid | 4.7189 ns | 0.1066 ns | 0.0048 | 40 B | | ToByteArray | NUlid | 8.7597 ns | 0.1460 ns | 0.0048 | 40 B | | ToGuid | ByteAetherUlid | 0.8170 ns | 0.0070 ns | - | - | | ToGuid | NetUlid | 10.3155 ns | 0.0230 ns | - | - | | ToGuid | Ulid | 0.9731 ns | 0.0074 ns | - | - | | ToGuid | NUlid | 0.7636 ns | 0.0061 ns | - | - | ``` -------------------------------- ### Get ULID as Byte Span Source: https://github.com/byteaether/ulid/blob/main/_autodocs/MANIFEST.md Provides a read-only span of the ULID's 10-byte representation without allocating a new array. ```csharp var ulid = Ulid.New(); ReadOnlySpan byteSpan = ulid.AsByteSpan(); ``` -------------------------------- ### ULID Configuration: Maximum Performance Source: https://github.com/byteaether/ulid/blob/main/_autodocs/api-reference/random-provider.md Configure ULID generation for maximum performance by using PseudoRandomProvider for both initial and increment sources, with non-monotonicity. This pattern is the fastest but offers lower randomness quality. ```csharp using ByteAether.Ulid; Ulid.DefaultGenerationOptions = new Ulid.GenerationOptions { Monotonicity = Ulid.GenerationOptions.MonotonicityOptions.NonMonotonic, InitialRandomSource = new PseudoRandomProvider(), IncrementRandomSource = new PseudoRandomProvider() }; ``` -------------------------------- ### Get Maximum ULID at Timestamp Source: https://github.com/byteaether/ulid/blob/main/_autodocs/MANIFEST.md Returns the maximum possible ULID value for a given DateTimeOffset timestamp. This is useful for setting boundaries. ```csharp var maxUlid = Ulid.MaxAt(DateTimeOffset.UtcNow); ``` -------------------------------- ### ULID Boundary Values Source: https://github.com/byteaether/ulid/blob/main/_autodocs/quick-reference.md Demonstrates how to access and compare the minimum and maximum ULID values. ```csharp // Minimum ULID (all zeros) var min = Ulid.MinValue; // 00000000000000000000000000 var empty = Ulid.Empty; // Same as MinValue // Maximum ULID (all 0xFF) var max = Ulid.MaxValue; // ZZZZZZZZZZZZZZZZZZZZZZZZZZ // Test with boundaries if (ulid == Ulid.MinValue) { /* Is empty */ } if (ulid == Ulid.MaxValue) { /* Is maximum */ } ``` -------------------------------- ### Configure Initial Random Source Source: https://github.com/byteaether/ulid/blob/main/_autodocs/MANIFEST.md Allows specifying a custom random provider to be used for the initial random bytes when a ULID is generated. This is useful for testing or specific security requirements. ```csharp var customRandomProvider = new PseudoRandomProvider(12345); var ulid = Ulid.New(new GenerationOptions { InitialRandomSource = customRandomProvider }); ``` -------------------------------- ### Get Minimum ULID at Timestamp Source: https://github.com/byteaether/ulid/blob/main/_autodocs/MANIFEST.md Returns the minimum possible ULID value for a given DateTimeOffset timestamp. This is useful for setting boundaries. ```csharp var minUlid = Ulid.MinAt(DateTimeOffset.UtcNow); ``` -------------------------------- ### Configure Monotonic with Random Increments Source: https://github.com/byteaether/ulid/blob/main/_autodocs/api-reference/generation-options.md Use MonotonicityOptions.MonotonicRandom2Byte for monotonic ordering with random 2-byte increments. ```csharp var randomized = new Ulid.GenerationOptions { Monotonicity = Ulid.GenerationOptions.MonotonicityOptions.MonotonicRandom2Byte }; ``` -------------------------------- ### Get ULID Hash Code Source: https://github.com/byteaether/ulid/blob/main/_autodocs/api-reference/ulid-struct.md Returns a hash code for the ULID, suitable for use in hash tables. This is an override of the base GetHashCode method. ```csharp public override int GetHashCode() { // ... implementation details ... } ``` -------------------------------- ### ULID Configuration: Balanced Performance and Security Source: https://github.com/byteaether/ulid/blob/main/_autodocs/api-reference/random-provider.md Configure ULID generation with a balanced approach, using CryptographicallySecureRandomProvider for the initial source and PseudoRandomProvider for the increment source. This offers good security with reasonable performance. ```csharp using ByteAether.Ulid; Ulid.DefaultGenerationOptions = new Ulid.GenerationOptions { Monotonicity = Ulid.GenerationOptions.MonotonicityOptions.MonotonicRandom2Byte, InitialRandomSource = new CryptographicallySecureRandomProvider(), IncrementRandomSource = new PseudoRandomProvider() }; ``` -------------------------------- ### Entity Framework Core Integration for ULID Source: https://github.com/byteaether/ulid/blob/main/_autodocs/quick-reference.md Demonstrates configuring Entity Framework Core to handle ULID properties, including entity definition and DbContext configuration for byte conversion. ```csharp // Entity definition public class Entity { public Ulid Id { get; set; } = Ulid.New(); public string Name { get; set; } } // DbContext configuration protected override void ConfigureConventions(ModelConfigurationBuilder configurationBuilder) { configurationBuilder .Properties() .HaveConversion(); } // Storage: BINARY(16) modelBuilder.Entity() .Property(e => e.Id) .HasColumnType("BINARY(16)"); ``` -------------------------------- ### ULID Conversions and Interoperability Source: https://github.com/byteaether/ulid/blob/main/src/ByteAether.Ulid/PACKAGE.md Provides methods for converting ULID instances to byte spans, byte arrays, GUIDs, and string representations, along with implicit operators. ```APIDOC ## Conversions & Interoperability ### `.AsByteSpan()` Provides a `ReadOnlySpan` representing the contents of the ULID. ### `.ToByteArray()` Converts the ULID to a byte array. ### `.ToGuid()` Converts the ULID to a `Guid`. ### `.ToString(string? format = null, IFormatProvider? formatProvider = null)` Converts the ULID to a canonical string representation. Format arguments are ignored. Provides implicit operators to and from `Guid` and `string`. ``` -------------------------------- ### Using CryptographicallySecureRandomProvider for ULID Generation Source: https://github.com/byteaether/ulid/blob/main/_autodocs/api-reference/random-provider.md Shows how to instantiate CryptographicallySecureRandomProvider and use it as the initial random source in Ulid.GenerationOptions. This ensures strong randomness for new ULID generation. ```csharp var provider = new CryptographicallySecureRandomProvider(); var options = new Ulid.GenerationOptions { InitialRandomSource = provider }; var ulid = Ulid.New(options); ``` -------------------------------- ### Use Maximum Performance Random Provider Strategy Source: https://github.com/byteaether/ulid/blob/main/_autodocs/MANIFEST.md Configures ULID generation to use a pseudo-random provider for all randomness. This offers the highest performance but is not cryptographically secure. ```csharp var options = new GenerationOptions { InitialRandomSource = new PseudoRandomProvider(42), IncrementRandomSource = new PseudoRandomProvider(42) }; var ulid = Ulid.New(options); ``` -------------------------------- ### Use Pseudo-Random Provider Source: https://github.com/byteaether/ulid/blob/main/_autodocs/quick-reference.md Instantiates a PseudoRandomProvider for generating ULIDs. This is faster than the cryptographic provider and is the default for IncrementRandomSource. ```csharp // Pseudo-random (faster, default for IncrementRandomSource) var pseudo = new PseudoRandomProvider(); ``` -------------------------------- ### Configure Strict Monotonic Increment Source: https://github.com/byteaether/ulid/blob/main/_autodocs/api-reference/generation-options.md Use MonotonicityOptions.MonotonicIncrement for strict sequential ordering within the same millisecond. ```csharp var strict = new Ulid.GenerationOptions { Monotonicity = Ulid.GenerationOptions.MonotonicityOptions.MonotonicIncrement }; ``` -------------------------------- ### Random Property Source: https://github.com/byteaether/ulid/blob/main/_autodocs/api-reference/ulid-struct.md Gets the random component (last 10 bytes) as a byte span. This property provides direct access to the random part of the ULID in its raw byte format. ```APIDOC ## Random Property ### Description Gets the random component (last 10 bytes) as a byte span. ### Returns A 10-byte `ReadOnlySpan` containing the random portion. ### Example ```csharp var ulid = Ulid.New(); var randomBytes = ulid.Random; ``` ``` -------------------------------- ### TimeBytes Property Source: https://github.com/byteaether/ulid/blob/main/_autodocs/api-reference/ulid-struct.md Gets the raw timestamp component (first 6 bytes) as a byte span. This provides direct access to the time part of the ULID in its raw byte format. ```APIDOC ## TimeBytes Property ### Description Gets the raw timestamp component (first 6 bytes) as a byte span. ### Returns A 6-byte `ReadOnlySpan` containing the timestamp. ``` -------------------------------- ### Configure Increment Random Source with PseudoRandomProvider Source: https://github.com/byteaether/ulid/blob/main/_autodocs/api-reference/generation-options.md Set the IncrementRandomSource to PseudoRandomProvider for monotonic increments. This is used when Monotonicity is set to a MonotonicRandom*Byte option. ```csharp // Configure both sources var options = new Ulid.GenerationOptions { Monotonicity = Ulid.GenerationOptions.MonotonicityOptions.MonotonicRandom2Byte, InitialRandomSource = new CryptographicallySecureRandomProvider(), IncrementRandomSource = new PseudoRandomProvider() }; var ulid = Ulid.New(options); ``` -------------------------------- ### Time-Based Range Query with ULIDs Source: https://github.com/byteaether/ulid/blob/main/_autodocs/quick-reference.md Perform range queries on entities using ULIDs by leveraging their time-based nature. Requires ULID instances representing start and end dates. ```csharp // Time-based range query var minId = Ulid.MinAt(startDate); var maxId = Ulid.MaxAt(endDate); var items = db.Items.Where(i => i.Id >= minId && i.Id <= maxId); ``` -------------------------------- ### Create ULID with Generation Options Source: https://github.com/byteaether/ulid/blob/main/_autodocs/MANIFEST.md Creates a new ULID with specified generation options, allowing for customization of monotonicity and random sources. ```csharp var ulid = Ulid.New(new GenerationOptions { Monotonicity = MonotonicityOptions.MonotonicRandom4Byte }); ``` -------------------------------- ### Recommended Default Generation Options with Secure Provider Source: https://github.com/byteaether/ulid/blob/main/_autodocs/api-reference/random-provider.md Configures the default ULID generation options to use CryptographicallySecureRandomProvider for the initial random source and PseudoRandomProvider for increments. This is recommended for applications requiring strong security. ```csharp using ByteAether.Ulid; // For applications requiring strong security Ulid.DefaultGenerationOptions = new Ulid.GenerationOptions { InitialRandomSource = new CryptographicallySecureRandomProvider(), IncrementRandomSource = new PseudoRandomProvider() // Acceptable for increments }; ``` -------------------------------- ### Configuring Default Generation Options with PseudoRandomProvider Source: https://github.com/byteaether/ulid/blob/main/_autodocs/api-reference/random-provider.md Shows how to set the default generation options for Ulid to use PseudoRandomProvider for increments, alongside a CryptographicallySecureRandomProvider for initial secure generation. This is recommended for performance-critical applications. ```csharp using ByteAether.Ulid; // For performance-critical applications Ulid.DefaultGenerationOptions = new Ulid.GenerationOptions { Monotonicity = Ulid.GenerationOptions.MonotonicityOptions.MonotonicRandom2Byte, InitialRandomSource = new CryptographicallySecureRandomProvider(), // Secure generation IncrementRandomSource = new PseudoRandomProvider() // Fast increments }; ``` -------------------------------- ### Pseudo-Random Number Generator Source: https://github.com/byteaether/ulid/blob/main/_autodocs/types.md Implements IRandomProvider using System.Random for fast, non-cryptographically secure random byte generation. It uses Random.Shared on .NET 6.0+ and a static instance on older frameworks, making it thread-safe and suitable for incrementing random sources. ```csharp public readonly struct PseudoRandomProvider : IRandomProvider { #if NET6_0_OR_GREATER private static Random _rng => Random.Shared; #else private static readonly Random _rng = new(); #endif public void GetBytes(Span buffer) => _rng.NextBytes(buffer); } ``` -------------------------------- ### Convert ULID to Other Formats Source: https://github.com/byteaether/ulid/blob/main/_autodocs/quick-reference.md Convert a ULID object to its string, byte array, or GUID representation. ReadOnlySpan can be used for efficient byte access without allocation. Implicit operators simplify conversions. ```csharp var ulid = Ulid.New(); // To string string str = ulid.ToString(); ``` ```csharp // To byte array byte[] bytes = ulid.ToByteArray(); ``` ```csharp // To byte span (no allocation) ReadOnlySpan span = ulid.AsByteSpan(); ``` ```csharp // To GUID Guid guid = ulid.ToGuid(); ``` ```csharp // Implicit operators string str = ulid; // Implicit to string Guid guid = ulid; // Implicit to Guid Ulid ulid2 = guid; // Implicit from Guid ``` -------------------------------- ### TryFormat(Span, out int, ReadOnlySpan, IFormatProvider?) Source: https://github.com/byteaether/ulid/blob/main/_autodocs/api-reference/ulid-struct.md Attempts to format the ULID as UTF-8 bytes into the provided byte span. ```APIDOC ## TryFormat(Span, out int, ReadOnlySpan, IFormatProvider?) ### Description Attempts to format the ULID as UTF-8 bytes into the provided byte span. ### Parameters #### Path Parameters - **destination** (Span) - Required - The span to write UTF-8 bytes into (must be at least 26) - **bytesWritten** (int) - Out - Number of bytes written - **format** (ReadOnlySpan) - Required - Ignored - **provider** (IFormatProvider?) - Optional - Ignored ### Returns `true` if the span was large enough; `false` otherwise. ### Example ```csharp var ulid = Ulid.New(); Span buffer = stackalloc byte[26]; if (ulid.TryFormat(buffer, out var written)) { // Process the byte span } ``` ``` -------------------------------- ### Override Default ULID Generation Options Source: https://github.com/byteaether/ulid/blob/main/_autodocs/configuration.md Demonstrates how to pass a GenerationOptions instance to Ulid.New() to override defaults for a single call. The second call uses the system's default options. ```csharp var options = new Ulid.GenerationOptions { Monotonicity = Ulid.GenerationOptions.MonotonicityOptions.NonMonotonic }; var ulid = Ulid.New(options); // Uses specified options var ulid2 = Ulid.New(); // Uses DefaultGenerationOptions ``` -------------------------------- ### Migrate ULID column in SQL Server Source: https://github.com/byteaether/ulid/blob/main/_autodocs/integration-guide.md This SQL script demonstrates how to add a new BINARY(16) column, copy GUID data, drop the old column, and rename the new column for database migration. ```sql -- SQL Server example ALTER TABLE Entities ADD NewId BINARY(16); -- Copy GUID data as-is (same 16 bytes) UPDATE Entities SET NewId = CAST(OldGuidId AS BINARY(16)); -- Drop old column and rename ALTER TABLE Entities DROP COLUMN OldGuidId; EXEC sp_rename 'Entities.NewId', 'Id'; ```