Favorite Build 2024 Sessions
06/02/2024
These are my favorite sessions from Build 2024:
These are my favorite sessions from Build 2024:
In this post I explore how ASP.NET Core works together with the source generated JSON serializer. In .NET 8 the streaming JSON serialization can be enabled to use serialization-optimization mode with ASP.NET Core. However, using the default settings does not enable this fast-path. In this post I will explore how to enable the fast-path serialization by exploring the inner workings of JsonTypeInfo.cs
. For this post I use .NET 8 with the corresponding ASP.NET Core release.
The .NET 8 runtime comes with three built-in JSON serializer modes:
Reflection
Source generation (Metadata-based mode)
Source generation (Serialization-optimization mode)
Reflection mode is the default one. This mode is used when someone invokes JsonSerializer.(De)SerializeAsync
without additional arguments passed. Source Generation (Metadata-based mode) as the name suggests generates source code at compile time that contains the metadata that the Reflection would need to discover during its first invocation. This mode helps to enable JSON serialization in environments where reflection otherwise would not be possible, for example in case of AOT published applications. Source generation (Serialization-optimization mode) also generates code at compile time, but besides the metadata it also uses a generated fast-path method when serializing objects.
.NET 8 introduced a new garbage collection feature: Dynamic Adaptation To Application Sizes or DATAS. The inner workings of it are detailed in this post.
This feature tunes the GC to adjust the number of heaps and execute compacting garbage collections more often to have a smaller overall heap size. The result should be a heap size that more closely resembles the actual amount of memory that the application uses.
This feature is great for memory constrained environments or with uneven loads, where memory may be reclaimed between the loads.
In this post I will enable DATAS on my test server application and test client side application to observe the differences in the memory utilization.
I have recently realized that implementing the ISpanFormattable
interface enables a type to participate in string interpolation feature of C# in a more efficient way. This realization made me curious how much more efficient it is to implement the corresponding public bool TryFormat(Span<char> destination, out int charsWritten, ReadOnlySpan<char> format = default, IFormatProvider? provider = default)
method to the standard ToString()
. In this blog post I use .NET8 and C# 12.
Implementing ISpanFormattable is not automatically justified for all types, but ones that participate in frequent serialization, such as string interpolation. One can search the types that implement this interface, and it contains most of the primitive and value types (int
, Guid
, DateTime
, etc).
Fortunately I just have one such type on hand that lends itself for the investigation. In a previous blog post, I iterated through a couple of different implementation of FractionalDouble
type.
While understanding the details of the FractionalDouble
format is less relevant for this post, here is a quick summary:
In a recent PR I have optimized parsing known header values, such CacheControlHeaderValue
or MediaTypeHeaderValue
.
The original code used a Dictionary<>
to look up a Func<string, T?>
parsing method, with a string input and a generic type T
return type. In this blog post I will summarize the pros and cons of different alternatives that were considered as part of the optimization.
This dictionary contains known Func<string, T?>
parsers. These known parsers do not change at runtime. Using a FrozenDictionary would bring performance benefits for the lookup operations. However, freezing the dictionary itself takes time at runtime, because when freezing the new dictionary builds an efficient lookup. This is usually worth the trade-off as freezing only needs to happen once during the lifetime of the application. However, in this case all the contents of this dictionary are known at compile time.