Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

What's new in .NET 8 Preview 7 [WIP] #8438

Closed
3 tasks
leecow opened this issue May 3, 2023 · 14 comments
Closed
3 tasks

What's new in .NET 8 Preview 7 [WIP] #8438

leecow opened this issue May 3, 2023 · 14 comments

Comments

@leecow
Copy link
Member

leecow commented May 3, 2023

What's new in .NET 8 Preview 7

This issue is for teams to highlight work for the community that will release in .NET 8 Preview 7

To add content, use a new conversation entry. The entry should include the team name and feature title as the first line shown in the template below.

Required

## Team Name: Feature title

[link to the tracking issue or epic item for the work]

Tell the story of the feature and anything the community should pay particular attention 
to be successful in using the feature.

Optional

Below are three additional items to consider. These will help the .NET 8 blog team and the community throughout the release.

  • Link to documentation.
    • Where can we send people to learn more about the feature?
  • Link to where you'd like people to provide feedback for this feature.
    • Where can people best comment on the direction of this feature?
  • Whether you would like assistance from the .NET 8 writers to craft a story for this feature.

Index of .NET 8 releases

Preview 1: #8133
Preview 2: #8134
Preview 3: #8135
Preview 4: #8234
Preview 5: #8436
Preview 6: #8437
Preview 7: #8438
RC 1: #8439
RC 2: #8440

@mkhamoyan
Copy link
Member

mkhamoyan commented Jul 20, 2023

HybridGlobalization mode on iOS/tvOS/MacCatalyst platforms

dotnet/runtime#80689

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

When to consider using HybridGlobalization:

This option is most suitable for applications that cannot work in InvariantGlobalization mode and are using cultures which where trimmed from ICU data on mobile or want to load smaller ICU data file.

How to use HybridGlobalization:

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

Adventages

  • icudt.dat contains trimmed ICU data on mobile compared to desktop, while HybridGlobalization will call to Native API and get the information.
  • Some data that was missing in ICU ( for example CultureInfo.EnglishName, CultureInfo.NativeName), will work correctly using HybridGlobalization mode.
  • Loading smaller ICU data file

Limitations:

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

Final note

We would like to invite everyone to try out this new feature and file any discovered issues to help us improve the user experience further.

@karelz
Copy link
Member

karelz commented Jul 31, 2023

Re-adding feature we accidentally included in Preview 6 blog post and then removed: #8437 (comment)
cc @wfurt

Support for HTTPS proxy

dotnet/runtime#31113

While HttpClient supported various proxy types for a while, they all allows man-in-the-middle to see what site the client is connecting to. (even for HTTPS URIs) HTTPS proxy allows to create encrypted channel between client and the proxy so all the subsequent request can be handled with full privacy.

How to Use

for Unix
export all_proxy=https://x.x.x.x:3218 and set all_proxy=https://x.x.x.x:3218 for Windows. This can be also controlled programmatically via WebProxy class.

@eiriktsarpalis
Copy link
Member

System.Text.Json Improvements

JsonSourceGenerationOptionsAttribute feature parity dotnet/runtime#88753

Preview 7 sees the extension of JsonSourceGenerationOptionsAttribute so that it has feature parity with the JsonSerializerOptions class. It lets users specify serialization configuration at compile time:

[JsonSourceGenerationOptions(JsonSerializerDefaults.Web,
    AllowTrailingCommas = true,
    Converters = new[] { typeof(JsonStringEnumConverter<MyEnum>) },
    DefaultBufferSize =  1024,
    DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingDefault,
    DictionaryKeyPolicy = JsonKnownNamingPolicy.SnakeCaseUpper,
    IgnoreReadOnlyFields = true,
    IgnoreReadOnlyProperties = true,
    IncludeFields = true,
    MaxDepth = 1024,
    NumberHandling = JsonNumberHandling.WriteAsString,
    PreferredObjectCreationHandling = JsonObjectCreationHandling.Replace,
    PropertyNameCaseInsensitive = true,
    PropertyNamingPolicy = JsonKnownNamingPolicy.KebabCaseUpper,
    ReadCommentHandling = JsonCommentHandling.Skip,
    UnknownTypeHandling = JsonUnknownTypeHandling.JsonNode,
    UnmappedMemberHandling = JsonUnmappedMemberHandling.Disallow,
    WriteIndented = true)]
[JsonSerializable(typeof(MyPoco))]
public partial class MyContext : JsonSerializerContext { }

Which ensures that the generated MyContext.Default property is preconfigured with all the relevant options set.

Built-in support for Memory<T>/ReadOnlyMemory<T> dotnet/runtime#88713

The serializer now has built-in support for Memory<T> and ReadOnlyMemory<T> values, with semantics being equivalent to arrays: serializes to Base64 strings for Memory<byte>/ReadOnlyMemory<byte> values and JSON arrays for other types:

JsonSerializer.Serialize<Memory<int>>(new int[] { 1, 2, 3 }); // [1,2,3]
JsonSerializer.Serialize<ReadOnlyMemory<byte>>(new byte[] { 1, 2, 3 }); // "AQID"

Built-in support for Half, Int128 and UInt128 numeric types dotnet/runtime#88713

Console.WriteLine(JsonSerializer.Serialize(new object[] { Half.MaxValue, Int128.MaxValue, UInt128.MaxValue }));
// [65500,170141183460469231731687303715884105727,340282366920938463463374607431768211455]

Extending JsonIncludeAttribute and JsonConstructorAttribute to non-public members dotnet/runtime#88452

It is now possible to opt non-public members into the serialization contract for a given type using JsonInclude and JsonConstructor attribute annotations:

string json = JsonSerializer.Serialize(new MyPoco(42)); // {"X":42}
JsonSerializer.Deserialize<MyPoco>(json); 

public class MyPoco
{
    [JsonConstructor]
    internal MyPoco(int x) => X = x;

    [JsonInclude]
    internal int X { get; }
}

IJsonTypeInfoResolver.WithAddedModifier extension method dotnet/runtime#88255

This new extension method lets users easily introduce modifications to the serialization contracts of arbitrary IJsonTypeInfoResolver instances:

var options = new JsonSerializerOptions
{
    TypeInfoResolver = MyContext.Default
        .WithAddedModifier(static typeInfo =>
        {
            foreach (JsonPropertyInfo prop in typeInfo.Properties)
            {
                prop.Name = prop.Name.ToUpperInvariant();
            }
        })
};

JsonSerializer.Serialize(new MyPoco(42), options); // {"VALUE":42}

public record MyPoco(int value);

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

Additional JsonNode functionality dotnet/runtime#87381

The JsonNode APIs now come with the following new methods:

namespace System.Text.Json.Nodes;

public partial class JsonNode
{
    // Creates a deep clone of the current node and all its descendants.
    public JsonNode DeepClone();

    // Returns true if the two nodes are equivalent JSON representations.
    public static bool DeepEquals(JsonNode? node1, JsonNode? node2);

    // Determines the JsonValueKind of the current node.
    public JsonValueKind GetValueKind(JsonSerializerOptions options = null);

    // If node is the value of a property in the parent object, returns its name. Throws InvalidOperationException otherwise.
    public string GetPropertyName();
   
    // If node is the element of a parent JsonArray, returns its index. Throws InvalidOperationException otherwise.
    public int GetElementIndex();

    // Replaces this instance with a new value, updating the parent object/array accordingly.
    public void ReplaceWith<T>(T value);
}

public partial class JsonArray
{
    // Returns an IEnumerable<T> view of the current array.
    public IEnumerable<T> GetValues<T>();
}

Credit to @RaymondHuy for contributing the implementation.

@JulieLeeMSFT
Copy link
Member

JulieLeeMSFT commented Aug 2, 2023

CodeGen

Community PRs (Many thanks to JIT community contributors!)

  • @khushal1996 made the first contribution to dotnet and optimized scalar conversions with AVX512 in PR#84384.
  • @MichalPetryka made 5 contributions in Preview 7. Please see a few PRs to highlight below:
    • PR#87374 fixed an issue that might lead to undefined behavior when using Unsafe.As on the single dimensional arrays by intrinsifying Array typed GetArrayDataReference.
    • PR#88073 converted Volatile to JIT intrinsics that removed VM implementation and improved codegen.
  • @Ruihan-Yin enabled embedded broadcast for binary operators on AVX-512 system in PR#87946. The benefit of this PR is that it increases data locality and minimizes the impact to the cache. The supported operators include below ops:
    and, andn, or, xor,
    min, max,
    div, mul, mull, sub,
    variable shiftleftlogical/rightarithmetic/rightlogical
    

Struct Physical Promotion

PR#88090 enabled a new physical promotion optimization pass that generalizes the JIT's ability to promote struct variables. This optimization (also commonly called scalar replacement of aggregates) replaces the fields of struct variables by primitive variables that the JIT is then able to reason about and optimize more precisely.

The JIT already supported this optimization but with several large limitations. Some of the largest limitations of the JIT's existing support was that it was only supported for structs with 4 or fewer fields, and only if each field was of a primitive type, or a very simple struct wrapping a primitive type. Physical promotion removes these limitations which fixes a number of long-standing JIT issues (see the PR for some of the issues closed).

As an example: foreach over a Dictionary<TKey, TValue> involves a struct enumerator with 5 fields, so before this change the JIT was not able to promote and reason about this enumerator. The JIT was similarly not able to reason about foreach over a List<(int, int)> (the struct enumerator only has 4 fields, but one field is a (int, int) tuple). These cases are both covered by physical promotion in preview 7 which means that simple benchmarks like

private readonly Dictionary<int, int> _dictionary = new(Enumerable.Range(0, 10000).Select(i => KeyValuePair.Create(i, i)));

[Benchmark]
public int SumDict()
{
    int sum = 0;
    foreach ((int key, int value) in _dictionary)
    {
        sum += key;
        sum += value;
    }
    return sum;
}

private readonly List<(int, int)> _list = Enumerable.Range(0, 10000).Select(i => (i, i)).ToList();

[Benchmark]
public int SumList()
{
    int sum = 0;
    foreach ((int key, int value) in _list)
    {
        sum += key;
        sum += value;
    }
    return sum;
}

see significant improvements, here measured on an i9-10885H:

Method Runtime Mean Error StdDev Median Ratio RatioSD
SumDict .NET 7.0 24.936 us 0.4918 us 0.8613 us 25.350 us 1.00 0.00
SumDict .NET 8.0 preview 7 11.027 us 0.2180 us 0.4149 us 11.249 us 0.44 0.01
SumList .NET 7.0 15.847 us 0.3044 us 0.7582 us 15.794 us 1.00 0.00
SumList .NET 8.0 preview 7 6.038 us 0.1197 us 0.2033 us 6.130 us 0.39 0.02

@pchaurasia14
Copy link
Member

OpenFolderDialog in WPF

dotnet/wpf#7244

WPF now ships with new dialog box control - OpenFolderDialog which allows users to browse and select folders in their application. This reduces the need for external 3rd party dependency for supporting this usecase.
Special thanks to @miloush for contributing extensively to this feature!

How to use it ?

    OpenFolderDialog openFolderDialog = new OpenFolderDialog()
    {
        Title = "Select folder to open ...",
        InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles),
    };

    string folderName = "";
    if (openFolderDialog.ShowDialog() == true)
    {
        folderName = openFolderDialog.FolderName;
    }

@ericstj
Copy link
Member

ericstj commented Aug 4, 2023

Microsoft.Extensions.Hosting.IHostedLifecycleService

dotnet/runtime#87335

Hosted services now have more options for execution during the application lifecycle. IHostedService provided StartAsync and StopAsync. IHostedLifeCycleService provides an additional StartingAsync, StartedAsync, StoppingAsync, StoppedAsync - which run before and after the existing points respectively.

How to use it ?

IHostBuilder hostBuilder = new HostBuilder();
hostBuilder.ConfigureServices(services =>
{
    services.AddHostedService<MyService>();
}

using (IHost host = hostBuilder.Build())
{
    await host.StartAsync();
}

public class MyService : IHostedLifecycleService
{
    public Task StartingAsync(CancellationToken cancellationToken) => /* add logic here */ Task.CompletedTask;
    public Task StartAsync(CancellationToken cancellationToken) => /* add logic here */ Task.CompletedTask;
    public Task StartedAsync(CancellationToken cancellationToken) => /* add logic here */ Task.CompletedTask;
    public Task StopAsync(CancellationToken cancellationToken) => /* add logic here */ Task.CompletedTask;
    public Task StoppedAsync(CancellationToken cancellationToken) => /* add logic here */ Task.CompletedTask;
    public Task StoppingAsync(CancellationToken cancellationToken) => /* add logic here */ Task.CompletedTask;
}

@ericstj
Copy link
Member

ericstj commented Aug 4, 2023

Keyed services support in Microsoft.Extensions.DependencyInjection

dotnet/runtime#64427, dotnet/runtime#87183

Provides a means for registering and retrieving DI services using keys. Keys allow for scoping of registration and consumption of services. Support has been added to DI abstractions, as well as an implementation in the built in Microsoft.Extensions.DependencyInjection. See more detail in the linked issue.

How to use it?

using Microsoft.Extensions.Caching.Memory;
using Microsoft.Extensions.Options;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddSingleton<BigCacheConsumer>();
builder.Services.Addsingleton<SmallCacheConsumer>();

builder.Services.AddKeyedsingleton<IMemoryCache, BigCache>(“big“);
builder.Services.AddKeyedSingleton<IMemoryCache, SmallCache>("small“);

var app = builder.Build();

app.MapGet(/big", (BigCacheConsumer data) => data.GetData());
app.MapGet(“/small", (SmallCacheConsumer data) => data.GetData());

app.Run();

class BigCacheConsumer([FromKeyedServices("big“)] IMemoryCache cache)
{
    public object? GetData() => cache.Get("data");
}

class SmallCacheConsumer(IKeyedServiceProvider keyedServiceProvider)
{
    public object? GetData() => keyedServiceProvider.GetRequiredKeyedService<IMemoryCache>("small");
}

@ivdiazsa
Copy link
Member

ivdiazsa commented Aug 4, 2023

New Platforms for Docker ASP.NET Composite Images

dotnet/dotnet-docker#4710

In Preview 5, we released a new flavor of our ASP.NET Docker Images: The Composites. These were initially only available on Alpine Linux containers, so as part of the Preview 7 new features, we present to you two new flavors of the composite images:

  • Jammy Chiseled
  • Mariner Distroless

Here is the original description explaining what the composite images are in more detail, how they work, and where they can be acquired.

What are the composite images?

As part of the containerization performance efforts, we are now offering a new ASP.NET Alpine-based Docker image with a composite version of the runtime in Preview 5. This composite is built by compiling multiple MSIL assemblies into a single R2R output binary. Due to having these assemblies embedded into a single image, we save jitting time and thus boosting the startup performance of apps. The other big advantage of the composite over the regular ASP.NET image is that the composites have a smaller size on disk. However, all these benefits don't come without a caveat. Since composites have multiple assemblies embedded into one, they have tighter version coupling. This means the final app run cannot use custom versions of framework and/or ASP.NET binaries embedded into the composite one.

Where can we get the composite images?

As of now, the composite images are available as preview in under the mcr.microsoft.com/dotnet/nightly/aspnet repo. The tags are listed with the -composite suffix in the official nightly Dotnet Docker page.

@mungojam
Copy link

mungojam commented Aug 5, 2023

class SmallCacheConsumer(IKeyedServiceProvider keyedServiceProvider)
{
public object? GetData() => keyedServiceProvider.GetRequiredKeyedService("big");
}

Looks like a small typo at the end of this one, I assume you meant it to be "small", not "big"

@ericstj
Copy link
Member

ericstj commented Aug 7, 2023

Seems like a typo. Yes, change to small. I updated the sample. Pulled this from here, btw: https://twitter.com/davidfowl/status/1683956501570879489

@JonDouglas
Copy link
Collaborator

Complete via https://devblogs.microsoft.com/dotnet/announcing-dotnet-8-preview-7/

@Rob-Hague
Copy link

Complete via https://devblogs.microsoft.com/dotnet/announcing-dotnet-8-preview-7/

fyi this and the asp.net core blog appear on https://devblogs.microsoft.com/dotnet but not https://devblogs.microsoft.com. Not sure if intended

@mairaw
Copy link
Contributor

mairaw commented Aug 21, 2023

You're right @Rob-Hague. I'll report that to the devblogs team.

@mairaw
Copy link
Contributor

mairaw commented Oct 19, 2023

@Rob-Hague forgot to report earlier that this issue has been fixed. The posts are now at https://devblogs.microsoft.com/page/30 and https://devblogs.microsoft.com/page/31.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests