Saturday, 16 November 2024

Url encoding base 64 strings in .NET 9

This article shows new functionality how to url encode base 64 strings in .NET 9. In .NET 8 you would do multiple steps to url encode base 64 strings like this: Program.cs



using System.Buffers.Text;
using System.Net;
using System.Text;
using System.Text.Encodings.Web;

byte[] data = Encoding.UTF8.GetBytes("Hello there, how yall doin");
var base64 = Convert.ToBase64String(data);
var base64UrlEncoded = WebUtility.UrlEncode(base64);

Console.WriteLine(base64UrlEncoded);


We here first convert the string to a bytes in a byte array and then we base 64 encode the byte array into a Base64 string. Finally we url encode the string into a URL safe string. Let's see how simple this is in .NET 9 : Program.cs (v2)



using System.Buffers.Text;
using System.Net;
using System.Text;
using System.Text.Encodings.Web;

byte[] data = Encoding.UTF8.GetBytes("Hello there, how yall doin");
var base64UrlEncodedInNet9 = Base64Url.EncodeToString(data);

Console.WriteLine(base64UrlEncodedInNet9);


If we use ImplicitUsings here in the .csproj file the code above just becomes :

byte[] data = Encoding.UTF8.GetBytes("Hello there, how yall doin");
var base64UrlEncodedInNet9 = Base64Url.EncodeToString(data);
Console.WriteLine(base64UrlEncodedInNet9);

This shows we can skip the intermediate step where we first convert the bytes into a base64-string and then into a Url safe string and instead do a base-64 encoding and then an url encoding in one go. This way is more optimized, it is also possible here to use ReadOnlySpan (that works for both .NET 8 and .NET 9). Putting together we get:

using System.Buffers.Text;
using System.Net;
using System.Text;
using System.Text.Encodings.Web;

ReadOnlySpan data = Encoding.UTF8.GetBytes("Hello there, how yall doin");
var base64 = Convert.ToBase64String(data);
var base64UrlEncoded = WebUtility.UrlEncode(base64);

var base64UrlEncodedInNet9 = Base64Url.EncodeToString(data);

Console.WriteLine(base64UrlEncoded);
Console.WriteLine(base64UrlEncodedInNet9);

The output is the following :

SGVsbG8gdGhlcmUsIGhvdyB5YWxsIGRvaW4%3D
SGVsbG8gdGhlcmUsIGhvdyB5YWxsIGRvaW4

As we can see, the .NET 9 Base64.UrlEncode skips the the padding characters, so beware of that.



Note that by omitting the padding, it is necessary to pad the base 64 url encoded string if you want to decode it. Consider this helpful extension method to add the necessary padding:


/// <summary>
/// Provides extension methods for Base64 encoding operations.
/// </summary>
public static class Base64Extensions
{
    /// <summary>
    /// Adds padding to a Base64 encoded string to ensure its length is a multiple of 4.
    /// </summary>
    /// <param name="base64">The Base64 encoded string without padding.</param>
    /// <param name="isUrlEncode">Set to true if this is URL encode, will add instead '%3D%' as padding at the end (0-2 such padding chars, same for '=').</param>
    /// <returns>The Base64 encoded string with padding added, or the original string if it is null or whitespace.</returns>
    public static string? AddPadding(this string base64, bool isUrlEncode = false)
    {
        string paddedBase64 = !string.IsNullOrWhiteSpace(base64) ? base64.PadRight(base64.Length + (4 - (base64.Length % 4)) % 4, '=') : base64;
        return !isUrlEncode ? paddedBase64 : paddedBase64?.Replace("=", "%3D");
    }    
}


We can now achieve the same output with this extension method :



using System.Buffers.Text;
using System.Net;
using System.Text;
using System.Text.Encodings.Web;

ReadOnlySpan data = Encoding.UTF8.GetBytes("Hello there, how yall doin");
var base64 = Convert.ToBase64String(data);
var base64UrlEncoded = WebUtility.UrlEncode(base64);

var base64UrlEncodedInNet9 = Base64Url.EncodeToString(data);

// Using the extension method to add padding
base64UrlEncodedInNet9 = base64UrlEncodedInNet9.AddPadding(isUrlEncode: true);

Console.WriteLine(base64UrlEncoded);
Console.WriteLine(base64UrlEncodedInNet9);


Finally, the output using the two different approaching pre .NET 9 and .NET 9 gives the same results:

SGVsbG8gdGhlcmUsIGhvdyB5YWxsIGRvaW4%3D
SGVsbG8gdGhlcmUsIGhvdyB5YWxsIGRvaW4%3D

No comments:

Post a Comment