July 11th, 2023

Announcing .NET 8 Preview 6

Justin Yoo
Senior Cloud Advocate

We’re delighted to let you know about the latest features and improvements coming with .NET 8 Preview 6! This release is a continuation of the Preview 5 release, and we’re committed to bringing you more enhancements with each monthly release.

Today we have an exciting release incorporated with plenty of library updates, a new WASM mode, more source generators, constant performance improvements, and NativeAOT support on iOS. We hope you enjoy these new features and improvements. Stay tuned for more updates as we continue our journey of making .NET better, together!

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

There are several exciting posts you should check out as well:

  • ASP.NET Core brings an improved startup debugging experience, Blazor enhancements, and metrics in the Preview 6 release.
  • C# 12 adds three new features for .NET 8 Preview 6: interceptors, inline arrays, and enhancements to the nameof expression.
  • .NET MAUI resolved 23 high-impact issues and introduces Native AOT for iOS in the Preview 6 release.
  • Finally, today you can now enjoy .NET MAUI in .NET 8 using the new .NET MAUI extension for Visual Studio Code

Stay current with what’s new and coming in What’s New in .NET 8. It will be kept updated throughout the release.

Now, let’s take a look at some new .NET 8 features.

Download .NET 8 Preview 6

System.Text.Json improvements

We made a number of improvements to the System.Text.Json source generator, primarily aimed at making Native AOT on par with the reflection-based serializer.

  • Added caching support to the incremental generator, improving IDE performance in large projects. https://github.com/dotnet/runtime/pull/86121
  • Improved formatting of source generated code, including fixes to a number of indentation issues https://github.com/dotnet/runtime/pull/86526, https://github.com/dotnet/runtime/pull/87557
  • Added a number of new diagnostic warnings https://github.com/dotnet/runtime/pull/87980
  • Fixed a number of bugs related to accessibility modifier resolution https://github.com/dotnet/runtime/pull/87136
  • Ensures that types of ignored or inaccessible properties are not included by the generator https://github.com/dotnet/runtime/pull/87383
  • Fix issues related to JsonNumberHandling support https://github.com/dotnet/runtime/pull/87484
  • Fix support for recursive collection types https://github.com/dotnet/runtime/pull/87632
  • Fix custom converter support for nullable structs https://github.com/dotnet/runtime/pull/84208
  • Fix a number of bugs in the compile-time attribute parsing implementation https://github.com/dotnet/runtime/pull/87796
  • Add support for nesting JsonSerializerContext declarations within arbitrary type kinds https://github.com/dotnet/runtime/pull/87829

JsonStringEnumConverter<TEnum>

This new converter complements the existing JsonStringEnumConverter class, which is not supported in Native AOT.

Users wishing to target Native AOT users should annotate their enum types with the following pattern.

[JsonConverter(typeof(JsonStringEnumConverter<MyEnum>))]
public enum MyEnum { Value1, Value2, Value3 }

[JsonSerializable(typeof(MyEnum))]
public partial class MyContext : JsonSerializerContext { }

JsonConverter.Type

The new property allows users to look up the type of a non-generic JsonConverter instance:

Dictionary<Type, JsonConverter> CreateDictionary(IEnumerable<JsonConverter> converters)
    => converters.Where(converter => converter.Type != null).ToDictionary(converter => converter.Type!);

The property is nullable since it returns null for JsonConverterFactory instances and typeof(T) for JsonConverter<T> instances.

Stream-based ZipFile CreateFromDirectory and ExtractToDirectory method overloads

We added new overloads of ZipFile.CreateFromDirectory that allow users to collect all the files included in a directory and zip them, then store the resulting zip file into the provided stream.

Symmetrically, we added the ZipFile.ExtractToDirectory overloads that allow users to provide a stream containing a zipped file and extract its contents into the filesystem.

These APIs can avoid having to use the disk as an intermediate step. This can be useful in scenarios where disk space is constrained, like, for example, in cloud-based environments:

  • CreateFromDirectory does not have to write the zipped result into disk.
  • ExtractToDirectory does not require the zipped file to be located in disk.

ZipFile.CreateFromDirectory usage

Stream destinationStream = GetStreamFromSomewhere();

ZipFile.CreateFromDirectory(
    sourceDirectoryName: "/home/username/sourcedirectory/",
    destination: destinationStream,
    compressionLevel: CompressionLevel.Optimal,
    includeBaseDirectory: true,
    entryNameEncoding: Encoding.UTF8);

ZipFile.ExtractToDirectory usage

Stream sourceStream = GetStreamFromSomewhere();

ZipFile.ExtractToDirectory(
    source: sourceStream,
    destinationDirectoryName: "/home/username/destinationdirectory/",
    entryNameEncoding: Encoding.UTF8,
    overwriteFiles: true);

MetricCollector Metrics API

MetricCollector is a new class that is designed to help test scenarios. It was previously called InstrumentRecorder. We’ve made significant improvements to this class and moved it to the Microsoft.Extensions.Telemetry.Testing package.

The MetricCollector class can now record metric measurements along with timestamps. Additionally, the class offers the flexibility to use any desired time provider for accurate timestamp generation.

The following example demonstrates how to use the feature.

MetricCollector usage

const string CounterName = "MyCounter";

var now = DateTimeOffset.Now;

var timeProvider = new FakeTimeProvider(now);
using var meter = new Meter(Guid.NewGuid().ToString());
var counter = meter.CreateCounter<long>(CounterName);
using var collector = new MetricCollector<long>(counter, timeProvider);

Assert.Empty(collector.GetMeasurementSnapshot());
Assert.Null(collector.LastMeasurement);

counter. Add(3);

// verify the update was recorded
Assert.Equal(counter, collector.Instrument);
Assert.NotNull(collector.LastMeasurement);

Assert.Single(collector.GetMeasurementSnapshot());
Assert.Same(collector.GetMeasurementSnapshot().Last(), collector.LastMeasurement);
Assert.Equal(3, collector.LastMeasurement.Value);
Assert.Empty(collector.LastMeasurement.Tags);
Assert.Equal(now, collector.LastMeasurement.Timestamp);        

Introducing the options validation source generator

To reduce startup overhead and improve validation feature set, we’ve introduced the source code generator that implements the validation logic.

Options validation usage


public class FirstModelNoNamespace
{
    [Required]
    [MinLength(5)]
    public string P1 { get; set; } = string. Empty;

    [Microsoft.Extensions.Options.ValidateObjectMembers(typeof(SecondValidatorNoNamespace))]
    public SecondModelNoNamespace? P2 { get; set; }

    [Microsoft.Extensions.Options.ValidateObjectMembers]
    public ThirdModelNoNamespace? P3 { get; set; }
}

public class SecondModelNoNamespace
{
    [Required]
    [MinLength(5)]
    public string P4 { get; set; } = string. Empty;
}

public class ThirdModelNoNamespace
{
    [Required]
    [MinLength(5)]
    public string P5 { get; set; } = string.Empty;
}

[OptionsValidator]
public partial class FirstValidatorNoNamespace : IValidateOptions<FirstModelNoNamespace>
{
}

[OptionsValidator]
public partial class SecondValidatorNoNamespace : IValidateOptions<SecondModelNoNamespace>
{
}

If the app is using dependency injection, it can inject the validation using the following pattern.


var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllersWithViews();
builder.Services.Configure<FirstModelNoNamespace>(builder.Configuration.GetSection(...));

builder.Services.AddSingleton<IValidateOptions<FirstModelNoNamespace>, FirstValidatorNoNamespace>();
builder.Services.AddSingleton<IValidateOptions<SecondModelNoNamespace>, SecondValidatorNoNamespace>();

Expanding LoggerMessageAttribute Constructor Overloads for Enhanced Functionality

New LoggerMessageAttribute constructor overloads have been introduced, offering greater flexibility in specifying the required parameters with reduced code. The new constructor overloads include options such as specifying only the LogLevel and message, only the LogLevel, or only the message.

These enhancements make it easier for users to define LoggerMessageAttributes while minimizing unnecessary code.

    public LoggerMessageAttribute(LogLevel level, string message);
    public LoggerMessageAttribute(LogLevel level);
    public LoggerMessageAttribute(string message);

LoggerMessage usage

The following example demonstrate an instantiation of LoggerMessage that previously wasn’t possible.

        [LoggerMessage(Level = LogLevel.Warning, Message = "{p1} should be valid")]
        public partial void LogWaraning(string p1);

Note: In a later preview, for constructors that do not require an event Id, the system will automatically generate the event Id, eliminating the need for users to manually provide it.

Configuration binding source generator improvements

In Preview 3, we introduced a new source generator to provide AOT and trim-friendly configuration in ASP.NET Core. The generator is an alternative to the pre-exising reflection-based implementation. Since then, we’ve made several improvements based on community feedback and the generator is ready for folks to give it another go using Preview 6.

An example app that uses configuration binding and is published with AOT goes from having two (2) AOT analysis warnings during compilation to having none. The app would fail when executed but now it works.

No source code changes are needed to use the generator. It’s enabled by default in Native AOT web apps. For other project types it is off by default, but you can control it by adding the following property to your project.

<PropertyGroup>
    <EnableConfigurationBindingGenerator>true</EnableConfigurationBindingGenerator>
</PropertyGroup>

You can find known issues here.

Source Generated COM Interop

We now have a new source generator that supports interoperating with COM interfaces using the source generated interop support that we started with LibraryImportAttribute. You can use the System.Runtime.InteropServices.Marshalling.GeneratedComInterfaceAttribute to mark an interface as a COM interface for the source generator. The source generator will then generate code to enable calling from C# code to unmanaged code, as well as code to enable calling from unmanaged code into C#. This source generator integrates with LibraryImportAttribute, and you can use types with the GeneratedComInterfaceAttribute as parameters and return types in LibraryImportAttribute-attributed methods.

The COM source generator provides a straightforward IDE experience through analyzers and code fixers. This is similar to LibraryImportAttribute. Next to each interface that has the System.Runtime.InteropServices.ComImportAttribute, a lightbulb will offer an option to convert to source generated interop. This fix will change the interface to use the GeneratedComInterfaceAttribute. Next to every class that implements an interface with the GeneratedComInterfaceAttribute, a lightbulb will offer an option to add the GeneratedComClassAttribute to the type. Once your types are converted, you can move your DllImport methods to use LibraryImportAttribute with the existing code fixer there. With these two lightbulbs, it is easy to convert your existing COM interop code to use the new source generated interop. There are also more analyzers to help catch places where you may be mixing source-generated and runtime-based COM interop that may require additional work.

As part of this project, we updated the System.Transactions library to use the new source-generated interop! We used this experience to help refine the analyzers and code-fixers to provide a good migration experience.

GeneratedComInterface usage

using System.Runtime.InteropServices;
using System.Runtime.InteropServices.Marshalling;

[GeneratedComInterface]
[Guid("5401c312-ab23-4dd3-aa40-3cb4b3a4683e")]
interface IComInterface
{
    void DoWork();
}

internal class MyNativeLib
{
    [LibraryImport(nameof(MyNativeLib))]
    public static partial void GetComInterface(out IComInterface comInterface);
}

GeneratedComClassAttribute

The source generator also supports the new System.Runtime.InteropServices.Marshalling.GeneratedComClassAttribute to enable you to pass your types that implement interfaces with the System.Runtime.InteropServices.Marshalling.GeneratedComInterfaceAttribute-attributed interfaces to unmanaged code. The source generator will generate the code necessary to expose a COM object that implements the interfaces and forwards calls to the managed implementation.

GeneratedComClassAttribute usage

using System.Runtime.InteropServices;
using System.Runtime.InteropServices.Marshalling;

MyNativeLib.GetComInterface(out IComInterface comInterface);
comInterface.RegisterCallbacks(new MyCallbacks());
comInterface.DoWork();

[GeneratedComInterface]
[Guid("5401c312-ab23-4dd3-aa40-3cb4b3a4683e")]
interface IComInterface
{
    void DoWork();
    void RegisterCallbacks(ICallbacks callbacks);
}

[GeneratedComInterface]
[Guid("88470b56-aabc-46af-bf97-8106a1aa3cf9")]
interface ICallbacks
{
    void Callback();
}

internal class MyNativeLib
{
    [LibraryImport(nameof(MyNativeLib))]
    public static partial void GetComInterface(out IComInterface comInterface);
}

[GeneratedComClass]
internal class MyCallbacks : ICallbacks
{
    public void Callback()
    {
        Console.WriteLine("Callback called");
    }
}

Interacting with LibraryImportAttribute

Methods on interfaces with the GeneratedComInterfaceAttribute support all the same types as LibraryImportAttribute, and LibraryImportAttribute gains support for GeneratedComInterface-attributed types and GeneratedComClass-attributed types in this release.

If your C# code will only be use a GeneratedComInterfaceAttribute-attributed interface to either wrap a COM object from unmanaged code or wrap a managed object from C# to expose to unmanaged code, you can use the options in the GeneratedComInterfaceAttribute.Options property to customize which code will be generated. This option will enable you to not need to write marshallers for scenarios that you know will not be used.

The source generator uses the new System.Runtime.InteropServices.Marshalling.StrategyBasedComWrappers type to create and manage the COM object wrappers and the managed object wrappers. This new type handles providing the expected .NET user experience for COM interop, while providing customization points for advanced users. If your application has its own mechanism for defining types from COM or if you need to support scenarios that source-generated COM does not currently support, you can consider using the new StrategyBasedComWrappers type to add the missing features for your scenario and get the same .NET user experience for your COM types.

Limitations

Currently the COM source generator has the following limitations. We do not expect to address these limitations in .NET 8, but we may in a future version of .NET.

  • No support for IDispatch-based interfaces.
    • Support for these interfaces may be manually implemented using a local definition of the IDispatch interface.
  • No support for IInspectable-based interfaces.
    • Use the CsWinRT tool to generate the interop code for these interfaces.
  • No support for apartment affinity.
    • All COM objects are assumed to be free-threaded. Support for apartment affinity may be manually implemented using the StrategyBasedComWrappers type and custom strategy implementations.
  • No support for COM properties.
    • These may be manually implemented as methods on the interface.
  • No support for COM events.
    • These may be manually implemented using the underlying COM APIs.
  • No support for using the new keyword to activate a COM CoClass.
    • Use LibraryImportAttribute to P/Invoke to the CoCreateInstance API to activate the CoClass.

System.Security: SHA-3 Support

Support for the SHA-3 hashing primitives is now available on platforms that offer SHA-3. This is currently Linux with OpenSSL 1.1.1+ and Windows 11 build 25324+.

APIs where SHA-2 is available now offer a SHA-3 compliment. This includes SHA3_256, SHA3_384, and SHA3_512 for hashing; HMACSHA3_256, HMACSHA3_384, and HMACSHA3_512 for HMAC; HashAlgorithmName.SHA3_256, HashAlgorithmName.SHA3_384, and HashAlgorithmName.SHA3_512 for hashing where the algorithm is configurable; and RSAEncryptionPadding.OaepSHA3_256, RSAEncryptionPadding.OaepSHA3_384, and RSAEncryptionPadding.OaepSHA3_512 for RSA OAEP encryption.

Using the SHA-3 APIs is similar to SHA-2, with the addition of an IsSupported property to determine if the platform offers SHA-3.

// Hashing example
// Check if SHA-3-256 is supported on the current platform.
if (SHA3_256.IsSupported)
{
    byte[] hash = SHA3_256.HashData(dataToHash);
}
else
{
    // Determine application behavior if SHA-3 is not available.
}

// Signing Example
// Check if SHA-3-256 is supported on the current platform.
if (SHA3_256.IsSupported)
{
     using ECDsa ec = ECDsa.Create(ECCurve.NamedCuves.nistP256);
     byte[] signature = ec.SignData(dataToBeSigned, HashAlgorithmName.SHA3_256);
}
else
{
    // Determine application behavior if SHA-3 is not available.
}

Additionally, SHA-3 includes two extendable-output functions (XOFs), SHAKE128 and SHAKE256. These are available as Shake128 and Shake256.

if (Shake128.IsSupported)
{
    using Shake128 shake = new Shake128();
    shake.AppendData("Hello .NET!"u8);
    byte[] digest = shake.GetHashAndReset(outputLength: 32);

    // Also available as a one-shot:
    digest = Shake128.HashData("Hello .NET!"u8, outputLength: 32);
}
else
{
    // Determine application behavior if SHAKE is not available.
}

SHA-3 support is currently aimed at supporting cryptographic primitives. Higher level constructions and protocols are not expected to fully support SHA-3 initially. This includes, but is not limited to, X.509 certificates, SignedXml, and COSE. Support for SHA-3 may expand in the future depending on platform support and standards which adopt SHA-3.

SHA-3 was standardized by NIST as FIPS 202 as an alternative to, not successor, to SHA-2. Developers and organizations should decide when or even if adopting SHA-3 is appropriate for them.

SDK: container publishing performance and compatibility

We’ve made a few changes to the generated image defaults for .NET 8 apps.

  • Images now default to using the new rootless capability of .NET containers, making your applications secure-by-default. You can change this at any time by setting your own ContainerUser, like root.
  • Images are tagged as latest by default, the same as other container tools.

We’ve improved the performance of container pushes to remote registries, the reliability of the push operation, and support for a larger range of registries. At the same time, Tom Deseyn of Red Hat was busy improving our support for a range of prevalent container implementations.

This version should see much improved performance for container pushes, especially to Azure registries. This is because of our improved support for pushing layers in one operation. In addition, for registries that don’t support atomic uploads, we’ve implemented a more reliable and re-try-able chunking upload mechanism.

As a side effect of these changes, we also expanded our support matrix for registries. Harbor and Artifactory join the list of known-working registries, and Tom’s work enabled Quay.io and Podman pushes as well.

HybridGlobalization mode on WASM

WASM apps can use a new globalization mode that brings lighter ICU bundle and leverages Web API instead. In Hybrid mode, globalization data is partially pulled from ICU bundle and partially from calls into JS. It serves all the locales supported by WASM.

When to consider using HybridGlobalization

This option is most suitable for applications that cannot work in InvariantGlobalization mode and use localization data from more than one ICU shard (EFIGS, CJK, no-CJK) – so currently using either:

<BlazorWebAssemblyLoadAllGlobalizationData>true</BlazorWebAssemblyLoadAllGlobalizationData>

in Blazor WebAssembly or

<WasmIncludeFullIcuData>true</WasmIncludeFullIcuData>

in WASM Browser.

Apps that were loading no-CJK or CJK shard using the custom ICU file loading method:

<WasmIcuDataFileName>icudt_no_CJK.dat</WasmIcuDataFileName>

might also be interested, because hybrid file is smaller than no-CJK shard by 26% and smaller than CJK by 15%.

How to use HybridGlobalization

Set MsBuild property: <HybridGlobalization>true</HybridGlobalization>. It will load icudt_hybrid.dat file that is 46% smaller than originally loaded icudt.dat.

Limitations

Due to limitations of Web API, not all Globalization APIs are supported in Hybrid mode. Some of the supported APIs changed their behavior. To make sure your application is will not be affected, read the section Behavioral differences for WASM.

APIs that obtain the result by calling into JS have worse performance than the non-hybrid version. These APIs are listed in the documentation. The APIs that are not on the “Affected public APIs” lists perform the same as in non-hybrid mode.

Support for targeting iOS platforms with NativeAOT

We now have support for targeting iOS-like platforms with Native AOT. This includes building and running .NET iOS and .NET MAUI applications with NativeAOT on: ios, iossimulator, maccatalyst, tvos or tvossimulator systems. The motivation of this work is to enable users to explore the possibility of achieving better performance and size savings when targeting such platforms with NativeAOT.

This is available as an opt-in feature intended for app deployment, while Mono is still used as the default runtime choice for app development and deployment. This milestone has been reached with a great collaboration between our community members: @filipnavara @AustinWise and @am11 who contributed with their work, and joint effort of NativeAOT, Mono and Xamarin teams.

Current state

The current state has been tested with:

  • .NET iOS app (dotnet new ios)
  • .NET MAUI iOS app (dotnet new maui)

These sample applications show the following preliminary results compared to Mono:

.NET iOS app Mono-p6 NativeAOT-p6 diff (%)
Size on disk (Mb) 11,61 6,99 -40%
.ipa (Mb) 4,37 2,69 -39%
.NET MAUI iOS app Mono-p6 NativeAOT-p6 diff (%) NativeAOT-fix diff (%)
Size on disk (Mb) 40,24 50,13 25% 27,58 -31,46%
.ipa (Mb) 14,68 16,59 13% 10,23 -30,32%

The .NET 8 Preview 6 results (marked as *-p6) show that the .NET iOS app has significant improvements compared to Mono where the compressed app bundle (.ipa) is up to ~39% smaller showing great potential, while the .NET MAUI iOS app shows worse results producing ~13% larger output. However, we have identified the root cause of the size regression with the .NET MAUI app and we are currently working on the following list of issues to address the size regression:

  1. https://github.com/xamarin/xamarin-macios/pull/18532
  2. https://github.com/xamarin/xamarin-macios/issues/18479
  3. https://github.com/dotnet/runtime/issues/87924
  4. https://github.com/dotnet/runtime/issues/86649

By fixing the identified issues 1-3) we have estimated that NativeAOT can reach great results with the .NET MAUI app, which is shown in the column NativeAOT-fix, where the size of the application bundle is ~30% smaller compared to Mono. Fixing the issue 4) would potentially improve the performance even further, but at this stage we cannot estimate the exact numbers. More information about .NET MAUI performance with NativeAOT is being tracked in: https://github.com/dotnet/runtime/issues/80907

We would like to point out that conclusions regarding NativeAOT performance on iOS-like platforms should not be drawn out from the presented numbers in the table nor from the .NET 8 Preview 6 release in general. Especially since this is still work-in-progress and only the first step towards making the feature ready for .NET 9 official release. Therefore, we are actively working on improvements and identifying all the work that will try to bring full NativeAOT experience to our customers towards achieving great performance and size savings, which is being tracked in the following list of issues (and their subtasks):

  • https://github.com/dotnet/runtime/issues/80905 tracks: Overall progress
  • https://github.com/xamarin/xamarin-macios/issues/17339 tracks: Xamarin integration improvements
  • https://github.com/dotnet/runtime/issues/86649 tracks: Trimming and extension compatibility improvements=

How to build and run a .NET MAUI application with NativeAOT on an iOS device with .NET CLI

Installation

dotnet workload install maui

Creating a sample application

dotnet new maui -n HelloMaui

Choosing NativeAOT over Mono

The MSBuild properties PublishAot=true and PublishAotUsingRuntimePack=true (temporary, see below) enable NativeAOT deployments.

These two properties are the only notable difference compared to when deploying with Mono. You need to add them in a PropertyGroup of the project file of your application:

<PropertyGroup>
    <PublishAot>true</PublishAot>
    <PublishAotUsingRuntimePack>true</PublishAotUsingRuntimePack>
</PropertyGroup>

Which means that every time the app is deployed via dotnet publish it will be deployed by using NativeAOT.

Running your application

dotnet publish -f net8.0-ios -c Release -r ios-arm64  /t:Run

iOS and NativeAOT compatibility

Not all features in iOS are compatible with NativeAOT. Similarly, not all libraries commonly used in iOS are compatible with NativeAOT. .NET 8 represents the start of work to enable NativeAOT for iOS, your feedback will help guide our efforts during .NET 8 previews and beyond, to ensure we focus on the places where the benefits of NativeAOT can have the largest impact.

The following list includes some limitations when targeting iOS-like platforms that have been encountered so far (and thus might not be the final list):

  • Installation and app deployment by using Visual Studio have not been tested yet
  • Using NativeAOT is only enabled during app deployment – dotnet publish
  • Linq.Expressions library functionality is not fully supported yet
  • The PublishAotUsingRuntimePack=true MSBuild property is a temporary workaround required for targeting iOS-like platforms with NativeAOT
    • This requirement will become obsolete by fixing: https://github.com/dotnet/runtime/issues/87060
  • Managed code debugging is only supported with Mono

NOTE: The previous list is an extension to the limitations applicable for all platforms with NativeAOT: https://github.com/dotnet/runtime/blob/main/src/coreclr/nativeaot/docs/limitations.md

CodeGen

Community PRs (Many thanks to JIT community contributors!)

  • @huoyaoyuan made use of ECMA-335 III.4.6 to optimize type checks involving Nullable<T>, PR#87241. @huoyaoyuan also made a fix for parameter ordering and value in gtNewColonNode in PR#87366.

  • @jasper-d optimized new Vector3 { X = val1, Y = val2, Z = val3 } pattern to emit the same codegen as Vector3 { val1,val2, val3} by folding cost WithElement to CNS_VEC, PR#84543.

Vector3 Foo1() => new Vector3 { X = 1, Y = 2, Z = 3 }; 
Vector3 Foo2() => new Vector3(1, 2, 3); 
  • @pedrobsaila fused numeric < and == comparisons to <= and > and == to >= and reduced the number of instructions in #PR78786.

  • @SingleAccretion has been working on internal JIT cleanup to greatly simplify the Internal Representation (IR). He removed GT_ASG IR that we had for many years, and it shows about 1 ~ 1.5% of throughput improvements, PR#85871.

    Windows x64 Codegen improvement

AVX-512

Since we enabled Vector512 and AVX512 support in Preview 4, our community members continued to add new features.

  • @DeepakRajendrakumaran accelerated Vector256/512.Shuffle() using AVX512 VBMI that improves performance by reducing data movement from memory to registers and rearranging data in the two memory addresses, PR#87083.

  • @Ruihan-Yin enabled EVEX feature that embeds broadcast and optimized Vector256.Add() when vector base type is TYP_FLOAT, PR#84821.

Arm64

  • @SwapnilGaikwad used Conditional Invert (cinv) and Conditional Negate (cneg) instead of Conditional Select(csel) that reduced code size and speed on Arm64 platform, PR#84926.

    Arm64 Codegen improvement

  • @SwapnilGaikwad also combined two vector table lookups into one on Arm64 that shows 10-50% of speed-up on microbenchmarks such as FormatterInt32, PR#87126.

  • We changed register allocation to iterate over the registers of interest instead of over all the registers, which improved the JIT’s own throughput for various scenarios by up to 5% on Arm64 and around 2% on x64.

Community spotlight (Wraith2)

I’m a career developer working in a mix of technologies from vb6 to netcore with most things in between. I maintain extend and assist in developing new products. I got started working with .net core using System.IO.Pipelines to efficiently parse a text based custom protocol that was causing performance concerns at work. I was very pleased with results but as soon as I started adding database access to the project suddenly there was a lot going on in performance profiles that didn’t seem to be needed. Since the runtime was open source I realized that I could improve what I found.

I started contributing performance enhancements to the System.Data.SqlClient driver in the dotnet/runtime repository and then once SqlClient was moved out of the runtime into a new project Microsoft.Data.SqlClient I continued to contribute there working with the team to improve the performance and stability of the driver. I’ve continued to take an interest in the runtime by reviewing code and occasionally adding new features like some new BMI instructions support in the JIT. Working on new and evolving codebase has allowed me to learn a lot about .net runtime and libraries by interacting with enthusiastic and knowledgeable contributors from all over the world.

Do you know anybody who is contributing to .NET that we should feature in future posts? Nominate them at https://aka.ms/net8contributor.

Summary

.NET 8 Preview 6 contains exciting new features and improvements that would not be possible without the hard work and dedication of a diverse team of engineers at Microsoft and a passionate open-source community. We want to extend our sincere thanks to everyone who has contributed to .NET 8 so far, whether it was through code contributions, bug reports, or providing feedback.

Your contributions have been instrumental in the making of the .NET 8 Previews, and we look forward to continuing to work together to build a brighter future for .NET and the entire technology community.

Curious about what is coming? Go see for yourself what’s next in .NET!

Author

Justin Yoo
Senior Cloud Advocate

15 comments

Discussion is closed. Login to edit/delete existing comments.

  • Lei Xi

    I am curious about the amazing feature NativeAOT.
    Anyone successed with the NativeAOT build of MAUI descripted in this post?
    With DotNet prevew 7, I followed the steps but failed with following errors

    <code>

    I'm not sure what is wrong with me.

    Read more
  • Álvaro García

    What’s happened with “Improvements to auth and identity in ASP.NET Core 8”?
    I didn’t read any new on last previews.

    • Doğan Çoruh

      I wonder that too… Waiting for a Duende free identity implementation for commercial projects…

  • Rafael Ferreira ALves

    When will Native AOT be fully compatible with dotnet 8, including aspnet core and libs like System.Reflection?
    It would be great to take advantage of and use in aws lambda functions and also in azure functions, making initialization very fast

  • d3c0d3d

    When I saw the ZipFile.ExtractToDirectory in the post I laughed because the only thing missing for me to use this API for a decade is the option to extract with a password and microsoft does not put this, making me and most people use third-party libraries, incredible!

    • Michael Taylor

      The open issue for this request is here. As seen in that discussion there are both legal issues and algorithm questions related to this. However at the end of the day it is just an encryption stream. Given that this issue has been open for 7 years I really question how many people are really asking for this feature given that the code is open sourced, they have asked for anyone to contribute code to...

      Read more
  • Philippe Rollin

    Thank you for the write up.

    One area that remains unclear is how does NativeAOT compares to Mono AOT as used by Xamarin.iOS and current net7-ios apps? What are the benefits of NativeAOT vs the existing AOT toolchain?

    • Charles Roddie

      NativeAOT iOS support is a suprising and fantastic development.

      The benefits are:

      Read more
  • Sodiq Yekeen

    “To make sure your application is will not be affected, read the section Behavioral differences for WASM.” Seems some typo here… Meanwhile, great work.

  • Paulo Pinto

    Given the extent that WinDev focus on COM, the new COM related improvements are quite welcomed.

    I still look forward to having back the Visual Basic 6 and .NET Native development experience in regards to COM/WinRT, without having to deal with C++ and primitive IDL tooling as well.

  • Jaeson Aras

    Thanks guys, great work! Visual Studio Pro for Windows works well. Just a note though, the Mac installer launches the Xamarin Profiler instead of the VS installer.

  • William Liebenberg

    Thanks for the write up Justin 🙂 lots of new things to try out in this preview.

  • Holger Schwichtenberg (www.DOTNET-DOKTOR.de)

    I think, all your samples of Source Generated COM Interop missing the partial keyword.

    If I try your code

    <code>

    in Visual Studio 17.7 Preview 3.0 with .NET 8.0 Preview 6 I get:
    The interface 'IComInterface' or one of its containing types is missing the 'partial' keyword. Code will not be generated for 'IComInterface'.

    However, this compiles:

    <code>

    Read more