{"id":46481,"date":"2023-07-11T10:08:00","date_gmt":"2023-07-11T17:08:00","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/dotnet\/?p=46481"},"modified":"2024-02-23T15:16:54","modified_gmt":"2024-02-23T23:16:54","slug":"asp-net-core-updates-in-dotnet-8-preview-6","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/dotnet\/asp-net-core-updates-in-dotnet-8-preview-6\/","title":{"rendered":"ASP.NET Core updates in .NET 8 Preview 6"},"content":{"rendered":"<p><a href=\"https:\/\/devblogs.microsoft.com\/dotnet\/announcing-dotnet-8-preview-6\">.NET 8 Preview 6 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>Improved startup debugging experience<\/li>\n<li><a href=\"#blazor\">Blazor<\/a>\n<ul>\n<li>Form model binding &amp; validation with server-side rendering<\/li>\n<li>Enhanced page navigation &amp; form handling<\/li>\n<li>Preserve existing DOM elements with streaming rendering<\/li>\n<li>Specify component render mode at the call site<\/li>\n<li>Interactive rendering with Blazor WebAssembly<\/li>\n<li>Sections improvements<\/li>\n<li>Cascade query string values to Blazor components<\/li>\n<li>Blazor Web App template option for enabling server interactivity<\/li>\n<li>Blazor template consolidation<\/li>\n<\/ul>\n<\/li>\n<li><a href=\"#metrics\">Metrics<\/a>\n<ul>\n<li>Testing metrics in ASP.NET Core apps<\/li>\n<li>New, improved, and renamed counters<\/li>\n<\/ul>\n<\/li>\n<li><a href=\"#api-authoring\">API authoring<\/a>\n<ul>\n<li>Complex form binding support in minimal APIs<\/li>\n<\/ul>\n<\/li>\n<li><a href=\"#servers\">Servers &amp; middleware<\/a>\n<ul>\n<li>HTTP.sys kernel response buffering<\/li>\n<li>Redis-based output-cache<\/li>\n<\/ul>\n<\/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 6, <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>. If you&#8217;re using Visual Studio Code, you can try out the new <a href=\"https:\/\/devblogs.microsoft.com\/visualstudio\/announcing-csharp-dev-kit-for-visual-studio-code\/\">C# Dev Kit<\/a>. If you are on macOS, you can now develop using Visual Studio for Mac 17.6.1 after enabling the preview feature for .NET 8 in Preferences.<\/p>\n<h2>Upgrade an existing project<\/h2>\n<p>To upgrade an existing ASP.NET Core app from .NET 8 Preview 5 to .NET 8 Preview 6:<\/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.6.*<\/code>.<\/li>\n<li>Update all Microsoft.Extensions.* package references to <code>8.0.0-preview.6.*<\/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>Improved startup debugging experience<\/h2>\n<p>Last preview we introduced <a href=\"https:\/\/devblogs.microsoft.com\/dotnet\/asp-net-core-updates-in-dotnet-8-preview-5\/#improved-asp-net-core-debugging-experience\">debugging improvements to <code>HttpContext<\/code> and friends<\/a>. In .NET 8 Preview 6 we&#8217;ve improved the debugging experience for the <code>WebApplication<\/code> type.<\/p>\n<p><code>WebApplication<\/code> is the default way to configure and start ASP.NET Core apps in <code>Program.cs<\/code>. <a href=\"https:\/\/learn.microsoft.com\/visualstudio\/debugger\/using-the-debuggerdisplay-attribute\">Debug customization attributes<\/a> have been applied to <code>WebApplication<\/code> to highlight important information, such as configured endpoints, middleware, and <code>IConfiguration<\/code> values in your IDE&#8217;s debugger.<\/p>\n<p><strong>.NET 7<\/strong><\/p>\n<p><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/dotnet\/wp-content\/uploads\/sites\/10\/2024\/02\/webapplication-debugging-before.png\" alt=\"WebApplication debugging before\" \/><\/p>\n<p><strong>.NET 8<\/strong><\/p>\n<p><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/dotnet\/wp-content\/uploads\/sites\/10\/2024\/02\/webapplication-debugging-after.png\" alt=\"WebApplication debugging after\" \/><\/p>\n<p>See the <a href=\"https:\/\/github.com\/dotnet\/aspnetcore\/issues\/48205\">ASP.NET Core \u2764\ufe0f Debugging<\/a> GitHub issue for more information about debugging improvements in .NET 8.<\/p>\n<p><a id=\"blazor\"><\/a><\/p>\n<h2>Blazor<\/h2>\n<h3>Form model binding &amp; validation with server-side rendering<\/h3>\n<p>Blazor&#8217;s new server-side rendering mode can now model bind and validate HTTP form post values.<\/p>\n<p>To bind data from a form request, apply the <code>[SupplyParameterFromForm]<\/code> attribute to a component property. Data in the request that matches the name of the property will be bound to the property. The property can be a primitive type, complex type, collection, or dictionary. Server-side validation using data annotations is also supported as well.<\/p>\n<p><em>Movie.cs<\/em><\/p>\n<pre><code class=\"language-csharp\">public class Movie\n{\n    public int Id { get; set; }\n    public string? Title { get; set; }\n    public DateOnly? ReleaseDate { get; set; }\n    public string? Genre { get; set; }\n    public decimal Price { get; set; }\n}<\/code><\/pre>\n<p><em>Pages\/Movies\/Create.razor<\/em><\/p>\n<pre><code class=\"language-razor\">@page \"\/movies\/create\"\n@inject BlazorMovieContext DB\n\n&lt;PageTitle&gt;Create&lt;\/PageTitle&gt;\n\n&lt;h1&gt;Create&lt;\/h1&gt;\n\n&lt;h4&gt;Movie&lt;\/h4&gt;\n&lt;hr \/&gt;\n&lt;div class=\"row\"&gt;\n    &lt;div class=\"col-md-4\"&gt;\n        &lt;EditForm method=\"post\" Model=\"Movie\" OnValidSubmit=\"AddMovie\"&gt;\n            &lt;DataAnnotationsValidator \/&gt;\n            &lt;ValidationSummary class=\"text-danger\" \/&gt;\n            &lt;div class=\"mb-3\"&gt;\n                &lt;label for=\"title\" class=\"form-label\"&gt;Title:&lt;\/label&gt;\n                &lt;InputText id=\"title\" @bind-Value=\"Movie.Title\" class=\"form-control\" \/&gt;\n                &lt;ValidationMessage For=\"() =&gt; Movie.Title\" class=\"text-danger\" \/&gt;\n            &lt;\/div&gt;\n            &lt;div class=\"mb-3\"&gt;\n                &lt;label for=\"release-date\" class=\"form-label\"&gt;Release date:&lt;\/label&gt;\n                &lt;InputDate id=\"release-date\" @bind-Value=\"Movie.ReleaseDate\" class=\"form-control\" \/&gt;\n                &lt;ValidationMessage For=\"() =&gt; Movie.ReleaseDate\" class=\"text-danger\" \/&gt;\n            &lt;\/div&gt;\n            &lt;div class=\"mb-3\"&gt;\n                &lt;label for=\"genre\" class=\"form-label\"&gt;Genre:&lt;\/label&gt;\n                &lt;InputText id=\"genre\" @bind-Value=\"Movie.Genre\" class=\"form-control\" \/&gt;\n                &lt;ValidationMessage For=\"() =&gt; Movie.Genre\" class=\"text-danger\" \/&gt;\n            &lt;\/div&gt;\n            &lt;div class=\"mb-3\"&gt;\n                &lt;label for=\"price\" class=\"form-label\"&gt;Price:&lt;\/label&gt;\n                &lt;InputNumber id=\"price\" @bind-Value=\"Movie.Price\" min=\"0\" step=\"0.01\" class=\"form-control\" \/&gt;\n                &lt;ValidationMessage For=\"() =&gt; Movie.Price\" class=\"text-danger\" \/&gt;\n            &lt;\/div&gt;\n            &lt;button type=\"submit\" class=\"btn btn-primary\"&gt;Create&lt;\/button&gt;\n        &lt;\/EditForm&gt;\n    &lt;\/div&gt;\n&lt;\/div&gt;\n\n&lt;div&gt;\n    @if (movieAdded)\n    {\n        &lt;span&gt;\n            Movie was added.\n        &lt;\/span&gt;\n    }\n    &lt;a href=\"\/movies\"&gt;Back to List&lt;\/a&gt;\n&lt;\/div&gt;\n\n@code {\n\n    [SupplyParameterFromForm]\n    public Movie Movie { get; set; } = new();\n\n    private bool movieAdded = false;\n\n    public async Task AddMovie()\n    {\n        DB.Movie.Add(Movie);\n        await DB.SaveChangesAsync();\n        movieAdded = true;\n    }\n}<\/code><\/pre>\n<p>If there are multiple forms on a page they can be distinguished using the <code>Name<\/code> parameter, and you can use the <code>Name<\/code> property on the <code>[SupplyParameterFromForm]<\/code> to indicate which form you wish to bind data from.<\/p>\n<p>You no longer need to set up a <code>CascadingModelBinder<\/code> component to enable model binding. It&#8217;s now set up for you automatically.<\/p>\n<h3>Enhanced page navigation &amp; form handling<\/h3>\n<p>Blazor will now enhance page navigation and form handling by intercepting the request in order to apply the response to the existing DOM preserving as much as possible. The enhancement avoids the need to fully load the page and provides a much smoother user experience, similar to a single page app (SPA), even though the app is still being server-side rendered.<\/p>\n<p>In this preview release, enhanced navigation and form handling isn&#8217;t yet compatible with having interactive (Server or WebAssembly) components on the page at the same time. If your app uses interactive components, enhanced navigation will automatically be disabled. This limitation will be addressed in an upcoming preview before the .NET 8 GA release.<\/p>\n<h3>Preserve existing DOM elements with streaming rendering<\/h3>\n<p>Blazor streaming rendering will now preserve existing DOM elements when streaming updates into the page, which provides a faster and smoother user experience.<\/p>\n<h3>Specify component render mode at the call site<\/h3>\n<p>You can now specify the render mode for a component instance using the <code>@rendermode<\/code> directive attribute. The render mode will then apply to the component and its children. For example,<\/p>\n<pre><code class=\"language-razor\">&lt;Counter @rendermode=\"@RenderMode.Server\" \/&gt;<\/code><\/pre>\n<p>To enable call site <code>@rendermode<\/code> usage, make sure to set the Razor Language Version in the project file to <code>8.0<\/code>. This will be handled internally in the framework and won&#8217;t be necessary from the next preview release. To do this, edit your project&#8217;s <code>.csproj<\/code> file, adding the following line into the first <code>&lt;PropertyGroup&gt;<\/code> element:\n<code>&lt;RazorLangVersion&gt;8.0&lt;\/RazorLangVersion&gt;<\/code><\/p>\n<h3>Interactive rendering with Blazor WebAssembly<\/h3>\n<p>You can now enable interactive rendering of components with Blazor WebAssembly. While this option is not <em>yet<\/em> exposed on the Blazor Web App template, you can enable it manually.<\/p>\n<p>To enable support for the WebAssembly render mode in your Blazor project, add the related services by calling <code>app.Services.AddRazorComponents().AddWebAssemblyComponents()<\/code> and add the WebAssembly render mode by calling <code>app.MapRazorComponents&lt;App&gt;().AddWebAssemblyRenderMode()<\/code>. Any components you wish to render on WebAssembly will need to be downloaded along with all of their dependencies to the browser. You&#8217;ll need to setup a separate Blazor WebAssembly project to handle building any WebAssembly specific code and reference it from your Blazor app.<\/p>\n<p>You can specify the WebAssembly interactive render mode for a component by adding the <code>[RenderModeWebAssembly]<\/code> attribute to the component definition or by specifying <code>@rendermode=\"@RenderMode.WebAssembly\"<\/code> on a component instance. Components that you setup to render on WebAssembly will also be prerendered from the server by default, so be sure either to author your components so they render correctly in either environment or disable prerendering when specifying the render mode: <code>[RenderModeWebAssembly(prerender: false)]<\/code> or <code>@rendermode=\"@(new WebAssemblyRenderMode(prerender: false))<\/code>.<\/p>\n<p>Here&#8217;s a <a href=\"https:\/\/github.com\/mkArtakMSFT\/BlazorWasmClientInteractivity\">sample<\/a> showcasing how to set up WebAssembly-based interactivity for a <code>Counter<\/code> component that is rendered from the <code>Index<\/code> page.<\/p>\n<p>Note that there&#8217;s currently a <a href=\"https:\/\/github.com\/dotnet\/aspnetcore\/issues\/49313\">limitation<\/a> where components with routes must be defined in the same assembly as the <code>App<\/code> component passed to <code>MapRazorComponents&lt;App&gt;()<\/code>, so they cannot currently be defined in the client assembly. This will be addressed in a future update.<\/p>\n<h3>Blazor sections improvements<\/h3>\n<p>We&#8217;ve made the following improvements to how Blazor sections interact with other Blazor features:<\/p>\n<ul>\n<li><strong>Cascading values<\/strong>: Cascading values will now flow into section content from where the content is defined instead of where it is rendered in a section outlet.<\/li>\n<li><strong>Error boundaries<\/strong>: Unhandled exceptions will now be handled by error boundaries defined around the section content instead of around the section outlet.<\/li>\n<li><strong>Streaming rendering<\/strong>: Whether section content will use streaming rendering is now determined by the component where the section content is defined instead of by the component that defines the section outlet.<\/li>\n<\/ul>\n<h3>Cascade query string values to Blazor components<\/h3>\n<p>You can now receive query string parameter values in any component, not just <code>@page<\/code> components, using the <code>[SupplyParameterFromQuery]<\/code> attribute. For example:<\/p>\n<pre><code class=\"language-csharp\">[SupplyParameterFromQuery]\npublic int PageIndex { get; set; }<\/code><\/pre>\n<p>It is no longer necessary to add the <code>[Parameter]<\/code> attribute to any property that declares <code>[SupplyParameterFromQuery]<\/code>.<\/p>\n<h3>Blazor Web App template option for enabling server interactivity<\/h3>\n<p>The Blazor Web App template now provides an option in Visual Studio for enabling interactivity using the server render mode:<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/dotnet\/wp-content\/uploads\/sites\/10\/2024\/02\/Blazor-server-interactivity-template-option.png\" alt=\"Blazor template option for server interactivity\" \/><\/p>\n<p>The same option is already available from the command-line:<\/p>\n<pre><code class=\"language-console\">dotnet new blazor --use-server<\/code><\/pre>\n<h3>Blazor template consolidation<\/h3>\n<p>As part of unifying the various Blazor hosting models into a single model in .NET 8, we&#8217;re also consolidating the number of Blazor project templates. In this preview release we&#8217;ve removed the Blazor Server template and the &#8220;ASP.NET Core hosted&#8221; option from the Blazor WebAssembly template. Both of these scenarios will be represented by options when using the new Blazor Web App template.<\/p>\n<p><a id=\"metrics\"><\/a><\/p>\n<h2>Metrics<\/h2>\n<h3>Testing metrics in ASP.NET Core apps<\/h3>\n<p>In an earlier .NET 8 preview, we <a href=\"https:\/\/devblogs.microsoft.com\/dotnet\/asp-net-core-updates-in-dotnet-8-preview-4\/#metrics\">introduced ASP.NET Core metrics<\/a>. It&#8217;s now easier to test metrics in ASP.NET Core apps.<\/p>\n<p>ASP.NET Core uses the <a href=\"https:\/\/github.com\/dotnet\/runtime\/issues\/77514\"><code>IMeterFactory<\/code><\/a> API to create and obtain meters. The meter factory integrates metrics with dependency injection, making isolating and collecting metrics easy. <code>IMeterFactory<\/code> is especially useful for unit testing, where multiple tests can run side-by-side and you want to only gather data for your test.<\/p>\n<p>The sample below shows how to use <code>IMeterFactory<\/code> and <code>MetricCollector&lt;T&gt;<\/code> (a simplified way to collect a counter&#8217;s data) in an ASP.NET Core functional test:<\/p>\n<pre><code class=\"language-csharp\">public class BasicTests : IClassFixture&lt;WebApplicationFactory&lt;Program&gt;&gt;\n{\n    private readonly WebApplicationFactory&lt;Program&gt; _factory;\n    public BasicTests(WebApplicationFactory&lt;Program&gt; factory) =&gt; _factory = factory;\n\n    [Fact]\n    public async Task Get_RequestCounterIncreased()\n    {\n        \/\/ Arrange\n        var meterFactory = _factory.Services.GetRequiredService&lt;IMeterFactory&gt;();\n        var collector = new MetricCollector&lt;double&gt;(meterFactory, \"Microsoft.AspNetCore.Hosting\", \"http-server-request-duration\");\n        var client = _factory.CreateClient();\n\n        \/\/ Act\n        var response = await client.GetAsync(\"\/\");\n\n        \/\/ Assert\n        Assert.Equal(\"Hello World!\", await response.Content.ReadAsStringAsync());\n\n        await collector.WaitForMeasurementsAsync(minCount: 1);\n        Assert.Collection(collector.GetMeasurementSnapshot(),\n            measurement =&gt;\n            {\n                Assert.Equal(\"http\", measurement.Tags[\"scheme\"]);\n                Assert.Equal(\"GET\", measurement.Tags[\"method\"]);\n                Assert.Equal(\"\/\", measurement.Tags[\"route\"]);\n            });\n    }\n}<\/code><\/pre>\n<h3>New, improved, and renamed counters<\/h3>\n<p>ASP.NET continues to improve its support for metrics by adding new counters and improving existing counters. We want to make ASP.NET Core apps observable in reporting dashboards and to enable custom alerts.<\/p>\n<p>New counters in this preview:<\/p>\n<ul>\n<li><code>routing-match-success<\/code> and <code>routing-match-failure<\/code> report how the request was <a href=\"https:\/\/learn.microsoft.com\/aspnet\/core\/fundamentals\/routing\">routed in the app<\/a>. If the request successfully matches a route, the counter includes information about the route pattern and whether it was a fallback route.<\/li>\n<li><code>diagnostics-handler-exception<\/code> is added to the <a href=\"https:\/\/learn.microsoft.com\/aspnet\/core\/fundamentals\/error-handling\">exception handling middleware<\/a>. The counter reports how unhandled exceptions are processed, and includes information about the exception name and handler result.<\/li>\n<li><code>http-server-unhandled-requests<\/code> is a new counter in ASP.NET Core hosting. It reports when an HTTP request reaches the end of the middleware pipeline without being handled by the app.<\/li>\n<li>Various new <a href=\"https:\/\/github.com\/dotnet\/aspnetcore\/issues\/47745\">rate limiting middleware counters<\/a> make it possible to observe the number of requests holding leases, the number of requests queued, queue duration, and more.<\/li>\n<\/ul>\n<p>Improved counters:<\/p>\n<ul>\n<li><code>kestrel-connection-duration<\/code> now includes the connection HTTP protocol and TLS protocol.<\/li>\n<li><code>signalr-http-transport-current-connections<\/code> now includes the connection transport type.<\/li>\n<\/ul>\n<p>Finally, based on testing ASP.NET Core with cloud-native tools, we&#8217;ve <a href=\"https:\/\/github.com\/dotnet\/aspnetcore\/issues\/48536\">renamed all ASP.NET Core counters<\/a> to include more information in the name. Counters were renamed to make them identifiable by name alone and to reduce the chance of naming conflicts. For example, <code>request-duration<\/code> was renamed to <code>http-server-request-duration<\/code>.<\/p>\n<h2>API authoring<\/h2>\n<h3>Complex form binding support in minimal APIs<\/h3>\n<p>In .NET 8 Preview 4 we <a href=\"https:\/\/devblogs.microsoft.com\/dotnet\/asp-net-core-updates-in-dotnet-8-preview-4\/#expanded-support-for-form-binding-in-minimal-apis\">expanded support for form binding in minimal APIs<\/a> to handle certain form-based parameters without the need of the <code>FromForm<\/code> attribute.  This was limited to parameter types including\n<code>IFormCollection<\/code>, <code>IFormFile<\/code>, and <code>IFormFileCollection<\/code>. Minimal APIs now supports form-binding for more complex scenarios, including:<\/p>\n<ul>\n<li>Collections, like <code>List<\/code> and <code>Dictionary<\/code><\/li>\n<li>Complex types, like <code>Todo<\/code> or <code>Project<\/code><\/li>\n<\/ul>\n<p>The sample below showcases a minimal endpoint that binds a multi-part form input to a complex object. It also outlines how to use the anti-forgery services in ASP.NET to support the generation and validation of anti-forgery tokens in minimal APIs. Key points to note in this sample include:<\/p>\n<ul>\n<li>The target parameter <em>must<\/em> be annotated with the <code>[FromForm]<\/code> attribute to disambiguate from parameters that should be read from the JSON body.<\/li>\n<li>Binding to <code>record<\/code> types is not currently supported, so complex types must be implemented as a class.<\/li>\n<li>Recursive binding is not supported, so the <code>Todo<\/code> type does not contain any recursive references.<\/li>\n<\/ul>\n<pre><code class=\"language-csharp\">using Microsoft.AspNetCore.Antiforgery;\nusing Microsoft.AspNetCore.Mvc;\n\nvar builder = WebApplication.CreateBuilder(args);\n\nbuilder.Services.AddAntiforgery();\n\nvar app = builder.Build();\n\napp.MapGet(\"\/\", (HttpContext context, IAntiforgery antiforgery) =&gt;\n{\n    var token = antiforgery.GetAndStoreTokens(context);\n    var html = $\"\"\"\n        &lt;html&gt;\n            &lt;body&gt;\n                &lt;form action=\"\/todo\" method=\"POST\" enctype=\"multipart\/form-data\"&gt;\n                    &lt;input name=\"{token.FormFieldName}\" type=\"hidden\" value=\"{token.RequestToken}\" \/&gt;\n                    &lt;input type=\"text\" name=\"name\" \/&gt;\n                    &lt;input type=\"date\" name=\"dueDate\" \/&gt;\n                    &lt;input type=\"checkbox\" name=\"isCompleted\" \/&gt;\n                    &lt;input type=\"submit\" \/&gt;\n                &lt;\/form&gt;\n            &lt;\/body&gt;\n        &lt;\/html&gt;\n    \"\"\";\n    return Results.Content(html, \"text\/html\");\n});\n\napp.MapPost(\"\/todo\", async Task&lt;Results&lt;Ok&lt;Todo&gt;, BadRequest&lt;string&gt;&gt;&gt; ([FromForm] Todo todo, HttpContext context, IAntiforgery antiforgery) =&gt;\n{\n    try\n    {\n        await antiforgery.ValidateRequestAsync(context);\n        return Results.Ok(todo);\n    }\n    catch (AntiforgeryValidationException e)\n    {\n        return TypedResults.BadRequest(\"Invalid anti-forgery token\");\n    }\n});\n\napp.Run();\n\nclass Todo\n{\n    public string Name { get; set; } = string.Empty;\n    public bool IsCompleted { get; set; } = false;\n    public DateTime DueDate { get; set; } = DateTime.Now.Add(TimeSpan.FromDays(1));\n}<\/code><\/pre>\n<p><a id=\"servers\"><\/a><\/p>\n<h2>Servers &amp; middleware<\/h2>\n<h3>HTTP.sys kernel response buffering<\/h3>\n<p>You can now enable kernel-based response buffering when using HTTP.sys using the <code>EnableKernelResponseBuffering<\/code> option. This option can improve response times, particularly when writing large responses with lots of small writes to a client with high latency. In affected scenarios, this can drastically improve response times from minutes (or outright failure) to seconds.<\/p>\n<h3>Redis-based output caching<\/h3>\n<p><a href=\"https:\/\/learn.microsoft.com\/aspnet\/core\/performance\/caching\/output\">Output caching<\/a> was introduced in .NET 7 and allows entire responses to be cached and replayed, reducing server processing. By default, cached responses are stored in-process, so each server node has a separate and isolated cache that is lost whenever the server process is restarted. As an alternative, we&#8217;re now introducing the ability to use a Redis backend for output caching, providing consistency between\nserver nodes via a shared cache that outlives individual server processes.<\/p>\n<p>To setup Redis-based output caching, add a package reference to <code>Microsoft.Extensions.Caching.StackExchangeRedis<\/code>, then configure the required services by calling <code>app.Services.AddStackExchangeRedisOutputCache(...)<\/code>. The available configuration options are identical to the existing <a href=\"https:\/\/learn.microsoft.com\/aspnet\/core\/performance\/caching\/distributed\">Redis-based distributed caching<\/a> options. You can provide your own Redis server, or use a hosted offering such as <a href=\"https:\/\/azure.microsoft.com\/products\/cache\/\">Azure Cache for Redis<\/a>.<\/p>\n<h2>Give feedback<\/h2>\n<p>We hope that 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 6 is now available! Check out what&#8217;s new in ASP.NET Core in this update.<\/p>\n","protected":false},"author":417,"featured_media":50729,"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-46481","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 6 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\/46481","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=46481"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/posts\/46481\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/media\/50729"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/media?parent=46481"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/categories?post=46481"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/tags?post=46481"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}