{"id":46801,"date":"2023-08-08T10:05:00","date_gmt":"2023-08-08T17:05:00","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/dotnet\/?p=46801"},"modified":"2024-12-13T14:18:39","modified_gmt":"2024-12-13T22:18:39","slug":"announcing-dotnet-8-preview-7","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/dotnet\/announcing-dotnet-8-preview-7\/","title":{"rendered":"Announcing .NET 8 Preview 7"},"content":{"rendered":"<p>.NET 8 Preview 7 is now available. We&#8217;re already at the final preview release for .NET 8 and will now shift to release candidates. Almost all new features for the release are in their final shape. System.Text.Json and codegen have the biggest changes in this build. You&#8217;ll want to take a look at those. Now is great time to pick up and test .NET 8 if you haven&#8217;t yet.<\/p>\n<p>The dates for <a href=\"https:\/\/dotnetconf.net\/\">.NET Conf 2023<\/a> have been announced! Join us November 14-16, 2023 to celebrate the .NET 8 release!<\/p>\n<p><a href=\"https:\/\/dotnet.microsoft.com\/download\/dotnet\/8.0\">Download .NET 8 Preview 7<\/a> for Linux, macOS, and Windows.<\/p>\n<ul>\n<li><a href=\"https:\/\/dotnet.microsoft.com\/download\/dotnet\/8.0\">Installers and binaries<\/a><\/li>\n<li><a href=\"https:\/\/hub.docker.com\/_\/microsoft-dotnet-aspnet\/\">Container images<\/a><\/li>\n<li><a href=\"https:\/\/github.com\/dotnet\/core\/tree\/main\/release-notes\/8.0\">Release notes<\/a><\/li>\n<li><a href=\"https:\/\/learn.microsoft.com\/dotnet\/core\/compatibility\/8.0?toc=%2Fdotnet%2Ffundamentals%2Ftoc.json&amp;bc=%2Fdotnet%2Fbreadcrumb%2Ftoc.json\">Breaking changes<\/a><\/li>\n<li><a href=\"https:\/\/github.com\/dotnet\/core\/blob\/main\/release-notes\/8.0\/known-issues.md\">Known issues<\/a><\/li>\n<li><a href=\"https:\/\/github.com\/dotnet\/core\/issues\">GitHub issue tracker<\/a><\/li>\n<\/ul>\n<blockquote><p>Note: .NET 8 Preview 7 is incompatible with <a href=\"https:\/\/marketplace.visualstudio.com\/items?itemName=ms-dotnettools.csdevkit\">C# Dev Kit<\/a>. We&#8217;re in the process of resolving it and will update this <a href=\"https:\/\/github.com\/microsoft\/vscode-dotnettools\/issues\/318\">tracking bug<\/a> with progress.<\/p><\/blockquote>\n<p>There are several exciting posts you should check out as well:<\/p>\n<ul>\n<li><a href=\"https:\/\/devblogs.microsoft.com\/dotnet\/asp-net-core-updates-in-dotnet-8-preview-7\">ASP.NET Core<\/a> describes new token antiforgery middleware with API and Blazor support, identity API updates, native AOT improvements, and more.<\/li>\n<li><a href=\"https:\/\/devblogs.microsoft.com\/dotnet\/announcing-dotnet-maui-in-dotnet-8-preview-7\">.NET MAUI<\/a> includes enhanced UI Control functionality as well as bug fixes and performance improvements.<\/li>\n<li><a href=\"https:\/\/devblogs.microsoft.com\/visualstudio\/visual-studio-2022-17-7-now-available\">Visual Studio 2022 17.7<\/a> is now generally available, and includes a number of features for .NET developers including <a href=\"https:\/\/devblogs.microsoft.com\/visualstudio\/visual-studio-2022-17-7-now-available#auto-decompilation-for-external-net-code\">auto-decompilation for External .NET Code<\/a> and <a href=\"https:\/\/devblogs.microsoft.com\/visualstudio\/visual-studio-2022-17-7-now-available#new-auto-insights-for-the-cpu-usage-tool\">new Auto Insights for the CPU Usage Tool<\/a>.\n<a href=\"https:\/\/learn.microsoft.com\/dotnet\/core\/whats-new\/dotnet-8\">What&#8217;s New in .NET 8<\/a> describes all the new features in .NET 8. For a broader view of the platform, read <a href=\"https:\/\/devblogs.microsoft.com\/dotnet\/why-dotnet\/\">Why .NET?<\/a>.<\/li>\n<\/ul>\n<h2>System.Text.Json improvements<\/h2>\n<p>This release includes several new improvements to <a href=\"https:\/\/learn.microsoft.com\/dotnet\/standard\/serialization\/system-text-json\/how-to\">System.Text.Json<\/a>.<\/p>\n<h3><code>JsonSourceGenerationOptionsAttribute<\/code> feature parity https:\/\/github.com\/dotnet\/runtime\/pull\/88753<\/h3>\n<p><a href=\"https:\/\/learn.microsoft.com\/dotnet\/api\/system.text.json.serialization.jsonsourcegenerationoptionsattribute\"><code>JsonSourceGenerationOptionsAttribute<\/code><\/a> now has feature parity with the <a href=\"https:\/\/learn.microsoft.com\/dotnet\/api\/system.text.json.jsonserializeroptions\"><code>JsonSerializerOptions<\/code><\/a> class, enabling specifing serialization configuration at compile time.<\/p>\n<p>An example <code>JsonSourceGenerationOptions<\/code> instance.<\/p>\n<pre><code class=\"language-C#\">[JsonSourceGenerationOptions(JsonSerializerDefaults.Web,\r\n    AllowTrailingCommas = true,\r\n    Converters = new[] { typeof(JsonStringEnumConverter&lt;MyEnum&gt;) },\r\n    DefaultBufferSize =  1024,\r\n    DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingDefault,\r\n    DictionaryKeyPolicy = JsonKnownNamingPolicy.SnakeCaseUpper,\r\n    IgnoreReadOnlyFields = true,\r\n    IgnoreReadOnlyProperties = true,\r\n    IncludeFields = true,\r\n    MaxDepth = 1024,\r\n    NumberHandling = JsonNumberHandling.WriteAsString,\r\n    PreferredObjectCreationHandling = JsonObjectCreationHandling.Replace,\r\n    PropertyNameCaseInsensitive = true,\r\n    PropertyNamingPolicy = JsonKnownNamingPolicy.KebabCaseUpper,\r\n    ReadCommentHandling = JsonCommentHandling.Skip,\r\n    UnknownTypeHandling = JsonUnknownTypeHandling.JsonNode,\r\n    UnmappedMemberHandling = JsonUnmappedMemberHandling.Disallow,\r\n    WriteIndented = true)]\r\n[JsonSerializable(typeof(MyPoco))]\r\npublic partial class MyContext : JsonSerializerContext { }<\/code><\/pre>\n<p>This example generates a <code>MyContext.Default<\/code> property that is preconfigured with all the relevant options set, while taking advantage of source generation.<\/p>\n<h3>Built-in support for <code>Memory&lt;T&gt;<\/code>\/<code>ReadOnlyMemory&lt;T&gt;<\/code><\/h3>\n<p>The serializer now has <a href=\"https:\/\/github.com\/dotnet\/runtime\/pull\/88713\">built-in support for <code>Memory&lt;T&gt;<\/code> and <code>ReadOnlyMemory&lt;T&gt;<\/code> values<\/a>, with semantics being equivalent to arrays:<\/p>\n<ul>\n<li>Serializes to <a href=\"https:\/\/en.wikipedia.org\/wiki\/Base64\">Base64<\/a> strings for <code>Memory&lt;byte&gt;<\/code>\/<code>ReadOnlyMemory&lt;byte&gt;<\/code> values<\/li>\n<li>Serializes to JSON arrays for other types<\/li>\n<\/ul>\n<p>You can see that behavior in the folowing examples (the second resulting in a Base64-encoded string).<\/p>\n<pre><code class=\"language-C#\">JsonSerializer.Serialize&lt;Memory&lt;int&gt;&gt;(new int[] { 1, 2, 3 }); \/\/ [1,2,3]\r\nJsonSerializer.Serialize&lt;ReadOnlyMemory&lt;byte&gt;&gt;(new byte[] { 1, 2, 3 }); \/\/ \"AQID\"<\/code><\/pre>\n<h3>Built-in support for <code>Half<\/code>, <code>Int128<\/code> and <code>UInt128<\/code> numeric types<\/h3>\n<p><a href=\"https:\/\/learn.microsoft.com\/dotnet\/api\/system.half\"><code>Half<\/code><\/a>, <a href=\"https:\/\/learn.microsoft.com\/dotnet\/api\/system.int128\"><code>Int128<\/code><\/a>, and <a href=\"https:\/\/learn.microsoft.com\/dotnet\/api\/system.uint128\"><code>UInt128<\/code><\/a> types now have <a href=\"https:\/\/github.com\/dotnet\/runtime\/pull\/88713\">built-in serialization support<\/a>.<\/p>\n<pre><code class=\"language-C#\">Console.WriteLine(JsonSerializer.Serialize(new object[] { Half.MaxValue, Int128.MaxValue, UInt128.MaxValue }));\r\n\/\/ [65500,170141183460469231731687303715884105727,340282366920938463463374607431768211455]<\/code><\/pre>\n<h3>Extending <code>JsonIncludeAttribute<\/code> and <code>JsonConstructorAttribute<\/code> to non-public members<\/h3>\n<p>It is now possible to <a href=\"https:\/\/github.com\/dotnet\/runtime\/pull\/88452\">opt non-public members into the serialization contract<\/a> for a given type using <a href=\"https:\/\/learn.microsoft.com\/dotnet\/api\/system.text.json.serialization.jsonincludeattribute\"><code>JsonInclude<\/code><\/a> and <a href=\"https:\/\/learn.microsoft.com\/dotnet\/api\/system.text.json.serialization.jsonconstructorattribute\"><code>JsonConstructor<\/code><\/a> attribute annotations.<\/p>\n<pre><code class=\"language-C#\">string json = JsonSerializer.Serialize(new MyPoco(42)); \/\/ {\"X\":42}\r\nJsonSerializer.Deserialize&lt;MyPoco&gt;(json); \r\n\r\npublic class MyPoco\r\n{\r\n    [JsonConstructor]\r\n    internal MyPoco(int x) =&gt; X = x;\r\n\r\n    [JsonInclude]\r\n    internal int X { get; }\r\n}<\/code><\/pre>\n<h3><code>IJsonTypeInfoResolver.WithAddedModifier<\/code> extension method<\/h3>\n<p>This <a href=\"https:\/\/github.com\/dotnet\/runtime\/pull\/88255\">new extension method<\/a> enables making modifications to serialization contracts of arbitrary <code>IJsonTypeInfoResolver<\/code> instances:<\/p>\n<pre><code class=\"language-C#\">var options = new JsonSerializerOptions\r\n{\r\n    TypeInfoResolver = MyContext.Default\r\n        .WithAddedModifier(static typeInfo =&gt;\r\n        {\r\n            foreach (JsonPropertyInfo prop in typeInfo.Properties)\r\n            {\r\n                prop.Name = prop.Name.ToUpperInvariant();\r\n            }\r\n        })\r\n};\r\n\r\nJsonSerializer.Serialize(new MyPoco(42), options); \/\/ {\"VALUE\":42}\r\n\r\npublic record MyPoco(int value);\r\n\r\n[JsonSerializable(typeof(MyPoco))]\r\npublic partial class MyContext : JsonSerializerContext { }<\/code><\/pre>\n<h3>Additional JsonNode functionality<\/h3>\n<p><code>JsonNode<\/code> <a href=\"https:\/\/github.com\/dotnet\/runtime\/pull\/87381\">has significantly updated functionality<\/a>.<\/p>\n<p>For example, deep cloning.<\/p>\n<pre><code class=\"language-C#\">JsonNode node = JsonNode.Parse(\"{\\\"Prop\\\":{\\\"NestedProp\\\":42}}\");\r\nJsonNode other = node.DeepClone();\r\nbool same = JsonNode.DeepEquals(node, other); \/\/ true<\/code><\/pre>\n<p>Support for <code>IEnumerable<\/code>.<\/p>\n<pre><code class=\"language-csharp\">JsonArray jsonArray = new JsonArray(1, 2, 3, 2);\r\n\r\n\/\/ With the proposed GetValues this is simpler:\r\nIEnumerable&lt;int&gt; values = jsonArray.GetValues&lt;int&gt;().Where(i =&gt; i == 2);<\/code><\/pre>\n<p>Credit to <a href=\"https:\/\/github.com\/RaymondHuy\">@RaymondHuy<\/a> for contributing the implementation.<\/p>\n<h2>Microsoft.Extensions.Hosting.IHostedLifecycleService<\/h2>\n<p><a href=\"https:\/\/github.com\/dotnet\/runtime\/pull\/87335\">Hosted services now have more options<\/a> for execution during the application lifecycle. <code>IHostedService<\/code> provided <code>StartAsync<\/code> and <code>StopAsync<\/code>. <code>IHostedLifeCycleService<\/code> provides an additional <code>StartingAsync<\/code>, <code>StartedAsync<\/code>, <code>StoppingAsync<\/code>, <code>StoppedAsync<\/code> &#8211; which run before and after the existing points respectively.<\/p>\n<h3>Using <code>IHostedLifecycleService<\/code><\/h3>\n<pre><code class=\"language-cs\">IHostBuilder hostBuilder = new HostBuilder();\r\nhostBuilder.ConfigureServices(services =&gt;\r\n{\r\n    services.AddHostedService&lt;MyService&gt;();\r\n}\r\n\r\nusing (IHost host = hostBuilder.Build())\r\n{\r\n    await host.StartAsync();\r\n}\r\n\r\npublic class MyService : IHostedLifecycleService\r\n{\r\n    public Task StartingAsync(CancellationToken cancellationToken) =&gt; \/* add logic here *\/ Task.CompletedTask;\r\n    public Task StartAsync(CancellationToken cancellationToken) =&gt; \/* add logic here *\/ Task.CompletedTask;\r\n    public Task StartedAsync(CancellationToken cancellationToken) =&gt; \/* add logic here *\/ Task.CompletedTask;\r\n    public Task StopAsync(CancellationToken cancellationToken) =&gt; \/* add logic here *\/ Task.CompletedTask;\r\n    public Task StoppedAsync(CancellationToken cancellationToken) =&gt; \/* add logic here *\/ Task.CompletedTask;\r\n    public Task StoppingAsync(CancellationToken cancellationToken) =&gt; \/* add logic here *\/ Task.CompletedTask;\r\n}<\/code><\/pre>\n<h2>Keyed services support in Microsoft.Extensions.DependencyInjection<\/h2>\n<p><a href=\"https:\/\/github.com\/dotnet\/runtime\/pull\/87183\">Provides a means for registering and retrieving Dependency Injection (DI) services<\/a> 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.<\/p>\n<h3>Using Keyed services<\/h3>\n<pre><code class=\"language-csharp\">using Microsoft.Extensions.Caching.Memory;\r\nusing Microsoft.Extensions.Options;\r\n\r\nvar builder = WebApplication.CreateBuilder(args);\r\n\r\nbuilder.Services.AddSingleton&lt;BigCacheConsumer&gt;();\r\nbuilder.Services.Addsingleton&lt;SmallCacheConsumer&gt;();\r\n\r\nbuilder.Services.AddKeyedsingleton&lt;IMemoryCache, BigCache&gt;(\"big\");\r\nbuilder.Services.AddKeyedSingleton&lt;IMemoryCache, SmallCache&gt;(\"small\");\r\n\r\nvar app = builder.Build();\r\n\r\napp.MapGet(\"\/big\", (BigCacheConsumer data) =&gt; data.GetData());\r\napp.MapGet(\"\/small\", (SmallCacheConsumer data) =&gt; data.GetData());\r\n\r\napp.Run();\r\n\r\nclass BigCacheConsumer([FromKeyedServices(\"big\")] IMemoryCache cache)\r\n{\r\n    public object? GetData() =&gt; cache.Get(\"data\");\r\n}\r\n\r\nclass SmallCacheConsumer(IKeyedServiceProvider keyedServiceProvider)\r\n{\r\n    public object? GetData() =&gt; keyedServiceProvider.GetRequiredKeyedService&lt;IMemoryCache&gt;(\"small\");\r\n}<\/code><\/pre>\n<h2>HTTPS proxy<\/h2>\n<p>You can now <a href=\"https:\/\/github.com\/dotnet\/runtime\/issues\/31113\">use an HTTPS proxy<\/a> with <code>HttpClient<\/code>. This can be a significant improvement to protect against <a href=\"https:\/\/en.wikipedia.org\/wiki\/Man-in-the-middle_attack\">interception attacks<\/a>.<\/p>\n<p><a href=\"https:\/\/en.wikipedia.org\/wiki\/HTTPS\">HTTPS<\/a> is pervasive, effectively a requirement for public internet websites. However, there are plenty of scenarios where raw (unencrypted) HTTP is a fine choice. Those scenarios often pair well with a <a href=\"https:\/\/en.wikipedia.org\/wiki\/Proxy_server\">proxy<\/a>. An HTTPS proxy establishes an encrypted channel between client and the proxy, establishing complete communication privacy.<\/p>\n<h3>HTTPS proxy usage<\/h3>\n<p>Proxy usage can be also controlled programmatically via <a href=\"https:\/\/learn.microsoft.com\/dotnet\/api\/system.net.webproxy\">WebProxy<\/a> class.<\/p>\n<p>It can also be controlled via the <code>all_proxy<\/code> environment variable:<\/p>\n<p>For example, with Docker:<\/p>\n<pre><code class=\"language-bash\">ENV all_proxy=https:\/\/x.x.x.x:3218<\/code><\/pre>\n<h2><code>OpenFolderDialog<\/code> in WPF<\/h2>\n<p>WPF now includes <a href=\"https:\/\/github.com\/dotnet\/wpf\/pull\/7244\"><code>OpenFolderDialog<\/code><\/a> which allows users to browse and select folders in their application.<\/p>\n<p>Credit to <a href=\"https:\/\/github.com\/miloush\">@miloush<\/a> for contributing extensively to this feature!<\/p>\n<h3>How to use <code>OpenFolderDialog<\/code><\/h3>\n<pre><code class=\"language-cs\">OpenFolderDialog openFolderDialog = new OpenFolderDialog()\r\n{\r\n    Title = \"Select folder to open ...\",\r\n    InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles),\r\n};\r\n\r\nstring folderName = \"\";\r\nif (openFolderDialog.ShowDialog() == true)\r\n{\r\n    folderName = openFolderDialog.FolderName;\r\n}<\/code><\/pre>\n<h2>HybridGlobalization mode on iOS\/tvOS\/MacCatalyst platforms<\/h2>\n<p>Mobile apps can now use a <a href=\"https:\/\/github.com\/dotnet\/runtime\/issues\/80689\">new globalization mode<\/a> that uses a <strong>34%<\/strong> smaller <a href=\"https:\/\/unicode-org.github.io\/icu\/\">ICU<\/a> bundle, reducing the size of apps. In hybrid mode, globalization data is partially pulled from the ICU bundle and partially from OS APIs. It supports all the <a href=\"https:\/\/github.com\/dotnet\/icu\/blob\/dotnet\/main\/icu-filters\/icudt_mobile.json\">locales supported by Mobile<\/a>.<\/p>\n<p><a href=\"https:\/\/github.com\/dotnet\/runtime\/blob\/main\/docs\/design\/features\/globalization-invariant-mode.md\">InvariantGlobalization mode<\/a> was created to eliminate the dependency on ICU (which comes with a large size cost). This mode comes with a significant trade-off, as most globalization functionality is no longer supported. This new feature is a middle ground, significantly reducing size (34% reduction) while maintaining globalization functionality.<\/p>\n<h3>How to use HybridGlobalization<\/h3>\n<p>Set the <code>HybridGlobalization<\/code> MsBuild property:<\/p>\n<pre><code class=\"language-xml\">&lt;HybridGlobalization&gt;true&lt;\/HybridGlobalization&gt;<\/code><\/pre>\n<p>It will load icudt_hybrid.dat file instead of icudt.dat.<\/p>\n<h3>Differences from ICU<\/h3>\n<ul>\n<li>Some data that was missing in ICU ( for example CultureInfo.EnglishName, CultureInfo.NativeName), will work correctly using HybridGlobalization mode.<\/li>\n<li>Some APIs are not supported or have different behavior.<\/li>\n<\/ul>\n<p>To make sure your application will not be affected, read the section <a href=\"https:\/\/github.com\/dotnet\/runtime\/blob\/main\/docs\/design\/features\/globalization-hybrid-mode.md\">Behavioral differences for OSX<\/a>.<\/p>\n<h2>CodeGen<\/h2>\n<p>The following improvements were made to code generation.<\/p>\n<h3>Community PRs<\/h3>\n<ul>\n<li><a href=\"https:\/\/github.com\/khushal1996\">@khushal1996<\/a> made their first contribution to dotnet and optimized scalar conversions with AVX512 in <a href=\"https:\/\/github.com\/dotnet\/runtime\/pull\/84384\">dotnet\/runtime #84384<\/a>.<\/li>\n<li><a href=\"https:\/\/github.com\/MichalPetryka\">@MichalPetryka<\/a> made <a href=\"https:\/\/github.com\/dotnet\/runtime\/pulls?q=is%3Apr+is%3Amerged+label%3Aarea-CodeGen-coreclr+closed%3A2023-06-22..2023-07-17++-milestone%3A7.0.x+author%3AMichalPetryka+\">5 contributions<\/a> in Preview 7. Please see a few PRs to highlight below:\n<ul>\n<li><a href=\"https:\/\/github.com\/dotnet\/runtime\/pull\/87374\">dotnet\/runtime #87374<\/a> fixed an issue that might lead to undefined behavior when using Unsafe.As on the single dimensional arrays by intrinsifying <code>Array<\/code> typed <code>GetArrayDataReference<\/code>.<\/li>\n<li><a href=\"https:\/\/github.com\/dotnet\/runtime\/pull\/88073\">dotnet\/runtime #88073<\/a> converted <code>Volatile<\/code> to JIT intrinsics that removed VM implementation and improved codegen.<\/li>\n<\/ul>\n<\/li>\n<li><a href=\"https:\/\/github.com\/Ruihan-Yin\">@Ruihan-Yin<\/a> enabled embedded broadcast for binary operators on AVX-512 system in <a href=\"https:\/\/github.com\/dotnet\/runtime\/pull\/87946\">dotnet\/runtime #87946<\/a>. The benefit of this PR is that it increases data locality and minimizes the impact to the cache.The supported operators follow:\n<pre><code class=\"language-text\">and, andn, or, xor,\r\nmin, max,\r\ndiv, mul, mull, sub,\r\nvariable shiftleftlogical\/rightarithmetic\/rightlogical<\/code><\/pre>\n<\/li>\n<\/ul>\n<h3>Struct Physical Promotion<\/h3>\n<p><a href=\"https:\/\/github.com\/dotnet\/runtime\/pull\/88090\">dotnet\/runtime #88090<\/a> enables a new physical promotion optimization pass that generalizes the JIT&#8217;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.<\/p>\n<p>The JIT already supported this optimization but with several large limitations. Some of the largest limitations of the JIT&#8217;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).<\/p>\n<p>As an example: <code>foreach<\/code> over a <code>Dictionary&lt;TKey, TValue&gt;<\/code> 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 <code>foreach<\/code> over a <code>List&lt;(int, int)&gt;<\/code> (the struct enumerator only has 4 fields, but one field is a <code>(int, int)<\/code> tuple). These cases (and others like it) hae been resolved.<\/p>\n<p>Consider the following benchmarks.<\/p>\n<pre><code class=\"language-csharp\">private readonly Dictionary&lt;int, int&gt; _dictionary = new(Enumerable.Range(0, 10000).Select(i =&gt; KeyValuePair.Create(i, i)));\r\n\r\n[Benchmark]\r\npublic int SumDict()\r\n{\r\n    int sum = 0;\r\n    foreach ((int key, int value) in _dictionary)\r\n    {\r\n        sum += key;\r\n        sum += value;\r\n    }\r\n    return sum;\r\n}\r\n\r\nprivate readonly List&lt;(int, int)&gt; _list = Enumerable.Range(0, 10000).Select(i =&gt; (i, i)).ToList();\r\n\r\n[Benchmark]\r\npublic int SumList()\r\n{\r\n    int sum = 0;\r\n    foreach ((int key, int value) in _list)\r\n    {\r\n        sum += key;\r\n        sum += value;\r\n    }\r\n    return sum;\r\n}<\/code><\/pre>\n<p>The improvement is significant.<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/dotnet\/wp-content\/uploads\/sites\/10\/2023\/08\/dotnet8-p7-sumdict-sumlist-chart.svg\" alt=\"Chart showing performance improvements for SumDict and SumList operations\" \/><\/p>\n<table>\n<thead>\n<tr>\n<th>Method<\/th>\n<th>Runtime<\/th>\n<th style=\"text-align: right;\">Mean<\/th>\n<th style=\"text-align: right;\">Error<\/th>\n<th style=\"text-align: right;\">StdDev<\/th>\n<th style=\"text-align: right;\">Median<\/th>\n<th style=\"text-align: right;\">Ratio<\/th>\n<th style=\"text-align: right;\">RatioSD<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td>SumDict<\/td>\n<td>.NET 7.0<\/td>\n<td style=\"text-align: right;\">24.936 us<\/td>\n<td style=\"text-align: right;\">0.4918 us<\/td>\n<td style=\"text-align: right;\">0.8613 us<\/td>\n<td style=\"text-align: right;\">25.350 us<\/td>\n<td style=\"text-align: right;\">1.00<\/td>\n<td style=\"text-align: right;\">0.00<\/td>\n<\/tr>\n<tr>\n<td>SumDict<\/td>\n<td>.NET 8.0 preview 7<\/td>\n<td style=\"text-align: right;\">11.027 us<\/td>\n<td style=\"text-align: right;\">0.2180 us<\/td>\n<td style=\"text-align: right;\">0.4149 us<\/td>\n<td style=\"text-align: right;\">11.249 us<\/td>\n<td style=\"text-align: right;\">0.44<\/td>\n<td style=\"text-align: right;\">0.01<\/td>\n<\/tr>\n<tr>\n<td><\/td>\n<td><\/td>\n<td style=\"text-align: right;\"><\/td>\n<td style=\"text-align: right;\"><\/td>\n<td style=\"text-align: right;\"><\/td>\n<td style=\"text-align: right;\"><\/td>\n<td style=\"text-align: right;\"><\/td>\n<td style=\"text-align: right;\"><\/td>\n<\/tr>\n<tr>\n<td>SumList<\/td>\n<td>.NET 7.0<\/td>\n<td style=\"text-align: right;\">15.847 us<\/td>\n<td style=\"text-align: right;\">0.3044 us<\/td>\n<td style=\"text-align: right;\">0.7582 us<\/td>\n<td style=\"text-align: right;\">15.794 us<\/td>\n<td style=\"text-align: right;\">1.00<\/td>\n<td style=\"text-align: right;\">0.00<\/td>\n<\/tr>\n<tr>\n<td>SumList<\/td>\n<td>.NET 8.0 preview 7<\/td>\n<td style=\"text-align: right;\">6.038 us<\/td>\n<td style=\"text-align: right;\">0.1197 us<\/td>\n<td style=\"text-align: right;\">0.2033 us<\/td>\n<td style=\"text-align: right;\">6.130 us<\/td>\n<td style=\"text-align: right;\">0.39<\/td>\n<td style=\"text-align: right;\">0.02<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>Note: measured on an i9-10885H.<\/p>\n<h2>Containers<\/h2>\n<p>We&#8217;ve made some small adjustements to improve container images and container publishing.<\/p>\n<p><a href=\"https:\/\/github.com\/dotnet\/dotnet-docker\/discussions\/4784\">Alpine image dependencies have changed<\/a>, resulting in smaller images and fewer CVEs. This comes with a breaking change if you rely on Kerberos in these images, as the <code>krb5-libs<\/code> package is no longer installed.<\/p>\n<p><a href=\"https:\/\/github.com\/dotnet\/dotnet-docker\/discussions\/4739\">Ubuntu Chiseled images can now be scanned<\/a> with industry scanning tools. The addition of scanning support is the last step to offering full support for Ubuntu Chiseled images.<\/p>\n<p><a href=\"https:\/\/github.com\/dotnet\/sdk-container-builds\/issues\/483#issuecomment-1656742008\">Publishing images to Docker Hub<\/a> via <code>dotnet publish<\/code> now works as expected with <code>docker.io<\/code>.<\/p>\n<p><a href=\"https:\/\/github.com\/dotnet\/dotnet-docker\/pull\/4715\">The UID for <code>app<\/code> was changed<\/a> in Preview 6 and is now <a href=\"https:\/\/github.com\/dotnet\/sdk\/pull\/34128\">reflected in container images published via the .NET SDK<\/a>.<\/p>\n<h2>New Platforms for Docker ASP.NET Composite Container Images<\/h2>\n<p>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, <a href=\"https:\/\/github.com\/dotnet\/dotnet-docker\/pull\/4710\">we present to you two new flavors<\/a> of the composite images:<\/p>\n<ul>\n<li>Jammy Chiseled<\/li>\n<li>Mariner Distroless<\/li>\n<\/ul>\n<p>Here is the original description explaining what the composite images are in more detail, how they work, and where they can be acquired.<\/p>\n<h3>What are the composite images?<\/h3>\n<p>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&#8217;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.<\/p>\n<h3>Where can we get the composite images?<\/h3>\n<p>Composite images are available as preview in under the <code>mcr.microsoft.com\/dotnet\/aspnet<\/code> repo. The tags are listed with the <code>-composite<\/code> suffix in the <a href=\"https:\/\/hub.docker.com\/_\/microsoft-dotnet-aspnet\">official nightly Dotnet Docker page<\/a>.<\/p>\n<h2>Community Contributor<\/h2>\n<p>This month&#8217;s community contributor is Guillaume Delahaye.<\/p>\n<p>Hi, I am Guillaume Delahaye, I&#8217;m living in Lille, France, and working at AXA France as a technical leader in the field of customer identity access management. I\u2019m also a member of <a href=\"https:\/\/www.mtg-france.org\/\">Microsoft Tech Group France<\/a> \u2013 an association that brings together and supports local tech communities.<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/dotnet\/wp-content\/uploads\/sites\/10\/2023\/08\/community-contributor.jpeg\" width=\"250px\" \/><\/p>\n<p>&#8220;How did you start contributing to .NET?&#8221;<\/p>\n<p>In 2021, I came across a <a href=\"https:\/\/corewcf.github.io\/blog\/2021\/02\/19\/corewcf-ga-release\">blog post announcing the release of CoreWCF 0.1.0<\/a>, which intrigued me as I had been looking for a migration path to move WCF SOAP services to modern .NET. <a href=\"https:\/\/github.com\/CoreWCF\/CoreWCF\">CoreWCF<\/a> is a port to modern .NET of the server side part of WCF. I tested the library, browsed opened issues and decided to start contributing. I began by adding unit tests to cover internal APIs, so they can be exposed as public APIs, then I went to enhance the existing API introducing asynchronous overloads. I was pleasantly surprised to see how responsive the team was and how community contributions were welcomed. At the same time I started to join the project monthly community meetings to discuss features and their implementation. The team was very supportive and helped me to port a feature from the dotnet\/wcf repository. Next we focused on modernizing features to bring developers working on a CoreWCF application a similar experience to ASP.NET Core MVC. These features included the support of the Authorize attribute on ServiceContract\/OperationContract to secure services, and FromServices attribute support to inject services from DI using a source generator. Today, I\u2019m working on modernizing the CoreWCF API, introducing a new binding, maintaining the codebase, and I&#8217;m starting to contribute to other .NET repositories too. For me, contributing is a great experience, providing opportunities to share and learn.<\/p>\n<h2>Summary<\/h2>\n<p>The team has transitioned to working on quality and polish as we near the final release in November. Now is a great time to report any issues that you&#8217;ve noticed in Preview 7 and earlier builds. We&#8217;d also love to hear your reactions to using these features.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>.NET 8 Preview 7 is now available with improvements to type containers, JSON source generation, and CodeGen as well as new support for HTTPS proxy, WPF open folder dialog, and iOS hybrid globalization.<\/p>\n","protected":false},"author":1312,"featured_media":46848,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[685],"tags":[7701],"class_list":["post-46801","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-dotnet","tag-dotnet-8"],"acf":[],"blog_post_summary":"<p>.NET 8 Preview 7 is now available with improvements to type containers, JSON source generation, and CodeGen as well as new support for HTTPS proxy, WPF open folder dialog, and iOS hybrid globalization.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/posts\/46801","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/users\/1312"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/comments?post=46801"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/posts\/46801\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/media\/46848"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/media?parent=46801"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/categories?post=46801"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/tags?post=46801"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}