{"id":44755,"date":"2023-03-14T02:05:00","date_gmt":"2023-03-14T10:05:00","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/dotnet\/?p=44755"},"modified":"2023-03-15T10:00:54","modified_gmt":"2023-03-15T18:00:54","slug":"asp-net-core-updates-in-dotnet-8-preview-2","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/dotnet\/asp-net-core-updates-in-dotnet-8-preview-2\/","title":{"rendered":"ASP.NET Core updates in .NET 8 Preview 2"},"content":{"rendered":"<p><a href=\"https:\/\/devblogs.microsoft.com\/dotnet\/announcing-dotnet-8-preview-2\">.NET 8 Preview 2 is now available<\/a> and includes many great new improvements to ASP.NET Core.<\/p>\n<p>Here&#8217;s a summary of what&#8217;s new in this preview release:<\/p>\n<ul>\n<li>Blazor <code>QuickGrid<\/code> component<\/li>\n<li>Improved Blazor WebAssembly performance with the jiterpreter<\/li>\n<li>New analyzer to detect multiple <code>FromBody<\/code> attributes<\/li>\n<li>New APIs in <code>ProblemDetails<\/code> to support more resilient integrations<\/li>\n<li>New <code>IResettable<\/code> interface in <code>ObjectPool<\/code><\/li>\n<li>Performance improvements to named pipes transport<\/li>\n<\/ul>\n<p>For more details on the ASP.NET Core work planned for .NET 8 see the full <a href=\"https:\/\/aka.ms\/aspnet\/roadmap\">ASP.NET Core roadmap for .NET 8<\/a> on GitHub.<\/p>\n<h2>Get started<\/h2>\n<p>To get started with ASP.NET Core in .NET 8 Preview 2, <a href=\"https:\/\/dotnet.microsoft.com\/next\">install the .NET 8 SDK<\/a>.<\/p>\n<p>If you&#8217;re on Windows using Visual Studio, we recommend installing the latest <a href=\"https:\/\/visualstudio.com\/preview\">Visual Studio 2022 preview<\/a>. Visual Studio for Mac support for .NET 8 previews isn\u2019t available at this time.<\/p>\n<h2>Upgrade an existing project<\/h2>\n<p>To upgrade an existing ASP.NET Core app from .NET 8 Preview 1 to .NET 8 Preview 2:<\/p>\n<ul>\n<li>Update the target framework of your app to <code>net8.0<\/code>.<\/li>\n<li>Update all Microsoft.AspNetCore.* package references to <code>8.0.0-preview.2.*<\/code>.<\/li>\n<li>Update all Microsoft.Extensions.* package references to <code>8.0.0-preview.2.*<\/code>.<\/li>\n<\/ul>\n<p>See also the full list of <a href=\"https:\/\/docs.microsoft.com\/dotnet\/core\/compatibility\/8.0#aspnet-core\">breaking changes<\/a> in ASP.NET Core for .NET 8.<\/p>\n<h2>Blazor <code>QuickGrid<\/code> component<\/h2>\n<p>The Blazor <code>QuickGrid<\/code> component is now part of .NET 8! <code>QuickGrid<\/code> is a high performance grid component for displaying data in tabular form. <code>QuickGrid<\/code> is built to be a simple and convenient way to display your data, while still providing powerful features like sorting, filtering, paging, and virtualization.<\/p>\n<p>To get started with <code>QuickGrid<\/code>:<\/p>\n<ol>\n<li>\n<p>Add reference to the Microsoft.AspNetCore.Components.QuickGrid package.<\/p>\n<pre><code class=\"language-console\">dotnet add package Microsoft.AspNetCore.Components.QuickGrid --prerelease<\/code><\/pre>\n<\/li>\n<li>\n<p>Add the following Razor code to render a very simple grid.<\/p>\n<pre><code class=\"language-razor\">&lt;QuickGrid Items=\"@people\"&gt;\n    &lt;PropertyColumn Property=\"@(p =&gt; p.PersonId)\" Title=\"ID\" Sortable=\"true\" \/&gt;\n    &lt;PropertyColumn Property=\"@(p =&gt; p.Name)\" Title=\"Name\" Sortable=\"true\" \/&gt;\n    &lt;PropertyColumn Property=\"@(p =&gt; p.BirthDate)\" Title=\"Birth date\" Format=\"yyyy-MM-dd\" Sortable=\"true\" \/&gt;\n&lt;\/QuickGrid&gt;\n\n@code {\n    record Person(int PersonId, string Name, DateOnly BirthDate);\n\n    IQueryable&lt;Person&gt; people = new[]\n    {\n        new Person(10895, \"Jean Martin\", new DateOnly(1985, 3, 16)),\n        new Person(10944, \"Ant\u00f3nio Langa\", new DateOnly(1991, 12, 1)),\n        new Person(11203, \"Julie Smith\", new DateOnly(1958, 10, 10)),\n        new Person(11205, \"Nur Sari\", new DateOnly(1922, 4, 27)),\n        new Person(11898, \"Jose Hernandez\", new DateOnly(2011, 5, 3)),\n        new Person(12130, \"Kenji Sato\", new DateOnly(2004, 1, 9)),\n    }.AsQueryable();\n}<\/code><\/pre>\n<p><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/dotnet\/wp-content\/uploads\/sites\/10\/2023\/03\/quickgrid.png\" alt=\"QuickGrid\" \/><\/p>\n<\/li>\n<\/ol>\n<p>You can see various examples of <code>QuickGrid<\/code> in action on the <a href=\"https:\/\/aka.ms\/blazor\/quickgrid\">QuickGrid demo site<\/a>.<\/p>\n<p><code>QuickGrid<\/code> was originally introduced as an experimental package based on .NET 7. As part of bringing <code>QuickGrid<\/code> into .NET 8 we&#8217;ve made some changes and improvements to the API. To update an existing Blazor app that uses <code>QuickGrid<\/code> to the .NET 8 version, you may need to make the following adjustments:<\/p>\n<ul>\n<li>Rename the <code>Value<\/code> attribute on the <code>Paginator<\/code> component to <code>State<\/code><\/li>\n<li>Rename the <code>IsDefaultSort<\/code> attribute on columns to <code>InitialSortDirection<\/code> and add <code>IsDefaultSortColumn=true<\/code> to indicate the column should still be sorted by default.<\/li>\n<li>Remove the <code>ResizableColumns<\/code> attribute on <code>QuickGrid<\/code>. Built-in support for resizable columns was removed.<\/li>\n<\/ul>\n<h2>Improved Blazor WebAssembly performance with the jiterpreter<\/h2>\n<p>The jiterpreter is a new runtime feature in .NET 8 that enables partial JIT support in the .NET IL interpreter to achieve improved runtime performance.<\/p>\n<p>Blazor WebAssembly apps are able to run .NET code in browser thanks to a small .NET runtime implemented in WebAssembly that gets downloaded with the app. This runtime is a .NET IL interpreter that is fully functional, reasonably small in size, and allows for fast developer iteration, but lacks the runtime performance benefits of native code execution through just-in-time (JIT) compilation. JITing to WebAssembly requires creating new WebAssembly modules on the fly and instantiating them, which poses unique challenges for the runtime. Blazor WebAssembly apps can instead choose to compile ahead-of-time (AOT) to WebAssembly to improve runtime performance but at the expense of a much larger download size. Since some common .NET coding patterns are incompatible with AOT, the .NET IL interpreter is still needed as a fallback mechanism to maintain full functionality.<\/p>\n<p>The jiterpreter optimizes execution of interpreter bytecodes by replacing them with tiny blobs of WebAssembly code. By leveraging the interpreter as a baseline, we&#8217;re able to optimize the most important parts of the app without having to handle more complex or obscure cases and without overly complicating the runtime. While the jiterpreter isn&#8217;t a full JIT implementation, it significantly improves runtime performance without the size and build time overhead of AOT. The jiterpreter helps when using AOT too by optimizing cases where the runtime has to fallback to the interpreter.<\/p>\n<p>In .NET 8 Preview 2 The jiterpreter is automatically enabled for your Blazor WebAssembly apps. You don&#8217;t have to do anything extra to turn it on.<\/p>\n<p>The jiterpreter can significantly speed up the performance of low level operations. For example, the following micro benchmark test for <code>Span&lt;byte&gt;.Reverse()<\/code> and <code>String.Normalize()<\/code> ran <strong>46.7%<\/strong> and <strong>86.9%<\/strong> faster respectively:<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/dotnet\/wp-content\/uploads\/sites\/10\/2023\/03\/jiterpreter-perf-low-level-ops.svg\" alt=\"Jiterpreter performance for low level operations\" \/><\/p>\n<p>These improvements add up and translate into better performance for higher layer features. In our JSON serialization tests, the jiterpreter is <strong>40.8%<\/strong> faster:<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/dotnet\/wp-content\/uploads\/sites\/10\/2023\/03\/jiterpreter-perf-json-serialization.svg\" alt=\"Jiterpreter performance for JSON serialization\" \/><\/p>\n<p>We&#8217;re still working to improve the jiterpreter with <a href=\"https:\/\/github.com\/dotnet\/runtime\/issues\/78428\">additional optimizations<\/a>, so the performance of the jiterpreter when we ship .NET 8 may differ from what we&#8217;re currently measuring, but so far the results are looking very promising!<\/p>\n<h2>New analyzer to detect multiple <code>FromBody<\/code> attributes<\/h2>\n<p>In addition to the <a href=\"https:\/\/devblogs.microsoft.com\/dotnet\/asp-net-core-updates-in-dotnet-8-preview-1\/#new-analyzers-for-api-development\">analyzers added in Preview 1<\/a>, we&#8217;re introducing a new analyzer in this release that provides a helpful warning if you are attempting to resolve more than one parameter from the body in a minimal API. For example, the new analyzer will warn on the following code.<\/p>\n<pre><code class=\"language-csharp\">\/\/ ASP0024\napp.MapPost(\"\/todos\", ([FromBody] Todo todo, [FromBody] User user) =&gt; ...);<\/code><\/pre>\n<p><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/dotnet\/wp-content\/uploads\/sites\/10\/2023\/03\/frombody-analyzer.png\" alt=\"FromBody analyzer\" \/><\/p>\n<p>To resolve the analyzer warning, limit each handler to have one parameter resolved from the body.<\/p>\n<pre><code class=\"language-csharp\">app.MapPost(\"\/todos\", ([FromBody] Todo todo, ClaimsPrincipal user) =&gt; ...);<\/code><\/pre>\n<h2>New APIs in <code>ProblemDetails<\/code> to support more resilient integrations<\/h2>\n<p>In .NET 7, we introduced the <code>ProblemDetailsService<\/code> to improve the experience for <a href=\"https:\/\/learn.microsoft.com\/aspnet\/core\/fundamentals\/minimal-apis\/handle-errrors#problem-details\">generating error responses<\/a> that comply with the ProblemDetails specification. In this release, we&#8217;ve introduced a new API to make it easier for implementers to implement fallback behavior if the <code>ProlemDetailsService<\/code> was not able to generate a <code>ProblemDetail<\/code>. The new <code>TryWriteAsync<\/code> API can be used as follows in user middleware:<\/p>\n<pre><code class=\"language-csharp\">var problemDetailsService = httpContext.RequestServices.GetService&lt;IProblemDetailsService&gt;();\nif (problemDetailsService == null ||\n    !await problemDetailsService.TryWriteAsync(new() { HttpContext = httpContext }))\n{\n    \/\/ Your fallback behavior, since problem details was not able to be written.\n}<\/code><\/pre>\n<h2>New <code>IResettable<\/code> interface in <code>ObjectPool<\/code><\/h2>\n<p><a href=\"https:\/\/learn.microsoft.com\/aspnet\/core\/performance\/objectpool\">Microsoft.Extensions.ObjectPool<\/a> provides support for pooling object instances in memory. Apps can use an object pool if the values are expensive to allocate or initialize.<\/p>\n<p>In Preview 2 we&#8217;re making the object pool easier to use by adding the <code>IResettable<\/code> interface. Reusable types often need to be reset back to a default state between uses. <code>IResettable<\/code> types are automatically reset when returned to an object pool.<\/p>\n<pre><code class=\"language-csharp\">public class ReusableBuffer : IResettable\n{\n    public byte[] Data { get; } = new byte[1024 * 1024]; \/\/ 1 MB\n\n    public bool TryReset()\n    {\n        Array.Clear(Data);\n        return true;\n    }\n}\n\nvar bufferPool = ObjectPool.Create&lt;ReusableBuffer&gt;();\n\nvar buffer = bufferPool.Get();\ntry\n{\n    await ProcessDataAsync(buffer.Data);\n}\nfinally\n{\n    bufferPool.Return(buffer); \/\/ Data is automatically reset\n}<\/code><\/pre>\n<h2>Performance improvements to named pipes transport<\/h2>\n<p>In Preview 1 we announced support for <a href=\"https:\/\/devblogs.microsoft.com\/dotnet\/asp-net-core-updates-in-dotnet-8-preview-1\/#support-for-named-pipes-in-kestrel\">using named pipes with Kestrel<\/a>.<\/p>\n<p>In preview 2 we&#8217;ve improved named pipe connection performance. Kestrel&#8217;s named pipe transport now accepts connections in parallel, and reuses <code>NamedPipeServerStream<\/code> instances.<\/p>\n<p>Time to create 100,000 connections:<\/p>\n<ul>\n<li><strong>Before:<\/strong> 5.916 seconds<\/li>\n<li><strong>After:<\/strong> 2.374 seconds<\/li>\n<\/ul>\n<p>These improvements were suggested by the community. Thanks to the folks at <a href=\"https:\/\/unity.com\/\">Unity<\/a> for helping contribute to this area!<\/p>\n<h2>Give feedback<\/h2>\n<p>We hope you enjoy this preview release of ASP.NET Core in .NET 8. Let us know what you think about these new improvements by filing issues on <a href=\"https:\/\/github.com\/dotnet\/aspnetcore\/issues\/new\">GitHub<\/a>.<\/p>\n<p>Thanks for trying out ASP.NET Core!<\/p>\n","protected":false},"excerpt":{"rendered":"<p>.NET 8 Preview 2 is now available! Check out what&#8217;s new in ASP.NET Core in this update.<\/p>\n","protected":false},"author":417,"featured_media":44837,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[685,197,7509,7251],"tags":[7701],"class_list":["post-44755","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-dotnet","category-aspnet","category-aspnetcore","category-blazor","tag-dotnet-8"],"acf":[],"blog_post_summary":"<p>.NET 8 Preview 2 is now available! Check out what&#8217;s new in ASP.NET Core in this update.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/posts\/44755","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\/417"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/comments?post=44755"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/posts\/44755\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/media\/44837"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/media?parent=44755"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/categories?post=44755"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/tags?post=44755"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}