.NET 6
Rainer Stropek | @rstropek
.NET 6 Status
- LTS version
- .NET 5 was not
- From now on π
- Every November a major version
- Every second major version will have LTS
Introduction
Rainer Stropek
- Passionate software developers for 25+ years
Β - Microsoft MVP, Regional Director
Β - Trainer, Teacher, Mentor
Β - π community
One
.NET
A little bit
of history...
A little bit of history...
- .NET Framework at its beginnings
- Windows only
- Closed source
- Mono appeared
- Separate implementation
- Open-source, cross platform
- .NET Core
- Lean, modern .NET
- Open-source, cross platform
- Grew bigger over time
- Back to one .NET
.NET Standard
.NET Unification Vision
.NET 6
- Plattform support π
- Nearly the same as .NET 5
- New: macOS Arm64
- No big migration hurdles to be expected
- LTS
- Patches for three years
- No new features/APIs to .NET Framework and .NET Core
- No need to run away
- Have a plan for switching to the "new world"
Modular SDK
- .NET Core: Monolithik SDK
- .NET >= 5: Modular SDK
- .NET 6: dotnet workloadΒ extended
# list workloads available to install
dotnet workload search
# installs a workload
dotnet workload install
# lists installed workloads
dotnet workload list
# re-install all workloads youβve previously installed
dotnet workload repair
# update workload
dotnet workload update
# remove the specified workload if you no longer it
dotnet workload uninstall
Crossgen2
aka ReadyToRun format
ReadyToRun File Format
- Goal: Binary file format for better startup performance
- Form of ahead of time compilation (AOT)
- Not full native AOT
- "Run anywhere" code ranging from full JIT to full AOT (flexible)
- Re-JITted after start for better steady-state performance
- Drawbacks
- Larger file sizes
- Specific for target architecture (e.g. Win x64)
- Publish as ReadyToRun π
- In .NET 6: Crossgen2 replaces Crossgen
- CLI (dotnet publish ... -p:PublishReadyToRun=true)
- .csproj (<PublishReadyToRun>true</PublishReadyToRun>)
Demo
Time!
Crossgen2 Demo
Measure startup time of ASP.NET Core Web API with EF Core (in-memory provider) with and without ReadyToRun.
Much better startup time, more than double the file size
Without ReadyToRun:
With ReadyToRun:
Sync-over-async Improvements
Sync-over-async
- Pattern: Use async only in library, sync in API surface
- Frequently found in legacy apps (e.g. modern lib, rather old UI)
// Note: Sync API, no async/await, no Task
static int DoSomethingSlow()
{
// Note async in the background
var result = Task.Run(async () =>
{
// Simulate work that takes 2 seconds (e.g. DB or net access)
await Task.Delay(TimeSpan.FromSeconds(2));
return 42;
}).Result; // Note the blocking access to the Result property here
return result;
}
Sync-over-async Improvements
- Thread injection happens faster
- If thread pool is busy just waiting for sync-over-async
- Consequence: Better performance
- Drawbacks
- Larger thread pool
- Uses more memory
- So?
- Prefer modern async/await/Task programming model
- Less problems when modernizing legacy apps
Demo
Time!
JSON Serialization
Code Generator
What's a Code Generator?
- Runs during compilation
- Inspects your program (using Roslyn)
- Produces additional files that are compiled together with your app
Why Code Generators?
- Currently:
- Runtime reflection, e.g. ASP.NET Core DI (impacts performance)
- Change IL after compilation ("IL weaving")
- MSBuild tasks
- In the future:
- Analyse code at compile time and generate code
- Similar to Google's Wire DI framework (Go)
- .NET examples: JSON SerializationΒ (new in .NET 6), Logging Source Generation (net in .NET 6), ASP.NET Core Razor (new in .NET 6), MvvmGenΒ (community)
- Less reflection leads to...
- ...better performance
- ...smaller apps because AoT compiler (linker) can remove unused parts of your code
- Analyse code at compile time and generate code
Demo
Time!
| Method | Mean | Error | StdDev |
|----------------------------- |---------:|----------:|---------:|
| DeserializeJsonBlob | 3.875 ms | 0.8436 ms | 2.487 ms |
| DeserializeJsonBlobGenerated | 3.748 ms | 0.6969 ms | 2.055 ms |
| Method | Mean | Error | StdDev |
|----------------------------- |---------:|----------:|----------:|
| DeserializeJsonBlob | 2.694 ms | 0.0280 ms | 0.0185 ms |
| DeserializeJsonBlobGenerated | 2.773 ms | 0.0193 ms | 0.0128 ms |
Cold Start Run Strategy
Execution Without Cold Starts
~3.3% improvement
No improvement
Source Generators Behind the Scenes
- Generator
-
Goal: Learn how a source generator works
- Build it
- Running it in compiler and VS2022
- Offer Generate attribute for partial methods
- Generates a configurable amount of dummy code
- No meaning, just generating lots of meaningless C#
- Kind of c-sharp-ipsum π
-
Goal: Learn how a source generator works
- Generate code in a library
- Makes lib pretty large
- Generate console app using the library
- Goal: Learn how assembly trimming works
- Build self-contained without/with assembly trimming
- Try dynamic calls with assembly trimmingΒ
Source Generators Behind the Scenes
[Generator]
public class DummyGenerator : ISourceGenerator
{
/// <summary>
/// Visitor class that finds methods to generate
/// </summary>
class SyntaxReceiver : ISyntaxContextReceiver
{
...
}
public void Initialize(GeneratorInitializationContext context)
{
// Register the attribute source
context.RegisterForPostInitialization((i) => i.AddSource("GenerateAttribute", attributeText));
// Register a syntax receiver that will be created for each generation pass
context.RegisterForSyntaxNotifications(() => new SyntaxReceiver());
}
public void Execute(GeneratorExecutionContext context)
{
...
// Create string builder for source generation
var sourceBuilder = new StringBuilder();
... // Generate code
// Inject the created source into the users compilation
context.AddSource("dummy_generated.cs", SourceText.From(sourceBuilder.ToString(), Encoding.UTF8));
}
}
Source Generators Behind the Scenes
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<Nullable>enable</Nullable>
<IsTrimmable>true</IsTrimmable>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\DummyCodeGenerator\DummyCodeGenerator.csproj"
OutputItemType="Analyzer" ReferenceOutputAssembly="false"/>
</ItemGroup>
</Project>
Trimmed Assemblies
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net6.0</TargetFramework>
<!--
Note that <TrimMode>link</TrimMode> is default in .NET 6.
See https://docs.microsoft.com/en-us/dotnet/core/deploying/trimming-options#trimming-granularity
-->
<!-- Note new support for compressing single-file bundles (expanded in-memory) -->
<EnableCompressionInSingleFile>true</EnableCompressionInSingleFile>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\LinkerLibrary\LinkerLibrary.csproj" />
</ItemGroup>
<!--
You can prevent trimming of assemblies. There are many additional options for trimming
Read more about them at https://docs.microsoft.com/en-us/dotnet/core/deploying/trim-self-contained#prevent-assemblies-from-being-trimmed
-->
<ItemGroup>
<TrimmerRootAssembly Include="System.Text.Json" />
</ItemGroup>
</Project>
Demo
Time!
JSON Serialization Enhancements
Yet Additional JSON APIs??
- Support for streaming through IAsyncEnumerableΒ π
- Significant performance improvement in some scenarios
- JSON Writeable DOM API π
- For scenarios in which POCOs are not an option
- Data structures not known at runtime
- Potential for perf optimization
- Deserialize only a subtree of large JSON in POCOs
- Manipulate a subtree without deserializing everything into POCOs
- For scenarios in which POCOs are not an option
Demo
Time!
Linq Enhancements
Community π€ππ
Demo
Time!
DateOnly π
TimeOnly β°
finally π₯³π
Demo
Time!
Additional Date/Time-Related Enhancements
Docker
Demo
Time!
What else?
.NET 6 π€
Rainer Stropek | @rstropek
.NET 6 Intro
By Rainer Stropek
.NET 6 Intro
- 1,123