{"id":41426,"date":"2022-08-09T10:02:16","date_gmt":"2022-08-09T17:02:16","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/dotnet\/?p=41426"},"modified":"2022-08-29T10:44:26","modified_gmt":"2022-08-29T17:44:26","slug":"asp-net-core-updates-in-dotnet-7-preview-7","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/dotnet\/asp-net-core-updates-in-dotnet-7-preview-7\/","title":{"rendered":"ASP.NET Core updates in .NET 7 Preview 7"},"content":{"rendered":"<p><a href=\"https:\/\/devblogs.microsoft.com\/dotnet\/announcing-dotnet-7-preview-7\">.NET 7 Preview 7 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>New Blazor WebAssembly loading page<\/li>\n<li>Blazor data binding get\/set\/after modifiers<\/li>\n<li>Blazor virtualization improvements<\/li>\n<li>Pass state using <code>NavigationManager<\/code><\/li>\n<li>Additional <code>System.Security.Cryptography<\/code> support on WebAssembly<\/li>\n<li>Updated Angular and React templates<\/li>\n<li>gRPC JSON transcoding performance<\/li>\n<li>Authentication will use single scheme as <code>DefaultScheme<\/code><\/li>\n<li><code>IFormFile<\/code>\/<code>IFormFileCollection<\/code> support for authenticated requests in minimal APIs<\/li>\n<li>New problem details service<\/li>\n<li>Diagnostics middleware updates<\/li>\n<li>New <code>HttpResults<\/code> interfaces<\/li>\n<\/ul>\n<p>For more details on the ASP.NET Core work planned for .NET 7 see the full <a href=\"https:\/\/aka.ms\/aspnet\/roadmap\">ASP.NET Core roadmap for .NET 7<\/a> on GitHub.<\/p>\n<h2>Get started<\/h2>\n<p>To get started with ASP.NET Core in .NET 7 Preview 7, <a href=\"https:\/\/dotnet.microsoft.com\/download\/dotnet\/7.0\">install the .NET 7 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 on macOS, we recommend installing the latest <a href=\"https:\/\/visualstudio.microsoft.com\/vs\/mac\/preview\/\">Visual Studio 2022 for Mac preview<\/a>.<\/p>\n<p>To install the latest .NET WebAssembly build tools, run the following command from an elevated command prompt:<\/p>\n<pre><code class=\"language-console\">dotnet workload install wasm-tools<\/code><\/pre>\n<blockquote><p>Note: Building .NET 6 Blazor projects with the .NET 7 SDK and the .NET 7 WebAssembly build tools is currently not supported. This will be addressed in a future .NET 7 update: <a href=\"https:\/\/github.com\/dotnet\/runtime\/issues\/65211\">dotnet\/runtime#65211<\/a>.<\/p><\/blockquote>\n<h2>Upgrade an existing project<\/h2>\n<p>To upgrade an existing ASP.NET Core app from .NET 7 Preview 6 to .NET 7 Preview 7:<\/p>\n<ul>\n<li>Update all Microsoft.AspNetCore.* package references to <code>7.0.0-preview.7.*<\/code>.<\/li>\n<li>Update all Microsoft.Extensions.* package references to <code>7.0.0-preview.7.*<\/code>.<\/li>\n<\/ul>\n<p>See also the full list of <a href=\"https:\/\/docs.microsoft.com\/dotnet\/core\/compatibility\/7.0#aspnet-core\">breaking changes<\/a> in ASP.NET Core for .NET 7.<\/p>\n<h2>New Blazor loading page<\/h2>\n<p>The Blazor WebAssembly project template has a new loading UI that shows the progress of loading the app.<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/dotnet\/wp-content\/uploads\/sites\/10\/2022\/08\/blazor-wasm-loading-screen.gif\" alt=\"Blazor WebAssembly loading screen\" \/><\/p>\n<p>The new loading screen is implemented with HTML and CSS in the Blazor WebAssembly template using two new CSS custom properties (variables) provided by Blazor WebAssembly:<\/p>\n<ul>\n<li><code>--blazor-load-percentage<\/code>: The percentage of app files loaded.<\/li>\n<li><code>--blazor-load-percentage-text<\/code>: The percentage of app files loaded rounded to the nearest whole number.<\/li>\n<\/ul>\n<p>Using these new CSS variables, you can create a custom loading UI that matches the styling of your own Blazor WebAssembly apps.<\/p>\n<h2>Blazor data binding get\/set\/after modifiers<\/h2>\n<p>Blazor provides a powerful <a href=\"https:\/\/docs.microsoft.com\/aspnet\/core\/blazor\/components\/data-binding\">data binding<\/a> feature for creating two-way bindings between UI elements or component parameters with .NET objects. In .NET 7 you can now easily run async logic after a binding event has completed using the new <code>@bind:after<\/code> modifier:<\/p>\n<pre><code class=\"language-razor\">&lt;input @bind=\"searchText\" @bind:after=\"PerformSearch\" \/&gt;\r\n\r\n@code {\r\n    string searchText;\r\n\r\n    async Task PerformSearch()\r\n    {\r\n        \/\/ ... do something asynchronously with 'searchText' ...\r\n    }\r\n}<\/code><\/pre>\n<p>In this example the <code>PerformSearch<\/code> async method will run automatically after any changes to the search text are detected.<\/p>\n<p>It&#8217;s also now easier to setup binding for component parameters. Components can support two-way data binding by defining a pair of parameters for the value and for a callback that is called when the value changes. The new <code>@bind:get<\/code> and <code>@bind:set<\/code> modifiers now make it trivial to create a component parameters that binds to an underlying UI element:<\/p>\n<pre><code class=\"language-razor\">&lt;input @bind:get=\"Value\" @bind:set=\"ValueChanged\" \/&gt;\r\n\r\n@code {\r\n    [Parameter] public TValue Value { get; set; }\r\n    [Parameter] public EventCallback&lt;TValue&gt; ValueChanged { get; set; }\r\n}<\/code><\/pre>\n<p>The <code>@bind:get<\/code> and <code>@bind:set<\/code> modifiers are always used together. The <code>@bind:get<\/code> modifier specifies the value to bind to and the <code>@bind:set<\/code> modifier specifies a callback that is called when the value changes.<\/p>\n<h2>Blazor virtualization improvements<\/h2>\n<p>Blazor&#8217;s <code>Virtualize<\/code> component renders a spacer element to define the vertical height of the scroll region. By default it uses a <code>div<\/code> element like this:<\/p>\n<pre><code class=\"language-html\">&lt;div style=\"height: 12345px\"&gt;&lt;\/div&gt;<\/code><\/pre>\n<p>However, in some cases the parent element might not allow child <code>div<\/code> elements. For example, the parent element might be a <code>tbody<\/code>, which only allows child <code>tr<\/code> elements. For these cases you can now use the new <code>SpacerElement<\/code> parameter to configure the spacer element that <code>Virtualize<\/code> uses:<\/p>\n<pre><code class=\"language-razor\">&lt;tbody&gt;\r\n  &lt;Virtualize SpacerElement=\"tr\"&gt;...&lt;\/Virtualize&gt;\r\n&lt;\/tbody&gt;<\/code><\/pre>\n<h2>Pass state using <code>NavigationManager<\/code><\/h2>\n<p>You can now pass state when navigating in Blazor apps using the <code>NavigationManager<\/code>.<\/p>\n<pre><code class=\"language-csharp\">navigationManager.NavigateTo(\"\/orders\", new NavigationOptions { HistoryEntryState = \"My state\" });<\/code><\/pre>\n<p>This mechanism allows for simple communication between different pages. The specified state is pushed onto the browser&#8217;s history stack so that it can be accessed later using either the <code>NavigationManager.HistoryEntryState<\/code> property or the <code>LocationChangedEventArgs.HistoryEntryState<\/code> property when listening for location changed events.<\/p>\n<h2>Additional <code>System.Security.Cryptography<\/code> support on WebAssembly<\/h2>\n<p>.NET 6 supported the SHA family of hashing algorithms when running on WebAssembly. .NET 7 enables more cryptographic algorithms by taking advantage of <a href=\"https:\/\/developer.mozilla.org\/docs\/Web\/API\/SubtleCrypto\">SubtleCrypto<\/a> when possible, and falling back to a .NET implementation when SubtleCrypto can&#8217;t be used. In .NET 7 Preview 7 the following algorithms are now supported on WebAssembly:<\/p>\n<ul>\n<li>SHA1, SHA256, SHA384, SHA512<\/li>\n<li>HMACSHA1, HMACSHA256, HMACSHA384, HMACSHA512<\/li>\n<li>Aes (only CBC mode is supported)<\/li>\n<li>Rfc2898DeriveBytes (PBKDF2)<\/li>\n<li>HKDF<\/li>\n<\/ul>\n<h2>Updated Angular and React templates<\/h2>\n<p>We updated the Angular project template to Angular 14 and the React project template to React 18.2.<\/p>\n<h2>gRPC JSON transcoding performance<\/h2>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/dotnet\/announcing-grpc-json-transcoding-for-dotnet\/\">gRPC JSON transcoding<\/a> is a new feature in .NET 7 for turning gRPC APIs into RESTful APIs.<\/p>\n<p>.NET 7 Preview 7 improves performance and memory usage when serializing messages. gRPC JSON transcoding serializes gRPC messages to a <a href=\"https:\/\/developers.google.com\/protocol-buffers\/docs\/proto3#json\">standardize JSON format<\/a>. Before Preview 7, transcoding required a custom <code>JsonConverter<\/code> to customize JSON serialization. This release replaces the <code>JsonConverter<\/code> with <a href=\"https:\/\/github.com\/dotnet\/runtime\/issues\/63686\">System.Text.Json&#8217;s new contract customization feature<\/a>.<\/p>\n<p>The benchmark results below compare serializing gRPC messages before and after using contract customization:<\/p>\n<table>\n<thead>\n<tr>\n<th>Method<\/th>\n<th>Mean<\/th>\n<th>Ratio<\/th>\n<th>Allocated<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td>SerializeMessage_Converter<\/td>\n<td>386.7 ns<\/td>\n<td>1.00<\/td>\n<td>160 B<\/td>\n<\/tr>\n<tr>\n<td>SerializeMessage_Contract<\/td>\n<td>213.3 ns<\/td>\n<td>0.55<\/td>\n<td>80 B<\/td>\n<\/tr>\n<tr>\n<td>DeserializeMessage_Converter<\/td>\n<td>296.0 ns<\/td>\n<td>1.00<\/td>\n<td>304 B<\/td>\n<\/tr>\n<tr>\n<td>DeserializeMessage_Contract<\/td>\n<td>167.6 ns<\/td>\n<td>0.57<\/td>\n<td>224 B<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>A custom contract and System.Text.Json&#8217;s high-performance serializer dramatically improves performance and allocations.<\/p>\n<h2>Authentication will use single scheme as <code>DefaultScheme<\/code><\/h2>\n<p>As part of the work to simplify authentication, when there is only a single authentication scheme registered, it will automatically be used as the <code>DefaultScheme<\/code>, which eliminates the need to specify the <code>DefaultScheme<\/code> in <code>AddAuthentication()<\/code> in this case. This behavior can be disabled via <code>AppContext.SetSwitch(\"Microsoft.AspNetCore.Authentication.SuppressAutoDefaultScheme\")<\/code><\/p>\n<h2><code>IFormFile<\/code>\/<code>IFormFileCollection<\/code> support for authenticated requests in minimal APIs<\/h2>\n<p>In .NET 7 Preview 1 we introduced support for <a href=\"https:\/\/devblogs.microsoft.com\/dotnet\/asp-net-core-updates-in-net-7-preview-1\/#iformfile-and-iformfilecollection-support\">handling file uploads in minimal APIs<\/a> using <code>IFormFile<\/code> and <code>IFormFileCollection<\/code>. .NET Preview 7 adds support for authenticated file upload requests to minimal APIs using an <code>Authorization<\/code> header, a client certificate, or a cookie header.<\/p>\n<p>There is no built-in support for anti-forgery in minimal APIs. However, it can be <a href=\"https:\/\/docs.microsoft.com\/aspnet\/core\/security\/anti-request-forgery?view=aspnetcore-7.0#antiforgery-with-minimal-apis\">implemented using the <code>IAntiforgery<\/code> service<\/a>.<\/p>\n<h2>New problem details service<\/h2>\n<p>.NET 7 Preview 7 introduces a new problem details service based on the <code>IProblemDetailsService<\/code> interface for generating consistent <a href=\"https:\/\/www.rfc-editor.org\/rfc\/rfc7807\">problem details<\/a> responses in your app.<\/p>\n<p>To add the problem details service, use the <code>AddProblemDetails<\/code> extension method on <code>IServiceCollection<\/code>.<\/p>\n<pre><code class=\"language-csharp\">builder.Services.AddProblemDetails();<\/code><\/pre>\n<p>You can then write a problem details response from any layer in your app by calling <code>IProblemDetailsService.WriteAsync<\/code>. For example, here&#8217;s how you can generate a problem details response from middleware:<\/p>\n<pre><code class=\"language-csharp\">httpContext.Response.StatusCode = StatusCodes.Status400BadRequest;\r\n\r\nif (context.RequestServices.GetService&lt;IProblemDetailsService&gt;() is { } problemDetailsService)\r\n{\r\n    return problemDetailsService.WriteAsync(new { HttpContext = httpContext });\r\n}\r\n\r\nreturn ValueTask.CompletedTask;<\/code><\/pre>\n<p>You can customize problem details responses generated by the service (including autogenerated responses for API controllers) using <code>ProblemDetailsOptions<\/code>:<\/p>\n<pre><code class=\"language-csharp\">builder.Services.AddProblemDetails(options =&gt;\r\n{\r\n    options.CustomizeProblemDetails = (context) =&gt; \r\n    {\r\n       context.ProblemDetails.Extensions.Add(\"my-extension\", new { Property = \"value\" });\r\n    };\r\n});<\/code><\/pre>\n<p>In addition, you can create your own <code>IProblemDetailsWriter<\/code> implementation for advanced customizations:<\/p>\n<pre><code class=\"language-csharp\">public class CustomWriter : IProblemDetailsWriter\r\n{\r\n    \/\/ Indicates that only responses with StatusCode == 400\r\n    \/\/ will be handled by this writer. All others will be\r\n    \/\/ handled by different registered writers if available.\r\n    public bool CanWrite(ProblemDetailsContext context) \r\n        =&gt; context.HttpContext.Response.StatusCode == 400;\r\n\r\n    public Task WriteAsync(ProblemDetailsContext context)\r\n    {\r\n        \/\/Additional customizations\r\n\r\n        \/\/ Write to the response\r\n        context.HttpResponse.Response.WriteAsJsonAsync(context.ProblemDetails);\r\n    }        \r\n}<\/code><\/pre>\n<p>Register any <code>IProblemDetailsWriter<\/code> implementations before the call to the <code>AddProblemDetails<\/code> method:<\/p>\n<pre><code class=\"language-csharp\">builder.Services.AddSingleton&lt;IProblemDetailsWriter, CustomWriter&gt;();\r\nbuilder.Services.AddProblemDetails();<\/code><\/pre>\n<h2>Diagnostics middleware updates<\/h2>\n<p>The following middleware were updated to generated problem details HTTP responses when the new problem details service (<code>IProblemDetailsService<\/code>) is registered:<\/p>\n<ul>\n<li><code>ExceptionHandlerMiddleware<\/code>: Generates a problem details response when a custom handler is not defined, unless not accepted by the client.<\/li>\n<li><code>StatusCodePagesMiddleware<\/code>: Generates a problem details response by default, unless not accepted by the client.<\/li>\n<li><code>DeveloperExceptionPageMiddleware<\/code>: Generate a problem details response when <code>text\/html<\/code> is not accepted, unless not accepted by the client.<\/li>\n<\/ul>\n<p>The following sample configures the app to generate a problem details response for all HTTP client and server error responses that do not have a body content yet:<\/p>\n<pre><code class=\"language-csharp\">var builder = WebApplication.CreateBuilder(args);\r\n\r\n\/\/ Add services to the containers\r\nbuilder.Services.AddControllers();\r\nbuilder.Services.AddProblemDetails();\r\n\r\nvar app = builder.Build();\r\n\r\napp.UseExceptionHandler();\r\napp.UseStatusCodePages();\r\n\r\n\/\/Configure the HTTP request pipeline.\r\nif (app.Environment.IsDevelopment())\r\n{\r\n    app.UseDeveloperExceptionPage();\r\n}\r\n\r\napp.MapControllers();\r\napp.Run();<\/code><\/pre>\n<h2>New <code>HttpResults<\/code> interfaces<\/h2>\n<p>In <a href=\"https:\/\/devblogs.microsoft.com\/dotnet\/asp-net-core-updates-in-dotnet-7-preview-3\/#improved-unit-testability-for-minimal-route-handlers\">.NET 7 Preview 3<\/a> the types implementing <code>IResult<\/code> in ASP.NET Core were made public. Now, in this preview, we&#8217;re introducing new interfaces in the <code>Microsoft.AspNetCore.Http.Http<\/code> namespace to describe the <code>IResult<\/code> types:<\/p>\n<ul>\n<li><code>Microsoft.AspNetCore.Http.IContentTypeHttpResult<\/code><\/li>\n<li><code>Microsoft.AspNetCore.Http.IFileHttpResult<\/code><\/li>\n<li><code>Microsoft.AspNetCore.Http.INestedHttpResult<\/code><\/li>\n<li><code>Microsoft.AspNetCore.Http.IStatusCodeHttpResult<\/code><\/li>\n<li><code>Microsoft.AspNetCore.Http.IValueHttpResult<\/code><\/li>\n<li><code>Microsoft.AspNetCore.Http.IValueHttpResult&lt;TValue&gt;<\/code><\/li>\n<\/ul>\n<p>With these interfaces you now have a more generalized way to detect the <code>IResult<\/code> type at runtime, which is a common pattern in filter implementations.<\/p>\n<pre><code class=\"language-csharp\">app.MapGet(\"\/weatherforecast\", (int days) =&gt;\r\n{\r\n    if (days &lt;= 0)\r\n    {\r\n        return Results.BadRequest();\r\n    }\r\n\r\n    var forecast = Enumerable.Range(1, days.Value).Select(index =&gt;\r\n       new WeatherForecast (DateTime.Now.AddDays(index), Random.Shared.Next(-20, 55), \"Cool\"))\r\n        .ToArray();\r\n    return Results.Ok(forecast);\r\n}).\r\nAddEndpointFilter(async (context,next) =&gt;\r\n{\r\n    var result = await next(context);\r\n\r\n    return result switch\r\n    {\r\n        IValueHttpResult&lt;WeatherForecast[]&gt; weatherForecastResult =&gt; new WeatherHttpResult(weatherForecastResult.Value),\r\n        _ =&gt; result\r\n    };\r\n});\r\n\r\ninternal record WeatherForecast(DateTime Date, int TemperatureC, string? Summary)<\/code><\/pre>\n<h2>Give feedback<\/h2>\n<p>We hope you enjoy this preview release of ASP.NET Core in .NET 7. 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 7 Preview 7 is now available! Check out what&#8217;s new in ASP.NET Core in this update.<\/p>\n","protected":false},"author":417,"featured_media":41427,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[685,197,7509,7251],"tags":[],"class_list":["post-41426","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-dotnet","category-aspnet","category-aspnetcore","category-blazor"],"acf":[],"blog_post_summary":"<p>.NET 7 Preview 7 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\/41426","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=41426"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/posts\/41426\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/media\/41427"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/media?parent=41426"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/categories?post=41426"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/tags?post=41426"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}