Announcing .NET 6 Preview 5

Richard Lander

Richard

We are thrilled to release .NET 6 Preview 5. We’re now in the second-half of the .NET 6 release, and starting to see significant features coming together. A great example is .NET SDK Workloads, which is the foundation of our .NET unification vision and enables supporting more application types. Like other features, it is coming together to provide a compelling end-to-end user experience.

You can download .NET 6 Preview 5 for Linux, macOS, and Windows.

See the ASP.NET CoreEF Core, and .NET MAUI posts for more detail on what’s new for web, data access, and cross-platform UI scenarios.

Visual Studio 2022 Preview 1 is also releasing today and .NET 6 Preview 5 is included in that release. .NET 6 has also been tested with Visual Studio 16.11 and Visual Studio for Mac 8.9. We recommend you use those builds if you want to try .NET 6 with Visual Studio.

Check out the new conversations posts for in-depth engineer-to-engineer discussions of the latest .NET features.

.NET SDK: Optional Workload improvements

SDK workloads is a new .NET SDK feature that enables us to add support for new application types — like mobile and WebAssembly — without increasing the size of the SDK.

The workloads feature has been updated to include list and update verbs. These new capabilities provide a sense of the expected final experience. You’ll be able to quickly establish your preferred environment with a few simple commands and to keep it up-to-date over time.

  • dotnet workload list will tell you which workloads you have installed.
  • dotnet workload update will update all installed workloads to the newest available version.

The update verb queries nuget.org for updated workload manifests, updates local manifests, downloads new versions of the installed workloads, and then removes all old versions of a workload. This is analogous to apt update and apt upgrade -y (used on Debian-based Linux distros).

The dotnet workload commands operate in the context of the given SDK. Imagine you have both .NET 6 and .NET 7 installed. If you use both, the workloads commands will provide different results since the workloads will be different (at least different versions of the same workloads).

As you can see, the workloads feature is essentially a package manager for the .NET SDK. Workloads were first introduced in the .NET 6 preview 4 release.

.NET SDK: NuGet Package Validation

Package Validation tooling will enable NuGet library developers to validate that their packages are consistent and well-formed.

This includes:

  • Validate that there are no breaking changes across versions.
  • Validate that the package has the same set of publics APIs for all runtime-specific implementations.
  • Determine any target-framework- or runtime- applicability gaps.

This tool is available via the Microsoft.DotNet.PackageValidation.

A post on this tool will soon be available.

.NET SDK: more Roslyn Analyzers

In .NET 5, we shipped approximately 250 analyzers with the .NET SDK. Many of them already existed but were shipped out-of-band as NuGet packages. We’re adding more analyzers for .NET 6.

By default most of the new analyzers are enabled at Info level. You can enable these analyzers at Warning level by configuring the analysis mode like this: <AnalysisMode>AllEnabledByDefault</AnalysisMode>.

We published the set of analyzers we wanted for .NET 6 (plus some extras) and then made most of them up-for-grabs.

Credit to Newell Clark and Meik Tranel for the following implementations, included in Preview 5. Note that the community has contributed other implementations in previous previews.

Contributor Issue Title
Newell Clark dotnet/runtime #33777 Use span-based string.Concat
Newell Clark dotnet/runtime #33784 Prefer string.AsSpan() over string.Substring() when parsing
Newell Clark dotnet/runtime #33789 Override Stream.ReadAsync/WriteAsync
Newell Clark dotnet/runtime #35343 Replace Dictionary<,>.Keys.Contains with ContainsKey
Newell Clark dotnet/runtime #45552 Use String.Equals instead of String.Compare
Meik Tranel dotnet/runtime #47180 Use String.Contains(char) instead of String.Contains(String)

 

.NET SDK: Enable custom guards for Platform Compatibility Analyzer

The CA1416 Platform Compatibility analyzer already recognizes platform guards using the methods in OperatingSystem/RuntimeInformation, such as OperatingSystem.IsWindows and OperatingSystem.IsWindowsVersionAtLeast. However, the analyzer does not recognize any other guard possibilities like the platform check result cached in a field or property, or complex platform check logic is defined in a helper method.

For allowing custom guard possibilities we added new attributes SupportedOSPlatformGuard and UnsupportedOSPlatformGuard for annotating the custom guard members with the corresponding platform name and/or version. This annotation is recognized and respected by the Platform Compatibility analyzer’s flow analysis logic.

Usage

    [UnsupportedOSPlatformGuard("browser")] // The platform guard attribute
#if TARGET_BROWSER
    internal bool IsSupported => false;
#else
    internal bool IsSupported => true;
#endif

    [UnsupportedOSPlatform("browser")]
    void ApiNotSupportedOnBrowser() { }

    void M1()
    {
        ApiNotSupportedOnBrowser();  // Warns: This call site is reachable on all platforms.'ApiNotSupportedOnBrowser()' is unsupported on: 'browser'

        if (IsSupported)
        {
            ApiNotSupportedOnBrowser();  // Not warn
        }
    }

    [SupportedOSPlatform("Windows")]
    [SupportedOSPlatform("Linux")]
    void ApiOnlyWorkOnWindowsLinux() { }

    [SupportedOSPlatformGuard("Linux")]
    [SupportedOSPlatformGuard("Windows")]
    private readonly bool _isWindowOrLinux = OperatingSystem.IsLinux() || OperatingSystem.IsWindows();

    void M2()
    {
        ApiOnlyWorkOnWindowsLinux();  // This call site is reachable on all platforms.'ApiOnlyWorkOnWindowsLinux()' is only supported on: 'Linux', 'Windows'.

        if (_isWindowOrLinux)
        {
            ApiOnlyWorkOnWindowsLinux();  // Not warn
        }
    }
}

Windows Forms: default font

You can now set a default font for an application with Application.SetDefaultFont. The pattern you use is similar to setting high dpi or visual styles.

class Program
{
    [STAThread]
    static void Main()
    {
        Application.SetHighDpiMode(HighDpiMode.SystemAware);
        Application.EnableVisualStyles();
        Application.SetCompatibleTextRenderingDefault(false);

+       Application.SetDefaultFont(new Font(new FontFamily("Microsoft Sans Serif"), 8f));

        Application.Run(new Form1());
    }
}

Here are two examples after setting the default font (with different fonts).

Microsoft Sans Serif, 8pt:

image

Chiller, 12pt:

image

The default font was updated in .NET Core 3.0. However that change introduced a significant hurdle for some users migrating .NET Framework apps to .NET Core. This new change makes it straightforward to choose the desired font for an app and removes that migration hurdle.

Libraries: Dropping support for older frameworks

Dropping a framework from a package is a source breaking change. At the same time, continuing to build for all frameworks we ever shipped increases the complexity and size of a package. In the past, we’ve solved this issue by harvesting, which basically meant:

  1. We build only for current frameworks
  2. During build, we download the earlier version of the package and harvest the binaries for earlier frameworks we no longer build for

While this means that you can always update without worrying that we drop a framework it also means that you’ll never get any bug fixes or new features if you consume a harvested binary. In other words, harvested assets can’t be serviced which is now hidden because from your point of view you’re able to keep updating the package to a later version even thought you’re consuming the same old binary that we’re no longer updating.

Starting with .NET 6 Preview 5, we plan to no longer perform any form of harvesting to ensure that all assets we ship can be serviced. This means we’re dropping support for any framework that is older than these:

  • .NET Framework 4.6.1
  • .NET Core 3.1
  • .NET Standard 2.0

If you’re currently referencing an impacted package from an earlier framework, you’ll no longer be able to update the referenced package to a later version. Your choice is to either retarget your project to a later framework version or not updating the referenced package (which is generally not a huge take back because you’re already consuming a frozen binary anyways).

For more details, including the full list of impacted packages, see dotnet/announcement: Dropping older framework versions.

Libraries: Microsoft.Extensions

We’ve been improving Microsoft.Extensions APIs this release. In Preview 5, we’ve focused on hosting and dependency injection. In Preview 4, we added a compile-time source generator for logging.

Credit to Martin Björkström](https://github.com/bjorkstromm) for dotnet/runtime #51840 (AsyncServiceScope).

Hosting – ConfigureHostOptions API

We added a new ConfigureHostOptions API on IHostBuilder to make application setup simpler (e.g. configuring the shutdown timeout):

using HostBuilder host = new()
    .ConfigureHostOptions(o =>
    {
        o.ShutdownTimeout = TimeSpan.FromMinutes(10);
    })
    .Build();

host.Run();

Prior to Preview 5, configuring the host options was a bit more complicated:

using HostBuilder host = new()
    .ConfigureServices(services =>
    {
        services.Configure<HostOptions>(o =>
        {
            o.ShutdownTimeout = TimeSpan.FromMinutes(10);
        });
    })
    .Build();

host.Run();

Dependency Injection – CreateAsyncScope APIs

You might have noticed that disposal of a service provider will throw an InvalidOperationException when it happens to register an IAsyncDisposable service.

The new CreateAsyncScope API provides a straightforward solution, as you can see in the following example:

await using (var scope = provider.CreateAsyncScope())
{
    var foo = scope.ServiceProvider.GetRequiredService<Foo>();
}

The following example demonstrate the existing problem case and then the previous suggested workaround.

using System;
using System.Threading.Tasks;
using Microsoft.Extensions.DependencyInjection;

await using var provider = new ServiceCollection()
        .AddScoped<Foo>()
        .BuildServiceProvider();

// This using can throw InvalidOperationException
using (var scope = provider.CreateScope())
{
    var foo = scope.ServiceProvider.GetRequiredService<Foo>();
}

class Foo : IAsyncDisposable
{
    public ValueTask DisposeAsync() => default;
}

You can workaround the exception by casting the returned scope to IAsyncDisposable.

var scope = provider.CreateScope();
var foo = scope.ServiceProvider.GetRequiredService<Foo>();
await ((IAsyncDisposable)scope).DisposeAsync();

CreateAsyncScope solves this problem, enabling you to safely use the using statement.

Libraries: JsonSerializer Source generation

The backbone of nearly all .NET serializers is reflection. Reflection is a great capability for certain scenarios, but not as the basis of high-performance cloud-native applications (which typically (de)serialize and process a lot of JSON documents). Reflection is a problem for startup, memory usage, and assembly trimming.

The alternative to runtime reflection is compile-time source generation. Source generators generate C# source files that can be compiled as part of the library or application build. Generating source code at compile time can provide many benefits to .NET applications, including improved performance.

In .NET 6, we are including a new source generator as part of System.Text.Json. The JSON source generator works in conjunction with JsonSerializer, and can be configured in multiple ways. It’s your decision whether you use the new source generator. It can provide the following benefits:

  • Reduce start-up time
  • Improve serialization throughput
  • Reduce private memory usage
  • Remove runtime use of System.Reflection and System.Reflection.Emit
  • Allows for trim-compatible JSON serialization

For example, instead of dynamically generating methods at runtime to get and set class properties during (de)serialization using Reflection.Emit (which uses private memory and has start-up costs), a source generator can generate code that more simply and efficiently assigns or retrieves a value directly to/from properties, which is lightning fast.

You can try out the source generator by using the latest preview version of the System.Text.Json NuGet package. We are working on a proposal for including source generators within the SDK.

Generating optimized serialization logic

By default, the JSON source generator emits serialization logic for the given serializable types. This delivers higher performance than using the existing JsonSerializer methods by generating source code that uses Utf8JsonWriter directly. In short, source generators offer a way of giving you a different implementation at compile-time in order to make the runtime experience better.

Zooming out, JsonSerializer is a powerful tool which has many features (and even more coming!) that can improve the (de)serialization of .NET types from/into the JSON format. It is fast, but can have some performance overhead when only a subset of features are needed for a serialization routine. Going forward, we will update JsonSerializer and the new source generator together.

Given a simple type:

namespace Test
{
    internal class JsonMessage
    {
        public string Message { get; set; }
    }
}

The source generator can be configured to generate serialization logic for instances of the example JsonMessage type. Note that the class name JsonContext is arbitrary. You can use whichever class name you want for the generated source.

using System.Text.Json.Serialization;

namespace Test
{
    [JsonSerializable(typeof(JsonMessage)]
    internal partial class JsonContext : JsonSerializerContext
    {
    }
}

We have defined a set of JsonSerializer features that are supported with the source generation mode that provides the best serialization throughput, via JsonSerializerOptionsAttribute. These features can be specified to the source generator ahead of time, to avoid extra checks at runtime. If the attribute is not used, then default JsonSerializationOptions are assumed at runtime.

As part of the build, the source generator augments the JsonContext partial class with the following shape:

internal partial class JsonContext : JsonSerializerContext
{
    public static JsonContext Default { get; }

    public JsonTypeInfo<JsonMessage> JsonMessage { get; }

    public JsonContext(JsonSerializerOptions options) { }

    public override JsonTypeInfo GetTypeInfo(Type type) => ...;
}

The serializer invocation with this mode could look like the following example. This example provides the best possible performance.

using MemoryStream ms = new();
using Utf8JsonWriter writer = new(ms);

JsonContext.Default.JsonMessage.Serialize(writer, new JsonMessage { "Hello, world!" });
writer.Flush();

// Writer contains:
// {"Message":"Hello, world!"}

Alternatively, you can continue to use JsonSerializer, and instead pass an instance of the generated code to it, with JsonContext.Default.JsonMessage.

JsonSerializer.Serialize(jsonMessage, JsonContext.Default.JsonMessage);

Here’s a similar use, with a different overload.

JsonSerializer.Serialize(jsonMessage, typeof(JsonMessage), JsonContext.Default);

The difference between these two overloads is that the first is using the typed metadata implementation — JsonTypeInfo<T> — and the second one is using a more general untyped implementation that does type tests to determine if a typed implementation exists within the context instance. It is a little slower (due to the type tests), as a result. If there is not a source-generated implementation for a given type, then the serializer throws a NotSupportedException. It does not fallback to a reflection-based implementation (as an explicit design choice).

The fastest and most optimized source generation mode — based on Utf8JsonWriter — is currently only available for serialization. Similar support for deserialization — based on Utf8JsonReader — may be provided in the future depending on your feedback.

However, the source generator also emits type-metadata initialization logic that can benefit deserialization as well. To deserialize an instance of JsonMessage using pre-generated type metadata, you can do the following:

JsonSerializer.Deserialize(json, JsonContext.Default.JsonMessage);

Similar to serialization above, you might also write:

JsonSerializer.Deserialize(json, typeof(JsonMessage), JsonContext.Default);

Additional notes

  • Multiple types can be included for source generation via [JsonSerializable] on a derived, partial JsonSerializerContext instance, not just one.
  • The source generator also supports nested object and collection members on objects, not just primitive types.

Libraries: WebSocket Compression

Compression is important for any data transmitted over a network. WebSockets now enable compression. We used an implementation of permessage-deflate extension for WebSockets, RFC 7692. It allows compressing WebSockets message payloads using DEFLATE algorithm.

This feature was one of the top user requests for Networking on GitHub. You can follow our journey to providing that API via API review 1 and API review 2.

Credit to Ivan Zlatanov. Thanks Ivan!

We realized that using compression together with encryption may lead to attacks, like CRIME and BREACH. It means that a secret cannot be sent together with user-generated data in a single compression context, otherwise that secret could be extracted. To bring user’s attention to these implications and help them weigh the risks, we renamed our API to DangerousDeflateOptions. We also added the ability to turn off compression for specific messages, so if the user would want to send a secret, they could do that securely without compression.

There was also a follow-up by Ivan that reduced the memory footprint of the WebSocket when compression is disabled by about 27%.

Enabling the compression from the client side is easy, see the example below. However, please bear in mind that the server can negotiate the settings, e.g. request smaller window, or deny the compression completely.

var cws = new ClientWebSocket();
cws.Options.DangerousDeflateOptions = new WebSocketDeflateOptions()
{
    ClientMaxWindowBits = 10,
    ServerMaxWindowBits = 10
};

WebSocket compression support for ASP.NET Core was also recently added. It will be included in an upcoming preview.

Libraries: Socks proxy support

SOCKS is a proxy server implementation that can process any TCP or UDP traffic, making it a very versatile system. It is a long-standing community request that has been added to .NET 6.

This change adds support for Socks4, Socks4a, and Socks5. For example, it enables testing external connections via SSH or connecting to the Tor network.

The WebProxy class now accepts socks schemes, as you can see in the following example.

var handler = new HttpClientHandler
{
    Proxy = new WebProxy("socks5://127.0.0.1", 9050)
};
var httpClient = new HttpClient(handler);

Credit to Huo Yaoyuan. Thanks Huo!

Libraries: Support for OpenTelemetry Metrics

We’ve been adding support for OpenTelemetry for the last couple .NET versions, as part of our focus on observability. In .NET 6, we’re adding support for the OpenTelemetry Metrics API. By adding support for OpenTelemetry, your apps can seamlessly interoperate with other OpenTelemetry systems.

System.Diagnostics.Metrics is the .NET implementation of the OpenTelemetry Metrics API specification. The Metrics APIs are designed explicitly for processing raw measurements, generally with the intent to produce continuous summaries of those measurements, efficiently and simultaneously.

The APIs include the Meter class which can be used to create instrument objects (e.g. Counter). The APIs expose four instrument classes: Counter, Histogram, ObservableCounter, and ObservableGauge to support different metrics scenarios. Also, the APIs expose the MeterListener class to allow listening to the instrument’s recorded measurement for aggregation and grouping purposes.

The OpenTelemetry .NET implementation will be extended to use these new APIs, which add support for Metrics observability scenarios.

Library Measurement Recording Example

    Meter meter = new Meter("io.opentelemetry.contrib.mongodb", "v1.0");
    Counter<int> counter = meter.CreateCounter<int>("Requests");
    counter.Add(1);
    counter.Add(1, KeyValuePair.Create<string, object>("request", "read"));

Listening Example

    MeterListener listener = new MeterListener();
    listener.InstrumentPublished = (instrument, meterListener) =>
    {
        if (instrument.Name == "Requests" && instrument.Meter.Name == "io.opentelemetry.contrib.mongodb")
        {
            meterListener.EnableMeasurementEvents(instrument, null);
        }
    };
    listener.SetMeasurementEventCallback<int>((instrument, measurement, tags, state) =>
    {
        Console.WriteLine($"Instrument: {instrument.Name} has recorded the measurement {measurement}");
    });
    listener.Start();

Libraries: BigInteger Performance

Parsing of BigIntegers from both decimal and hexadecimal strings has been improved. We see improvements of up to 89%, as demonstrated in the following chart.

graph

Credit to Joseph Da Silva. Thanks Joseph!

Libraries: Vector<T> now supports nint and nuint

Vector<T> now supports the nint and nuint primitive types, added in C# 9. For example, this change should make it simpler to use SIMD instructions with pointers or platform-dependent lengths.

Libraries: Support for OpenSSL 3

.NET cryptography APIs support using OpenSSL 3 as the preferred native cryptography provider on Linux. .NET 6 will use OpenSSL 3 if it is available. Otherwise, it will use OpenSSL 1.x.

Libraries: Add support ChaCha20/Poly1305 cryptography algorithm

The ChaCha20Poly1305 class has been added to System.Security.Cryptography. In order to use the ChaCha20/Poly1305 algorithm, it must be supported by the underlying operating system. The static IsSupported property can be used to determine if the algorithm is supported in a given context.

  • Linux: requires OpenSSL 1.1 or hßigher.
  • Windows: build 20142 or higher (currently requires the Dev “insider” channel)

Credit to Kevin Jones for the Linux support. Thanks Kevin!

Interop: Objective-C interoperability support

The team has been adding Objective-C support, with the goal of having a single Objective-C interop implementation for .NET. Up until now, the Objective-C interop system was built around the Mono embedding API but we decided it wasn’t the right approach to share across runtimes. As a result we’ve create a new .NET API that will enable a single Objective-C interop experience that will eventually work on both runtimes.

This new API for Objective-C interop has brought immediate support in both runtimes for NSAutoreleasePool, which enables support for Cocoa’s reference-counted memory management system. You can now configure whether you want each managed thread to have an implicit NSAutoreleasePool. This enables the release of Cocoa objects on a per-thread basis.

Diagnostics (EventPipe/DiagnosticsServer) – MonoVM

A lot of diagnostics features have been added into MonoVM since beginning of .NET 6. This has enabled features like managed EventSource/EventListener, EventPipe and DiagnosticsServer. It has enabled using diagnostics tools like dotnet-trace, dotnet-counters, dotnet-stacks for apps running on mobile devices (iOS/Android) as well as desktop.

These new features opens up ability to analyse nettrace files generated by MonoVM in tools like PrefView/SpeedScope/Chromium, dotnet-trace, or writing custom parsers using libraries like TraceEvent.

We will continue to include more features going forward, primarily focusing on SDK integration and adapting more native runtime events (Microsoft-Windows-DotNETRuntime) into MonoVM enabling more events in nettrace files.

The following features are now in place:

  • Share native EventPipe/DiagnosticsServer library between MonoVM and CoreCLR.
  • Add TCP/IP support into DiagnosticsServer and build MonoVM iOS/Android runtime packs leveraging that configuration. Needed in order to support mobile platforms.
  • BCL EventSources runs on MonoVM emitting events into EventPipe.
  • BCL Runtime counters emitted by System.Diagnostics.Tracing.RuntimeEventSource wired up on MonoVM, consumable from tools like dotnet-counters.
  • Custom EventSources runs on MonoVM, emitting custom events into EventPipe, consumable from tools like dotnet-trace.
  • Custom event counters runs on MonoVM, emitting custom counter events into EventPipe, consumable from tools like dotnet-counters.
  • Sample profiler is implemented on MonoVM emitting events into EventPipe. Opens up abilities to do CPU profiling on MonoVM using dotnet-trace.
  • Implementation of dotnet-dsrouter diagnostics tool, enables use of existing diagnostic tooling like, dotnet-trace, dotnet-counters, dotnet-stack together with MonoVM running on mobile targets, without any need to change existing tooling. dotnet-dsrouter runs a local IPC server routing all traffic from diagnostic tooling over to DiagnosticsServer running in MonoVM on simulator/device.
  • Implementation of EventPipe/DiagnosticsServer in MonoVM using component-based architecture.
  • Implementation/extension of diagnostics environment based file session.

iOS CPU sampling (SpeedScope)

The following image demonstrates part of an iOS start up CPU sampling session viewed in SpeedScope.

speedscope-p5

Android CPU sampling (PerfView)

The following image demonstrates Android CPU sampling viewed in PerfView (main thread in infinite sleep).

prefview-p5

Runtime: CodeGen

The following changes have been made in RyuJIT.

Community contributions

  • Delete the unused dummyBB variable https://github.com/dotnet/runtime/pull/52155
  • Delete unused functions reading integers in big-endian format https://github.com/dotnet/runtime/pull/52154
  • Pass TYP_FLOAT to gtNewDconNode instead of creating a new scope https://github.com/dotnet/runtime/pull/51928

Thanks to @SingleAccretion for these contributions.

Dynamic PGO https://github.com/dotnet/runtime/issues/43618

  • Revise inlinee scale computations https://github.com/dotnet/runtime/pull/51593
  • Update optReachable with excluded block check https://github.com/dotnet/runtime/pull/51842
  • Generalize the branch around empty flow optimization https://github.com/dotnet/runtime/pull/51409
  • Add MCS jitflags support for the new GetLikelyClass PGO record type https://github.com/dotnet/runtime/pull/51578
  • Generalize checking for valid IR after a tail call to support crossgen2 determinism https://github.com/dotnet/runtime/pull/51903
  • More general value class devirtualization https://github.com/dotnet/runtime/pull/52210
  • Chained guarded devirtualization https://github.com/dotnet/runtime/pull/51890

JIT Loop Optimizations https://github.com/dotnet/runtime/issues/43549

  • Improved loop inversion shows good performance improvement in BenchE https://github.com/dotnet/runtime/pull/52347<img src=”https://user-images.githubusercontent.com/63486087/121261311-6d8bd780-c867-11eb-896e-922725a5fd17.png” width=”600″ height=”120″>
  • Scale cloned loop block weights https://github.com/dotnet/runtime/pull/51901
  • Don’t recompute preds lists during loop cloning to preserve existing profile data on the edges https://github.com/dotnet/runtime/pull/51757
  • Improve DOT flow graph dumping https://github.com/dotnet/runtime/pull/52329
  • Improve loop unrolling documentation https://github.com/dotnet/runtime/pull/52099

LSRA https://github.com/dotnet/runtime/issues/43318

  • Include register selection heuristics in “Allocating Registers” table https://github.com/dotnet/runtime/pull/52513The diff of old vs. new table:image

Keep Structs in Register https://github.com/dotnet/runtime/issues/43867

  • Prepare JIT backend for structs in registers https://github.com/dotnet/runtime/pull/52039
  • Liveness fix for struct enreg https://github.com/dotnet/runtime/pull/51851
  • Improve struct inits to keep ASG struct(LCL_VAR, 0) as STORE_LCL_VAR struct(0) https://github.com/dotnet/runtime/pull/52292

Optimizations & Debugging experience

  • Recognize and handle Vector64/128/256 for nint/nuint https://github.com/dotnet/runtime/pull/52016
  • Add clrjit.natvis file for better debugging experience https://github.com/dotnet/runtime/pull/52668The sample visualizer for jitstd::list as well as RefPosition and the decomposition of registerAssignment inside it to show all the registers:

image

SIMD

Inlining of certain methods involving SIMD or HWIntrinsics should now have improved codegen and performance. We saw improvements of up to 95%.

graph

Closing

.NET 6 Preview 5 is perhaps the biggest preview yet in terms of breadth and quantity of features. You can see how much Roslyn features are affecting low-level libraries features, with source generators and analyzers. The future has truly arrived. We now have a very capable compiler toolchain that enables us to produce highly-optimized and correct code, and enables the exact same experience for your own projects.

Now is a great time to start testing .NET 6. It’s still early enough for us to act on your feedback. It’s hard to imagine given that while we’re not shipping until November 2021 that the feedback window will soon narrow to high-severity issues only. The team works about one and a half previews ahead, and will soon switch to focusing primarily on quality issues. Please give .NET 6 a try if you can.

Thanks for being a .NET developer.

20 comments

Leave a comment

  • Avatar
    Damian Wyka

    Quite a lot of interesting improvements. Im particularly interested in source gen system.text.json – does it support fields? If yes does it include internal/private fields? If not is there a plan to add support for it?

    EDIT i see that special attribute mentions IncludeFields so i assume answer to first question is yes. But second question still stands

    • Layomi Akinrinade
      Layomi AkinrinadeMicrosoft employee

      Hi Damian! Yes the generator supports fields.

      For .NET 6.0, the source generator will support internal members (when JsonIncludeAttribute is used), but not private. You can track the progress here – https://github.com/dotnet/runtime/issues/31511. The generator’s output is not generated directly on serializable types, so it cannot reference private members. In the future, we can add support for a new pattern where code is generated directly on serializable types, which will enable support for private members.

      • Avatar
        Damian Wyka

        I see. Thanks for the answer.

        Btw for private fields you probably could generate an exact copy of serialized class but with all members that were marked for inclusion public and abuse Unsafe.As. This assumes same definitions are laid out in memory in the same order in runtime. Not sure if this would work with properties probably not but this allows accessing private data in classes that werent aware of source gened S.T.J when released (but were aware of normal S.T.J). Also i dont know if there could be worse security risk than exposing private from within since im no expert in security

    • Avatar
      Johan LorenssonMicrosoft employee

      Hi André,

      EventPipe/DiagnosticsServer is currently only included as low-level runtime library and have not yet been integrated into Android/iOS workloads, we will also update samples in Preview 6 to simplify the process building/enabling/running with diagnostic support. It is however possible to link the libraries needed (if you for example embed MonoVM yourself) and run an app on x64 emulator. Below are some low-level details describing the process:

      The sample apps in dotnet/runtime, https://github.com/dotnet/runtime/tree/main/src/mono/sample, are examples on how the low-level process works, and there is a document in https://github.com/dotnet/runtime/blob/main/docs/design/mono/diagnostics-tracing.md describing how the sample apps are built together using the runtime diagnostic tracing component. Main difference in Preview 5 for Android compared to what the document describes is that the components are shipped as archives (libmono-component-diagnostics_tracing-static.a) in the runtime pack, while in Preview 6 (and forward), Android will use shared libraries for the components (as described in above document).

      Once you have an app build with diagnostic tracing support included, you need to enable it (also described in above document), this is done in the same way as for CoreCLR reverse connect diagnostic-port scenarios, having the DOTNET_DiagnosticPorts environment variable set when launching the app, for example, “DOTNET_DiagnosticPorts=10.0.2.2:9000,suspend” if you run on Android emulator (connecting back using loopback on port 9000). Starting the app using that configuration will put it in suspend mode (open opportunity to start a tracing session before runtime starts up). To use diagnostics against “remote” targets (like Android/iOS), you install the regular diagnostic tooling and there is a new tool called dotnet-dsrouter, currently in preview mode, so it needs to be installed as preview tool, –add-source https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-tools/nuget/v3/index.json –version 5.0.227602 or build from repository source, https://github.com/dotnet/diagnostics/tree/main/src/Tools/dotnet-dsrouter.

      If you would like to run dotnet-trace against emulator, start dotnet-trace using collect argument and –diagnostic-port [some-named-port]. That will print out what port to use to connect back to dotnet-trace. Start dotnet-dsrouter like this, dotnet-dsrouter -ipcc [full port printed by dotnet-trace] -tcps 127.0.0.1:9000, if you pass –verbose debug to dotnet-dsrouter you will get connectivity information logged, could be good to validate you got end points connected through dotnet-dsrouter. That command sets dotnet-dsrouter into client (IPC) – server (TCP) mode accept incoming requests on 127.0.0.1:9000 (runtime connecting back to dotnet-dsrouter) and IPC client connecting IPC server running in dotnet-trace tooling. If things worked as expected, the runtime will now resume execution and you should have a stream of EventPipe traffic going between runtime and dotnet-trace ending up in a nettrace file.

      As I initially said, in Preview 5 we only have the low-level infrastructure included, so still manual work to integrate and use it, but Preview 6, Preview 7 will integrated this into high level SDK’s hiding the build/enabling/running steps as described above. If you are only interested in running EventSource using in-proc EventListener (not using EventPipe), that is possible without integrating the EventPipe/DiagnosticsServer component.

      The MAUI team has also a guide on how to setup profiling on Android running MAUI apps, its currently in the works, but could also be an interesting source of information and I already know several teams running CPU sampling on MAUI apps, https://github.com/dotnet/maui/wiki/Profiling-Maui-Apps#running-the-profiler and the Xamarin Android team is having a similar guide, included as part of the PR integrating diagnostics into the Xamarin Android SDK, https://github.com/xamarin/xamarin-android/pull/6022, most if this will be part of subsequent previews together with additional EventPipe metrics and events.

  • Panagiotis Kanavos
    Panagiotis Kanavos

    Something’s wrong with workloads, at least on Mac. Executing even dotnet new or dotnet workload list on a machine that had Preview 4 installed throws:

    ❯ dotnet new
    An item with the same key has already been added. Key: microsoft-macos-sdk-full
       at System.Collections.Generic.Dictionary`2.TryInsert(TKey key, TValue value, InsertionBehavior behavior) in System.Private.CoreLib.dll:token 0x60062cb+0x1a0
       at System.Collections.Generic.Dictionary`2.Add(TKey key, TValue value) in System.Private.CoreLib.dll:token 0x60062be+0x0
       at Microsoft.NET.Sdk.WorkloadManifestReader.WorkloadResolver.RefreshWorkloadManifests() in Microsoft.DotNet.TemplateLocator.dll:token 0x6000065+0x1b2
       at Microsoft.NET.Sdk.WorkloadManifestReader.WorkloadResolver..ctor(IWorkloadManifestProvider manifestProvider, String[] dotnetRootPaths, String[] currentRuntimeIdentifiers) in Microsoft.DotNet.TemplateLocator.dll:token 0x6000064+0x31

    The /usr/local/share/dotnet/sdk-manifests/6.0.100 folder seems to have manifests for the same workloads with different names, eg an old Microsoft.NET.Workload.MacCatalyst and a newer microsoft.net.sdk.maccatalyst . Manually removing all Microsoft.NET.Workload.* folders allows `dotnet new` and `dotnet workload list` to run, but the latter’s result is an empty list.

    ❯ dotnet workload list
    Workload Id
    -----------
    
    

    Issue posted here

  • Avatar
    Ioanni C

    I am currently in the process of writing a high throughput low latency app in .NET that spends most of its time doing JSON parsing. I benchmarked SpanJson and found it to be about 2x faster than System.Text.Json on .NET 5 for my workloads, so I am very happy to see the above improvements, and will be testing them out. That said, I’d like to put my voice out there that Utf8JsonReader source generation would be greatly appreciated, and I’m sure there are many others whose JSON workloads are read heavy as well as or instead of write heavy.

    • Avatar
      Ioanni C

      Sadly, I did not find the source generated version to be notably faster for parsing, and SpanJson is still the clear winner.

      • Layomi Akinrinade
        Layomi AkinrinadeMicrosoft employee

        Hi Ioanni! Thanks for your feedback! Can you share more about the scenario you are benchmarking? You could share a GitHub project/gist, create a new issue in the dotnet/runtime repo, or share in some other way.

        It sounds like you care mostly about improving throughput when deserializing/reading JSON payloads. The current version of the JSON source generator does not provide improved deserialization throughput, but can certainly do so in the future. Applications should see improvements for serialization throughput and other benefits this blog post goes over, however. I’ve taken note of your feedback as we prioritize the feature for improved deserialization throughput.

  • Avatar
    Aleksander Kovač

    Anyone already congratulated MS team for a new preview version release less than a month from the last one? Congrats 🙂

  • Avatar
    Jeremy Morton

    Preview 4 broke building with analyzers turned on, and that continues with Preview 5 (Preview 3 works fine):

    0>CSC: Error CS8032 : An instance of analyzer Microsoft.CodeAnalysis.MakeFieldReadonly.MakeFieldReadonlyDiagnosticAnalyzer cannot be created from C:\Program Files\dotnet\sdk\6.0.100-preview.5.21302.13\Sdks\Microsoft.NET.Sdk\codestyle\cs\Microsoft.CodeAnalysis.CodeStyle.dll : Could not load file or assembly 'Microsoft.CodeAnalysis, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35' or one of its dependencies. The system cannot find the file specified..
    0>CSC: Error CS8032 : An instance of analyzer Microsoft.CodeAnalysis.UseExplicitTupleName.UseExplicitTupleNameDiagnosticAnalyzer cannot be created from C:\Program Files\dotnet\sdk\6.0.100-preview.5.21302.13\Sdks\Microsoft.NET.Sdk\codestyle\cs\Microsoft.CodeAnalysis.CodeStyle.dll : Could not load file or assembly 'Microsoft.CodeAnalysis, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35' or one of its dependencies. The system cannot find the file specified..
    0>CSC: Error CS8032 : An instance of analyzer Microsoft.CodeAnalysis.UseSystemHashCode.UseSystemHashCodeDiagnosticAnalyzer cannot be created from C:\Program Files\dotnet\sdk\6.0.100-preview.5.21302.13\Sdks\Microsoft.NET.Sdk\codestyle\cs\Microsoft.CodeAnalysis.CodeStyle.dll : Could not load file or assembly 'Microsoft.CodeAnalysis, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35' or one of its dependencies. The system cannot find the file specified..
    0>CSC: Error CS8032 : An instance of analyzer Microsoft.CodeAnalysis.CodeStyle.CSharpFormattingAnalyzer cannot be created from C:\Program Files\dotnet\sdk\6.0.100-preview.5.21302.13\Sdks\Microsoft.NET.Sdk\codestyle\cs\Microsoft.CodeAnalysis.CSharp.CodeStyle.dll : Could not load file or assembly 'Microsoft.CodeAnalysis, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35' or one of its dependencies. The system cannot find the file specified..
    0>CSC: Error CS8032 : An instance of analyzer Microsoft.CodeAnalysis.CSharp.AddAccessibilityModifiers.CSharpAddAccessibilityModifiersDiagnosticAnalyzer cannot be created from C:\Program Files\dotnet\sdk\6.0.100-preview.5.21302.13\Sdks\Microsoft.NET.Sdk\codestyle\cs\Microsoft.CodeAnalysis.CSharp.CodeStyle.dll : Could not load file or assembly 'Microsoft.CodeAnalysis, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35' or one of its dependencies. The system cannot find the file specified..
    0>CSC: Error CS8032 : An instance of analyzer Microsoft.CodeAnalysis.CSharp.AddRequiredParentheses.CSharpAddRequiredExpressionParenthesesDiagnosticAnalyzer cannot be created from C:\Program Files\dotnet\sdk\6.0.100-preview.5.21302.13\Sdks\Microsoft.NET.Sdk\codestyle\cs\Microsoft.CodeAnalysis.CSharp.CodeStyle.dll : Could not load file or assembly 'Microsoft.CodeAnalysis, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35' or one of its dependencies. The system cannot find the file specified..

    etc.

    This is building with the VS 16.11.0.30205 (Preview 2) version of MSBuild.exe

  • Avatar
    Rob Ainscough

    Couple of questions:

    1. Is VB officially dead in .NET 6?
    2. Is there still NO native DirectX support in .NET 6?

    It just seems rather limiting for Microsoft to still make DirectX 12 exclusive to C++ … I don’t understand how this is beneficial to Microsoft? Bringing DirectX to .NET would open so many more doors and platform leverage … can someone please tell me the why behind repeated blocking of DirectX in .NET? Is it really all about cross platform and DirectX was just too specific to make it cross platform? It’s just seems odd to be saying this in 2021.

    Cheers, Rob.

    • Avatar
      Andre Prellwitz

      Cross-platform graphics can be accomplished by Veldrid or Silk.NET. Veldrid attempts to be a unified abstraction, while Silk.NET is more of a high-performance set of bindings for the underlying technologies. In fact, the Silk.NET authors have used their bindings to replace Veldrid’s OpenGL implementation to get a substantial performance improvement. That said, there seems to be a bit of overlap between the two projects, simply from the need to have cross-platform window functions to be able to actually do something with them. One of the Silk.NET authors used to maintain OpenTK, so there’s that library, as well. Silk.NET also includes OpenAL, Assimp, SDL, and GLFW bindings.

      Both support DirectX. Silk.NET is recently made a .NET Foundation project.

  • Avatar
    silkfire

    I don’t seem to be able to serialize an IEnumerable with the new source generator-base JSON serializer. What figures?

    The error I get is: ‘Metadata for type ‘IEnumerable’ was not provided to the serializer. The serializer method used does not support reflection-based creation of serialization-related type metadata. If using source generation, ensure that all root types passed to the serializer have been indicated with ‘JsonSerializableAttribute’, along with any types that might be serialized polymorphically.’

    I’ve tried applying an [JsonSerializable(typeof(IEnumerable))] but the results are the same.

  • Avatar
    Sathya Rajagopalan

    There is no nuget for 6.0.0-preview.5.x.x version of Microsoft.AspNetCore.Http.Features.
    The latest available version for this package available is still in 6.0.0-preview.4.x.x .

    My app breaks when I move from preview 4 to preview 5 for all other packages but for above mentioned package. I am unable to move upto preview 5 until this is resolved.
    Is the latest 6 preview 5 version not published to nuget.org yet?

    Thanks.