GUIDs are commonly used as keys in a database. If you want to create a URL pointing to a specific record, you may want to include the GUID in the URL. The simplest approach is to use ToString("N"), which returns the GUID as 00000000000000000000000000000000. However, this format is inefficient. You can use ToBase64String to get a more compact representation, but standard Base64 is not URL-safe because it may contain / characters. This means you need to escape the value using Uri.EscapeDataString, and the result also includes padding characters (=) at the end.
A more compact approach is to use the WebEncoders.Base64UrlEncode method. This method converts a byte array to a Base64 string that is safe for use in URLs, as described in the Base64Url Encoding specification. This encoding uses the URL-safe characters - and _ instead of + and /, and omits the padding characters (=) at the end.
Here are some examples to show the difference between the formatting methods:
| Format | Length | Sample data |
|---|
| Guid.ToString() | 36 | 00000000-0000-0000-0000-000000000000 |
| Guid.ToString("N") | 32 | 00000000000000000000000000000000 |
| Convert.ToBase64String | 24 | 0000000000000000000000== |
| WebEncoders.Base64UrlEncode | 22 | 0000000000000000000000 |
Here's the code to encode and decode a GUID as a Base64Url string:
C#
static string EncodeGuid(Guid guid)
{
Span<byte> bytes = stackalloc byte[16];
guid.TryWriteBytes(bytes);
return Microsoft.AspNetCore.WebUtilities.WebEncoders.Base64UrlEncode(bytes);
}
static Guid DecodeGuid(string guid)
{
return new Guid(WebEncoders.Base64UrlDecode(str));
}
#ASP.NET Core model binding
To use shorter GUIDs in an ASP.NET Core application, you can create a custom struct that wraps a GUID and define custom converters for the ASP.NET Core model binder and JSON serializer.
C#
[ApiController]
[Route("[controller]")]
public class SampleController : ControllerBase
{
[HttpGet("{id}")]
public ShortGuid Get(ShortGuid id) => id;
[HttpGet]
public IEnumerable<ShortGuid> Get()
{
for (int i = 0; i < 10; i++)
yield return Guid.NewGuid();
}
}
C#
[TypeConverter(typeof(ShortGuidTypeConverter))]
[JsonConverter(typeof(ShortGuidJsonConverter))]
public readonly struct ShortGuid
{
private readonly Guid _value;
public ShortGuid(Guid value) => _value = value;
public static implicit operator Guid(ShortGuid shortGuid) => shortGuid._value;
public static implicit operator ShortGuid(Guid guid) => new(guid);
public static ShortGuid Parse(string input) => new Guid(WebEncoders.Base64UrlDecode(input));
public override string ToString()
{
Span<byte> bytes = stackalloc byte[16];
_value.TryWriteBytes(bytes);
return WebEncoders.Base64UrlEncode(bytes);
}
private sealed class ShortGuidTypeConverter : TypeConverter
{
public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
=> sourceType == typeof(string);
public override object? ConvertFrom(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value)
=> value is string str ? Parse(str) : null;
public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
=> destinationType == typeof(string);
public override object ConvertTo(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value, Type destinationType)
=> ((ShortGuid)value).ToString();
}
private sealed class ShortGuidJsonConverter : JsonConverter<ShortGuid>
{
public override ShortGuid Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
var str = reader.GetString();
if (str != null)
return Parse(str);
return default;
}
public override void Write(Utf8JsonWriter writer, ShortGuid value, JsonSerializerOptions options)
=> writer.WriteStringValue(value.ToString());
}
}
Do you have a question or a suggestion about this post? Contact me!