Base64Url

In .NET, it hasn't been possible to create URL-safe Base64 strings without using additional libraries. Since the Base64 standard allows the use of + and / characters, you could end up in a mess if you try to send Base64 in a query string using this code:

string s = Convert.ToBase64String(bytes);

Now, with .NET 9, you can use Base64Url, which will return a URL-safe Base64 string:

string s = Base64Url.EncodeToString(bytes);

OrderedDictionary<TKey, TValue>

For a long time, .NET has had OrderedDictionary, but it was only supported as an object, with no generic support.

OrderedDictionary myOrderedDictionary = new OrderedDictionary(); myOrderedDictionary.Add("testKey1", 1);

Now, we can finally declare OrderedDictionary using generics for the key and value:

OrderedDictionary<string, int> d = new(); d.Add("a", 1);

LINQ New Methods: CountBy and AggregateBy

CountBy and AggregateBy make it possible to aggregate without chaining a combination of the GroupBy, Select, Count, and Aggregate methods. Before .NET 9, you had to group elements by a key and then count or aggregate the occurrences of each group.

CountBy counts by each key. The following example finds the word that occurs most frequently in a text string:

string sourceText = """ Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed non risus. Suspendisse lectus tortor, dignissim sit amet, adipiscing nec, ultricies sed, dolor. Cras elementum ultrices amet diam. """; // Find the most frequent word in the text. KeyValuePair<string, int> mostFrequentWord = sourceText .Split(new char[] { ' ', '.', ',' }, StringSplitOptions.RemoveEmptyEntries) .Select(word => word.ToLowerInvariant()) .CountBy(word => word) .MaxBy(pair => pair.Value); Console.WriteLine(mostFrequentWord.Key); // amet

The following example shows how you can use AggregateBy to calculate the total scores by key. Before AggregateBy, you would typically use GroupBy along with Aggregate to achieve this task:

(string id, int score)[] data = { ("0", 42), ("1", 5), ("2", 4), ("1", 10), ("0", 25), }; var aggregatedData = data.AggregateBy( keySelector: entry => entry.id, seed: 0, (totalScore, curr) => totalScore + curr.score ); foreach (var item in aggregatedData) { Console.WriteLine(item); } // (0, 67) // (1, 15) // (2, 4)

JsonSchemaExporter

Using System.Text.Json, you can now export a [https://json-schema.org/](JSON schema) that describes the shape of a .NET type, which is great for OpenAPI.

The following code generates a JSON schema from a type:

Console.WriteLine(JsonSchemaExporter.GetJsonSchemaAsNode(JsonSerializerOptions.Default, typeof(Book)));

The type is defined as follows:

public class Book { public string Title { get; set; } public string? Author { get; set; } public int PublishYear { get; set; } }

The generated schema is:

{ "type": [ "object", "null" ], "properties": { "Title": { "type": "string" }, "Author": { "type": [ "string", "null" ] }, "PublishYear": { "type": "integer" } } }

Built-in Support for OpenAPI Document Generation

In .NET 9, it is now possible to create OpenAPI documents without any third-party packages. ASP.NET Core now provides built-in support for generating OpenAPI documents representing controller-based or minimal APIs via the Microsoft.AspNetCore.OpenApi package.

The following code highlights how to call:

  • AddOpenApi to register the required dependencies into the app's DI container.
  • MapOpenApi to register the required OpenAPI endpoints in the app's routes.
var builder = WebApplication.CreateBuilder(); 👇 builder.Services.AddOpenApi(); var app = builder.Build(); 👇 app.MapOpenApi(); app.MapGet("/hello/{name}", (string name) => $"Hello {name}!"); app.Run();

Install the Microsoft.AspNetCore.OpenApi package in the project using the following command:

dotnet add package Microsoft.AspNetCore.OpenApi --prerelease

Run the app and navigate to openapi/v1.json to view the generated OpenAPI document.

OpenAPI document


Some code examples are from Microsoft Learn.

Need help with an existing or new ASP.NET application? Reach out to us.