.NET 7

Rainer Stropek | @rstropek

.NET 7 Status

  • STS version
    • .NET 6 was LTS
  • Currently in RC

Introduction

Rainer Stropek

  • Passionate software developers for 25+ years
    ย 
  • Microsoft MVP, Regional Director
    ย 
  • Trainer, Teacher, Mentor
    ย 
  • ๐Ÿ’• community

It is fast
๐ŸŽ๏ธ

Docker

Base Images

Tagging

  • .NET Version
    • latest (stable)
    • Major (e.g. 6.0, 7.0)
    • Minor (e.g. 6.0.401, 7.0.100-rc.1)
  • OS Type & Version
    • Debian (e.g. 6.0-bullseye-slim)
    • Alpine
    • Ubuntu
    • Windows Nano Server
    • Windows Server Core
  • Processor Architecture
    • amd64 (e.g. 6.0-bullseye-slim-amd64)
    • arm64, arm32

Multi-Stage Build

# https://hub.docker.com/_/microsoft-dotnet
FROM mcr.microsoft.com/dotnet/sdk:7.0 AS build
WORKDIR /source

# copy csproj and restore as distinct layers
COPY aspnetapp/*.csproj .
RUN dotnet restore --use-current-runtime  

# copy everything else and build app
COPY aspnetapp/. .
RUN dotnet publish -c Release -o /app --use-current-runtime \
	--self-contained false --no-restore

# final stage/image
FROM mcr.microsoft.com/dotnet/aspnet:7.0
WORKDIR /app
COPY --from=build /app .
ENTRYPOINT ["dotnet", "aspnetapp.dll"]

Build

Runtime

Challenge

  • Non-trivial solutions consist of multiple projects
    • Each project needs to be dockerized
  • Where to put Dockerfiles?
    • In project folder โžก๏ธ solution-level config files missing in build context
    • In solution folder โžก๏ธ Dockerfiles are not in the project they belong to
    • Specify complicated parameters during docker build
  • Example:
    • Centralized Package Mangement ๐Ÿ”—, new in .NET 6/7 (demo)

Solution

  • Microsoft.NET.Build.Containers ๐Ÿ”—
    ย 
  • Container image for ASP.NET Core web becomes a publish target
    • No need to manually write and maintain Dockerfiles
  • Configurable through .NET config files
    • Meaningful container settings derived from proj settings (e.g. base image)
    • Some limitations apply, see docs ๐Ÿ”—ย and blog ๐Ÿ”—
  • Uses new .NET 7 features for handling TAR files/streams ๐Ÿ”—๐Ÿ”—ย  internally

Demo
Time!

Demo

# SLN folder is the current folder

dotnet publish --os linux --arch x64 -p:PublishProfile=DefaultContainer

docker images dotnet7api
docker tag <image-id> rstropek/dotnet7api
docker run -it --rm --name dotnet7api rstropek/dotnet7api

"Distroless" Images

  • Ubuntu containers with ASP.NET Core apps are big
    • Only solution until now: Alpine (supported by .NET)
  • Everything you have in your container can be attacked
    ย 
  • Solution approach: "Distroless" images
    • Slimmed down Linux distro plus all the app really needs
    • No need for e.g. grep, cat, bash, etc.
    • No root user
      ย 
  • New: .NET in Chiseled Ubuntu Containers

.NET in Chiseled Ubuntu Containers

  • ~50% smaller than regular Ubuntu
  • Alpine is still an option
    • Chiseled Ubuntu closer to Ubuntu dev env (e.g. no musl)
  • No chiseled images for SDK
  • Enhanced security
    • Non-root images
    • Secure supply chain between Canonical and MS
  • Commercial support by Ubuntu
    ย 
  • And BTW: .NET 6 is now available in Ubuntu with a single
    apt install command ๐Ÿ”—๐Ÿ”—
    • sudo apt install dotnet6

Demo
Time!

Demo

# Based on previous demo

docker images dotnet7api
# Note size

# Add to .csproj:
# <ContainerBaseImage>mcr.microsoft.com/dotnet/nightly/aspnet:7.0-jammy-chiseled</ContainerBaseImage>

# Rebuild
dotnet publish --os linux --arch x64 -p:PublishProfile=DefaultContainer

docker images dotnet7api
# Note size difference

docker run -it --rm --name dotnet7api <image-id>

ref fields in
ref structs

Quick Recap: Ref Structs, Spans

  • Ref structs are allocated on the stack and cannot escape to the heap
  • Prominent examples of ref structs:
    • Span<T>
    • ReadOnlySpan<T>
  • Quick recap on Spans ๐Ÿ”—

ref structs can now contain ref fields

var v = 42;
var c = new Container<int>(ref v);
Console.WriteLine(c.Value);

// Change v. As c has a reference to v, c.Value changes, too.
v = 43;
Console.WriteLine(c.Value);

ref struct Container<T>
{
    ref T value;

    public Container(ref T value)
    {
        this.value = ref value;
    }

    public T Value
    {
        get => this.value;
        set => this.value = value;
    }

    public void ChangeRef(ref T value) => this.value = ref value;
}

Demo
Time!

JSON Enhancements

Various JSON Enhancements

  • System.Text.Json now supports serializing and deserializing polymorphic type hierarchies ๐Ÿ”—
  • JSON Source Generation now supports...

JSON Contract Customization

  • Sometimes you want to influence serialization without changing the type
    • E.g. external library, simply doesn't fit
  • Now you can customize the JSON contract ๐Ÿ”—

Demo
Time!

Regex Enhancements

RegEx Enhancements

  • Regex became faster โšก
  • Opt-out from backtracking with new RegexOptions.NonBacktrackingย option
  • New StringSyntaxย attribute to enable editor support for custom methods
  • RegEx Generator ๐Ÿค˜
    • Including analyzer and fixer to generate GeneratedRegex

Demo
Time!

Various Small
Improvements

Linq Enhancements

var data = new[] { 2, 1, 3 };

var sorted = data.Order();
// instead of
// var sorted = data.OrderBy(e => e);

var sortedDesc = data.OrderByDescending();
// instead of
// var sortedDesc = data.OrderByDescending(e => e);

LibraryImport

  • LibraryImportย ๐Ÿ”— is a drop-in replacement for DllImport
    • Generates marshalling code at compile-time
    • Analyzer + Code Fix available to turn DllImport into LibraryImport ๐Ÿ”—

Demo
Time!

System.IO.Stream Enhancements

  • Tedious to read an exact number of bytes using Stream.Read ๐Ÿ”—
  • New methods on System.IO.Stream
    • ReadExactly
    • ReadAtLeast
  • Throw exception if stream ends unexpectedly

Nullable Annotations

  • In all recent .NET versions, Microsoft and the community annotated additional libraries for nullablity
  • In .NET 7: Microsoft.Extensions.*
  • Want to learn more about nullablity?

Trimming,
Native AOT

ย 

Trimming

  • .NET 6: Types in the user project are fully preserved
    • Only libs with <IsTrimmable>true</IsTrimmable>ย were trimmed
  • .NET 7: All assemblies are trimmed by default
    • If published with trimming or if using NativeAOT
    • TrimMode fullย is now the default
    • Use TrimMode partialย to revert to .NET 6 trimming behavior
  • Problem: Types that are accessed using Reflection at runtime
    • E.g. JSON deserialization with System.Text.Json
  • โ€‹Solutions
    • Configure trimming ๐Ÿ”—
    • Avoid reflection, prefer Code Generators

Quick Recap: Code Generators

  • Runs during compilation
  • Inspects your program (using Roslyn)
  • Produces additional files that are compiled together with your app

Demo
Time!

Native AOT

  • .NET has multiple AOT flavors
    • crossgen2/ReadyToRun for client and server
    • Mono AOT for mobile and WASM
  • New in .NET 7: Native AOT
    • Targets console apps and native libraries ๐Ÿ”—
    • <PublishAot>true</PublishAot>
  • Limitations apply
    • No code generation at runtime
    • No loading of .NET assemblies at runtime
  • Prepare for Native AOT: Make sure your libs/apps ๐Ÿ”— can be trimmed
    • Code generators!

.NET 7 ๐Ÿค˜

Rainer Stropek | @rstropek