{"id":7156,"date":"2023-05-26T13:58:25","date_gmt":"2023-05-26T13:58:25","guid":{"rendered":"https:\/\/www.ntspl.co.in\/blog\/?p=7156"},"modified":"2023-08-24T07:04:15","modified_gmt":"2023-08-24T07:04:15","slug":"asp-net-core-updates-in-net-8-preview-4","status":"publish","type":"post","link":"https:\/\/www.ntspl.co.in\/blog\/asp-net-core-updates-in-net-8-preview-4\/","title":{"rendered":"ASP.NET Core updates in .NET 8 Preview 4"},"content":{"rendered":"<p><a href=\"https:\/\/devblogs.microsoft.com\/dotnet\/announcing-dotnet-8-preview-4\">.NET 8 Preview 4 is now available<\/a> and includes many great new improvements to ASP.NET Core.<\/p>\n<p>Here\u2019s a summary of what\u2019s new in this preview release:<\/p>\n<ul>\n<li><a href=\"https:\/\/devblogs.microsoft.com\/dotnet\/#blazor\">Blazor<\/a>\n<ul>\n<li>Streaming rendering with Blazor components<\/li>\n<li>Handling form posts with Blazor SSR<\/li>\n<li>Route to named elements in Blazor<\/li>\n<li>Webcil packaging for Blazor WebAssembly apps<\/li>\n<\/ul>\n<\/li>\n<li><a href=\"https:\/\/devblogs.microsoft.com\/dotnet\/#api-authoring\">API authoring<\/a>\n<ul>\n<li>Expanded support for form binding in minimal APIs<\/li>\n<li>API project template includes <code>.http<\/code> file<\/li>\n<\/ul>\n<\/li>\n<li><a href=\"https:\/\/devblogs.microsoft.com\/dotnet\/#native-aot\">Native AOT<\/a>\n<ul>\n<li>Logging and exception handling in compile-time generated minimal APIs<\/li>\n<li>ASP.NET Core top-level APIs annotated for trim warnings<\/li>\n<li>Reduced app size with configurable HTTPS support<\/li>\n<li>Worker Service template updates<\/li>\n<li>Additional default services configured in the slim builder<\/li>\n<li>API template JSON configuration changes<\/li>\n<li>Support for JSON serialization of compiler-generated <code>IAsyncEnumerable<\/code> unspeakable types<\/li>\n<\/ul>\n<\/li>\n<li><a href=\"https:\/\/devblogs.microsoft.com\/dotnet\/#auth\">Authentication and authorization<\/a>\n<ul>\n<li>Identity API endpoints<\/li>\n<li>Improved support for custom authorization policies with <code>IAuthorizationRequirementData<\/code><\/li>\n<\/ul>\n<\/li>\n<li><a href=\"https:\/\/devblogs.microsoft.com\/dotnet\/#metrics\">ASP.NET Core metrics<\/a><\/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 4, <a href=\"https:\/\/dotnet.microsoft.com\/next\">install the .NET 8 SDK<\/a>.<\/p>\n<p>If you\u2019re 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 3 to .NET 8 Preview 4:<\/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.4.*<\/code>.<\/li>\n<li>Update all Microsoft.Extensions.* package references to <code>8.0.0-preview.4.*<\/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<p>&nbsp;<\/p>\n<h2>Blazor<\/h2>\n<h3>Streaming rendering with Blazor components<\/h3>\n<p>You can now stream content updates on the response stream when using server-side rendering (SSR) with Blazor in .NET 8. Streaming rendering can improve the user experience for server-side rendered pages that need to perform long-running async tasks in order to render fully.<\/p>\n<p>For example, to render a page you might need to make a long running database query or an API call. Normally all async tasks executed as part of rendering a page must complete before the rendered response can be sent, which can delay loading the page. Streaming rendering initially renders the entire page with placeholder content while async operations execute. Once the async operations completes, the updated content is sent to the client on the same response connection and then patched by Blazor into the DOM. The benefit of this approach is that the main layout of the app renders as quickly as possible and the page is updated as soon as the content is ready.<\/p>\n<p>To enable streaming rendering, you\u2019ll first need to add the new Blazor script.<\/p>\n<pre><code class=\"language-html\">&lt;script src=\"_framework\/blazor.web.js\" suppress-error=\"BL9992\"&gt;&lt;\/script&gt;<\/code><\/pre>\n<p>Note that if you\u2019re adding this script to a Blazor component, like your layout component, you\u2019ll need to add the <code>suppress-error=\"BL9992\"<\/code> attribute to avoid getting an error about using script tags in components.<\/p>\n<p>Then, to enable streaming rendering for a specific component, use the <code>[StreamRendering(true)]<\/code> attribute. Typically this is done using the <code>@attribute<\/code> Razor directive:<\/p>\n<pre><code class=\"language-razor\">@page \"\/fetchdata\"\r\n@using BlazorSSR.Data\r\n@inject WeatherForecastService ForecastService\r\n@attribute [StreamRendering(true)]\r\n\r\n&lt;PageTitle&gt;Weather forecast&lt;\/PageTitle&gt;\r\n\r\n&lt;h1&gt;Weather forecast&lt;\/h1&gt;\r\n\r\n@if (forecasts is null)\r\n{\r\n    &lt;p&gt;&lt;em&gt;Loading...&lt;\/em&gt;&lt;\/p&gt;\r\n}\r\nelse\r\n{\r\n    \/\/ Render weather forecasts\r\n}\r\n\r\n@code {\r\n    private string message;\r\n\r\n    protected override async Task OnInitializedAsync()\r\n    {\r\n        forecasts = await ForecastService.GetForecastAsync(DateOnly.FromDateTime(DateTime.Now));\r\n    }\r\n}<\/code><\/pre>\n<p>The component will now initially render without waiting for any async tasks to complete using placeholder content (\u201cLoading\u2026\u201d). As the async tasks complete, the updated content is streamed to the response and then patched by Blazor into the DOM.<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/dotnet\/wp-content\/uploads\/sites\/10\/2023\/05\/blazor-streaming-rendering.gif\" alt=\"Blazor streaming rendering\" \/><\/p>\n<h3>Handling form posts with Blazor SSR<\/h3>\n<p>You can now use Blazor components to handle form posts with server-side rendering.<\/p>\n<p>To enable handling form submissions from the server, you first need to setup a model binding context using the <code>CascadingModelBinder<\/code> component. An easy way to do this is in the main layout of your app:<\/p>\n<pre><code class=\"language-razor\">&lt;CascadingModelBinder&gt;\r\n    @Body\r\n&lt;\/CascadingModelBinder&gt;<\/code><\/pre>\n<p>To define a form in Blazor you use the existing <code>EditForm<\/code> component and the corresponding input components, like <code>InputText<\/code>, <code>InputSelect<\/code>, etc.<\/p>\n<p>The <code>EditForm<\/code> component will render a standard HTML <code>form<\/code> element, so you can use the <code>method<\/code> attribute to specify if the form should send POST request. The <code>EditForm<\/code> event handlers are not supported with GET requests.<\/p>\n<p>When the form is submitted, the request will be routed to the corresponding page and then handled by the form with the matching form handler name as specified by the <code>handler<\/code> query string parameter. You can specify the form handler name for an <code>EditForm<\/code> using the <code>FormHandlerName<\/code> attribute. If there\u2019s only one form on the page, then you don\u2019t need to specify a name. You can then handle the form submission using the <code>EditForm<\/code> events.<\/p>\n<p>Support for model binding and validating the request data hasn\u2019t been implemented yet (it\u2019s coming!), but you can manually handle the request data using the <code>FormDataProvider<\/code> service. The <code>FormDataProvider.Entries<\/code> property provides access to the form data and the <code>FormDataProvider.Name<\/code> property specifies the intended form handler.<\/p>\n<p>Here\u2019s what a simple server-side rendered form in Blazor looks like:<\/p>\n<pre><code class=\"language-razor\">@inject FormDataProvider FormData\r\n\r\n&lt;EditForm method=\"POST\" Model=\"exampleModel\" OnValidSubmit=\"HandleSubmit\"&gt;\r\n    &lt;InputText @bind-Value=\"exampleModel.Name\" \/&gt;\r\n    &lt;button type=\"submit\"&gt;Submit&lt;\/button&gt;\r\n&lt;\/EditForm&gt;\r\n\r\n@code {\r\n    ExampleModel exampleModel = new();\r\n\r\n    protected override void OnInitialized()\r\n    {\r\n        \/\/ Manually model bind the form data using the FormDataProvider service\r\n        if (FormData.Entries.TryGetValue(\"Name\", out var nameValues))\r\n        {\r\n            exampleModel.Name = nameValues.First();\r\n        }\r\n    }\r\n\r\n    void HandleSubmit()\r\n    {\r\n        \/\/ Handle the submitted form data\r\n    }\r\n\r\n    public class ExampleModel\r\n    {\r\n        public string? Name { get; set; }\r\n    }\r\n}<\/code><\/pre>\n<h3>Route to named elements in Blazor<\/h3>\n<p>Blazor now supports using client-side routing to navigate to a specific HTML element on a page using standard URL fragments. If you specify an identifier for an HTML element using the standard <code>id<\/code> attribute, Blazor will correctly scroll to that element when the URL fragment matches the element identifier.<\/p>\n<h3>Webcil packaging for Blazor WebAssembly apps<\/h3>\n<p>You can now try out the new Webcil package with Blazor WebAssembly apps. <a href=\"https:\/\/github.com\/dotnet\/runtime\/blob\/main\/docs\/design\/mono\/webcil.md\">Webcil<\/a> is web-friendly packaging of .NET assemblies that removes any content specific to native Windows execution to avoid issues when deploying to environments that block the download or use of .dll files.<\/p>\n<p>To enable use of Webcil for your Blazor WebAssembly apps, add the <code>WasmEnableWebcil<\/code> property to your project file:<\/p>\n<pre><code class=\"language-xml\">&lt;PropertyGroup&gt;\r\n    &lt;WasmEnableWebcil&gt;true&lt;\/WasmEnableWebcil&gt;\r\n&lt;\/PropertyGroup&gt;<\/code><\/pre>\n<p>If you encounter issues with using .webcil files in your environment, please let us know by <a href=\"https:\/\/github.com\/dotnet\/runtime\/issues\/new\">creating an issue on GitHub<\/a>.<\/p>\n<p>&nbsp;<\/p>\n<h2>API authoring<\/h2>\n<h3>Expanded support for form binding in minimal APIs<\/h3>\n<p>This preview introduces expanded support for binding to form types in minimal APIs.<br \/>\nForm-based parameters are now inferred without the need of the <code>FromForm<\/code> attribute.<br \/>\nSupport for form-based parameters includes: <code>IFormCollection<\/code>, <code>IFormFile<\/code>, and <code>IFormFileCollection<\/code>. OpenAPI metadata is inferred for form parameters to support integration with Swagger UI.<\/p>\n<p>The code sample below showcases implementing a minimal API that handles file uploads by leveraging inferred binding from the <code>IFormFile<\/code> type.<\/p>\n<pre><code class=\"language-csharp\">var app = WebApplication.Create();\r\n\r\nstring GetOrCreateFilePath(string fileName, string filesDirectory = \"uploadFiles\")\r\n{\r\n    var directoryPath = Path.Combine(app.Environment.ContentRootPath, filesDirectory);\r\n    Directory.CreateDirectory(directoryPath);\r\n    return Path.Combine(directoryPath, fileName);\r\n}\r\n\r\nasync Task UploadFileWithName(IFormFile file, string fileSaveName)\r\n{\r\n    var filePath = GetOrCreateFilePath(fileSaveName);\r\n    await using var fileStream = new FileStream(filePath, FileMode.Create);\r\n    await file.CopyToAsync(fileStream);\r\n}\r\n\r\napp.MapPost(\"\/upload\", async (IFormFile file) =&gt; {\r\n    var fileSaveName = Guid.NewGuid().ToString(\"N\") + Path.GetExtension(file.FileName);\r\n    await UploadFileWithName(file, fileSaveName);\r\n    return TypedResults.Ok(\"File uploaded successfully!\");\r\n});\r\n\r\napp.Run();<\/code><\/pre>\n<p>This feature is supported in minimal APIs that use runtime-based code generation <em>and<\/em> in minimal APIs leveraging <a href=\"https:\/\/devblogs.microsoft.com\/dotnet\/asp-net-core-updates-in-dotnet-8-preview-3\/#minimal-apis-and-native-aot\">the new compile-time code generation for Native AOT scenarios<\/a>.<\/p>\n<p>Note: It\u2019s important to be defensive against <a href=\"https:\/\/learn.microsoft.com\/aspnet\/core\/security\/anti-request-forgery?view=aspnetcore-7.0\">XSRF attacks<\/a> when implementing forms in an application. This <a href=\"https:\/\/gist.github.com\/captainsafia\/6b1f57026af53ae73bb5a2e58a68c4b8\">code sample<\/a> outlines how to use the anti-forgery services in ASP.NET to support the generation and validation of anti-forgery tokens in minimal APIs.<\/p>\n<p>&nbsp;<\/p>\n<h3>API project template includes <code>.http<\/code> file<\/h3>\n<p>The API project template (generated via <code>dotnet new api<\/code>) now includes an <code>.http<\/code> file that can be used to send requests to the endpoints defined within the application from <a href=\"https:\/\/devblogs.microsoft.com\/visualstudio\/web-api-development-in-visual-studio-2022\/\">the new HTTP editor in Visual Studio<\/a>.<\/p>\n<pre><code class=\"language-text\">@MyApi_HostAddress = http:\/\/localhost:5233\r\n\r\nGET {{MyApi_HostAddress}}\/todos\/\r\nAccept: application\/json\r\n\r\n###\r\n\r\nGET {{MyApi_HostAddress}}\/todos\/1\r\nAccept: application\/json\r\n\r\n###<\/code><\/pre>\n<p>&nbsp;<\/p>\n<h2>Native AOT<\/h2>\n<h3>Logging and exception handling in compile-time generated minimal APIs<\/h3>\n<p>Minimal APIs generated at runtime support automatically logging (or throwing exceptions in Development environments) when parameter binding fails. In this preview, we introduce the same support for APIs generated at compile-time via the <a href=\"https:\/\/devblogs.microsoft.com\/dotnet\/asp-net-core-updates-in-dotnet-8-preview-3\/#minimal-apis-and-native-aot\">Request Delegate Generator (RDG)<\/a>.<\/p>\n<p>Consider the following API endpoints where we\u2019ve enabled using the RDG by setting <code>&lt;EnableRequestDelegateGenerator&gt;true&lt;\/EnableRequestDelegateGenerator&gt;<\/code>:<\/p>\n<pre><code class=\"language-csharp\">var app = WebApplication.Create();\r\n\r\napp.MapGet(\"\/hello\/{name}\", (string name)\r\n    =&gt; $\"Hello {name}!\");\r\napp.MapGet(\"\/age\", (DateTime birthDate)\r\n    =&gt; $\"You're about {DateTime.Now.Year - birthDate.Year} years old!\");\r\n\r\napp.Run();<\/code><\/pre>\n<p>Sending the following request will throw a <code>BadHttpRequestException<\/code> since the required <code>name<\/code> parameter is not provided in the route or query string.<\/p>\n<pre><code class=\"language-console\">curl \"http:\/\/localhost:5056\/hello\"\r\nMicrosoft.AspNetCore.Http.BadHttpRequestException: Required parameter \"string name\" was not provided from route or query string.\r\n   ....\r\n   at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddlewareImpl.Invoke(HttpContext context)<\/code><\/pre>\n<p>Similarly, sending a request to the <code>\/age<\/code> endpoint with an unparsable <code>birthDate<\/code> value will throw an exception.<\/p>\n<pre><code class=\"language-console\">curl \"http:\/\/localhost:5056\/age?birthDate=invalidDate\"\r\nMicrosoft.AspNetCore.Http.BadHttpRequestException: Failed to bind parameter \"DateTime birthDate\" from \"invalidDate\".\r\n   ...\r\n   at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddlewareImpl.Invoke(HttpContext context)<\/code><\/pre>\n<h3>ASP.NET Core top-level APIs annotated for trim warnings<\/h3>\n<p>To help developers understand which features are incompatible with Native AOT, we\u2019ve annotated the main entry points to subsystems that do not work reliably with Native AOT. When these methods are called from an application with Native AOT enabled, developers will get a warning. For example, the following code snippet will produce a warning at the invocation of <code>AddControllers<\/code> to indicate that this API is not trim-safe.<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/dotnet\/wp-content\/uploads\/sites\/10\/2023\/05\/aot-warning-screenshot.png\" alt=\"Native AOT warnings for top-level APIs\" \/><\/p>\n<h3>Reduced app size with configurable HTTPS support<\/h3>\n<p>In Preview 4, we\u2019ve further reduced Native AOT binary size for apps that don\u2019t need HTTPS or HTTP\/3 support. This is quite common for apps that run behind a TLS termination proxy (e.g. hosted on Azure).<\/p>\n<p>When you use the new <code>WebApplication.CreateSlimBuilder<\/code>, by default this functionality won\u2019t be included. It can be re-added by calling <code>builder.WebHost.UseKestrelHttpsConfiguration()<\/code> or <code>builder.WebHost.UseQuic()<\/code>, respectively.<\/p>\n<p>As a result of these and other changes, we can update our <a href=\"https:\/\/devblogs.microsoft.com\/dotnet\/asp-net-core-updates-in-dotnet-8-preview-3\/#benefits-of-using-native-aot-with-asp-net-core\">table<\/a> from Preview 3:<\/p>\n<p>We ran a simple ASP.NET Core API app in our benchmarking lab to compare the differences in app size, memory use, startup time, and CPU load, published with and without native AOT:<\/p>\n<table>\n<thead>\n<tr>\n<th>Publish kind<\/th>\n<th>Startup time (ms)<\/th>\n<th>App size (MB)<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td>Default<\/td>\n<td>169<\/td>\n<td>88.5<\/td>\n<\/tr>\n<tr>\n<td>Native AOT \u2013 Preview 3<\/td>\n<td>34<\/td>\n<td>11.3<\/td>\n<\/tr>\n<tr>\n<td>Native AOT \u2013 Preview 4<\/td>\n<td>32<\/td>\n<td>9.3<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>Note the <strong>2 MB drop<\/strong> in app size.<\/p>\n<p>You can explore these and more metrics on our <a href=\"https:\/\/aka.ms\/aspnet\/nativeaot\/benchmarks\">public benchmarks dashboard<\/a>.<\/p>\n<h3>Worker Service template updates<\/h3>\n<p>The Worker Service templates in ASP.NET Core (available via <code>dotnet new worker<\/code>) now include support for the <code>--aot<\/code> flag to enable creating a worker service project with AOT publishing enabled.<\/p>\n<pre><code class=\"language-console\">dotnet new worker -o WorkerWithAot --aot<\/code><\/pre>\n<p>The templates have also been updated to leverage the simplified <code>HostApplicationBuilder<\/code> for configuring the application host.<\/p>\n<pre><code class=\"language-csharp\">using WorkerWithAot;\r\n\r\nvar builder = Host.CreateApplicationBuilder(args);\r\nbuilder.Services.AddHostedService&lt;Worker&gt;();\r\n\r\nvar host = builder.Build();\r\nhost.Run();<\/code><\/pre>\n<h3>Additional default services configured in the slim builder<\/h3>\n<p>The <code>WebApplication.CreateSlimBuilder<\/code> API, introduced in .NET 8 Preview 3, initializes the essential features in an app to minimize its deployed size. In .NET 8 Preview 4, we\u2019ve update the <code>SlimBuilder<\/code> to include the following features for an improved development experience, while still maintaining a total app size below 10 MB.<\/p>\n<ul>\n<li>JSON file configuration for <em>appsettings.json<\/em> and <em>appsettings.{EnvironmentName}.json<\/em><\/li>\n<li>User secrets configuration<\/li>\n<li>Console logging<\/li>\n<li>Logging configuration<\/li>\n<\/ul>\n<h3>API template JSON configuration changes<\/h3>\n<p>We introduced the new API project template in .NET 8 Preview 3. In Preview 4, projects created with this template using the <code>--aot<\/code> option, have changed to insert the app\u2019s source-generated <code>JsonSerializationContext<\/code> into the beginning of the <code>JsonSerializerOptions.TypeInfoResolverChain<\/code>. The previously generated code used the now-obsolete <code>JsonSerializerOptions.AddContext&lt;T&gt;<\/code> API and any project created with the Preview 3 version of the template should be updated to call the new API.<\/p>\n<p>You can read more about the new <code>JsonSerializerOptions.TypeInfoResolverChain<\/code> API in the <a href=\"https:\/\/devblogs.microsoft.com\/dotnet\/announcing-dotnet-8-preview-4\">.NET 8 Preview 4 blog post<\/a>.<\/p>\n<h3>Support for JSON serialization of compiler-generated <code>IAsyncEnumerable&lt;T&gt;<\/code> unspeakable types<\/h3>\n<p>Support for JSON serialization of <code>IAsyncEnumerable&lt;T&gt;<\/code> implementations implemented by the C# compiler is now supported, opening up their use in ASP.NET Core projects configured to publish native AOT. This is useful in scenarios where your route handler returns the result of calling an API that utilizes <code>IAsyncEnumerable&lt;T&gt;<\/code> and <code>yield return<\/code> to asynchonously return an enumeration, e.g. materializing rows from a database query (<a href=\"https:\/\/github.com\/aspnet\/Benchmarks\/blob\/7058cf6424321ecf5cc1442f8e1a0a06fdd5a19f\/src\/BenchmarksApps\/TodosApi\/TodoApi.cs#L16-L17\">example<\/a>).<\/p>\n<p>You can read more about the JSON serializer support for unspeakable types in the <a href=\"https:\/\/devblogs.microsoft.com\/dotnet\/announcing-dotnet-8-preview-4\">.NET 8 Preview 4 blog post<\/a>.<\/p>\n<p>&nbsp;<\/p>\n<h2>Authentication and Authorization<\/h2>\n<h3>Identity API endpoints<\/h3>\n<p>We\u2019re excited to introduce <code>MapIdentityApi&lt;TUser&gt;()<\/code> which is an extension method adds two new API endpoints (<code>\/register<\/code> and <code>\/login<\/code>). The main goal of the <code>MapIdentityApi<\/code> is to make it easy for developers to use ASP.NET Core Identity for authentication in JavaScript-based single page apps (SPA) or Blazor apps. Instead of using the default UI provided by ASP.NET Core Identity, which is based on Razor Pages, <code>MapIdentityApi<\/code> adds JSON API endpoints that are more suitable for SPA apps and non-browser apps.<\/p>\n<p>In addition to user registration and login, the identity API endpoints will support features like two-factor authentication and email verification in upcoming previews. You can find a list of planned features in the issues labeled <a href=\"https:\/\/github.com\/dotnet\/aspnetcore\/issues?q=is%3Aopen+label%3Afeature-token-identity+sort%3Aupdated-desc\">feature-token-identity<\/a> on the ASP.NET Core GitHub repository.<\/p>\n<p>The following shows the <code>Program.cs<\/code> of an ASP.NET Core app that uses <code>MapIdentityApi<\/code> to enable both opaque bearer token and cookie authentication. To individually enable cookie or token authentication, you can call the existing <code>AddCookie<\/code> or the new <code>AddBearerToken<\/code> <code>AuthenticationBuilder<\/code> extension methods directly. Both are done for you by the <code>AddIdentityApiEndpoints<\/code> method below:<\/p>\n<pre><code class=\"language-csharp\">\/\/ usings ... \r\n\r\nvar builder = WebApplication.CreateBuilder(args);\r\n\r\nbuilder.Services.AddAuthorization();\r\n\r\nbuilder.Services.AddDbContext&lt;ApplicationDbContext&gt;(\r\n    options =&gt; options.UseSqlite(builder.Configuration[\"ConnectionString\"]));\r\n\r\nbuilder.Services.AddIdentityApiEndpoints&lt;IdentityUser&gt;()\r\n    .AddEntityFrameworkStores&lt;ApplicationDbContext&gt;();\r\n\r\nvar app = builder.Build();\r\n\r\napp.MapGroup(\"\/identity\").MapIdentityApi&lt;IdentityUser&gt;();\r\n\r\napp.MapGet(\"\/requires-auth\", (ClaimsPrincipal user) =&gt; $\"Hello, {user.Identity?.Name}!\").RequireAuthorization();\r\n\r\napp.Run();\r\n\r\n\/\/ public class ApplicationDbContext : IdentityDbContext&lt;IdentityUser&gt; ...<\/code><\/pre>\n<p>On the client, you can call the <code>\/register<\/code> endpoint as follows assuming <code>httpClient<\/code>, <code>username<\/code> and <code>password<\/code> are already initialized in a .NET console app:<\/p>\n<pre><code class=\"language-csharp\">\/\/ Email confirmation will be added later.\r\n\/\/ The request body is: { \"username\": \"&lt;username&gt;\", \"password\": \"&lt;password&gt;\" }\r\nawait httpClient.PostAsJsonAsync(\"\/identity\/register\", new { username, password });<\/code><\/pre>\n<p>And you can sign in and get an opaque bearer token using the <code>\/login<\/code> endpoint:<\/p>\n<pre><code class=\"language-csharp\">\/\/ 2fa flow will be added later.\r\n\/\/ The request body is: { \"username\": \"&lt;username&gt;\", \"password\": \"&lt;password&gt;\" }\r\nvar loginResponse = await httpClient.PostAsJsonAsync(\"\/identity\/login\", new { username, password });\r\n\r\n\/\/ loginResponse is similar to the \"Access Token Response\" defined in the OAuth 2 spec\r\n\/\/ {\r\n\/\/   \"token_type\": \"Bearer\",\r\n\/\/   \"access_token\": \"...\",\r\n\/\/   \"expires_in\": 3600\r\n\/\/ }\r\n\/\/ refresh token is likely to be added later\r\nvar loginContent = await loginResponse.Content.ReadFromJsonAsync&lt;JsonElement&gt;();\r\nvar accessToken = loginContent.GetProperty(\"access_token\").GetString();\r\n\r\nhttpClient.DefaultRequestHeaders.Authorization = new(\"Bearer\", accessToken);\r\nConsole.WriteLine(await httpClient.GetStringAsync(\"\/requires-auth\"));<\/code><\/pre>\n<p>Or, if you want to get a cookie instead, you can set <code>?cookieMode=true<\/code> in the <code>\/login<\/code> query string:<\/p>\n<pre><code class=\"language-csharp\">\/\/ HttpClientHandler.UseCookies is true by default on supported platforms.\r\n\/\/ The request body is: { \"username\": \"&lt;username&gt;\", \"password\": \"&lt;password&gt;\" }\r\nawait httpClient.PostAsJsonAsync(\"\/identity\/login?cookieMode=true\", new { username, password });\r\n\r\nConsole.WriteLine(await httpClient.GetStringAsync(\"\/requires-auth\"));<\/code><\/pre>\n<p>We\u2019re looking forward to getting your feedback on our early work to improve the identity experience for SPA and mobile applications.<\/p>\n<h3>Improved support for custom authorization policies with <code>IAuthorizationRequirementData<\/code><\/h3>\n<p>Prior to this preview, adding a parameterized authorization policy to an endpoint required writing a lot of code.<\/p>\n<ul>\n<li>Implementing an <code>AuthorizeAttribute<\/code> for each policy<\/li>\n<li>Implementing an <code>AuthorizationPolicyProvider<\/code> to process a custom policy from a string-based contract<\/li>\n<li>Implementing an <code>AuthorizationRequirement<\/code> for the policy<\/li>\n<li>Implementing an <code>AuthorizationHandler<\/code> for each requirement<\/li>\n<\/ul>\n<p>A partial implementation of a custom parameterized policy is below. The <a href=\"https:\/\/gist.github.com\/captainsafia\/309e408cb5e2c2e5acd44d2e19f7f88e\">unabbreviated version<\/a> contains the complete code.<\/p>\n<pre><code class=\"language-csharp\">var builder = WebApplication.CreateBuilder();\r\n\r\nbuilder.Services.AddAuthentication().AddJwtBearer();\r\nbuilder.Services.AddAuthorization();\r\nbuilder.Services.AddSingleton&lt;IAuthorizationPolicyProvider, MinimumAgePolicyProvider&gt;();\r\nbuilder.Services.AddSingleton&lt;IAuthorizationHandler, MinimumAgeAuthorizationHandler&gt;();\r\n\r\nvar app = builder.Build();\r\n\r\napp.MapControllers();\r\n\r\napp.Run();\r\n\r\n[ApiController]\r\n[Route(\"api\/[controller]\")]\r\npublic class GreetingsController : Controller\r\n{\r\n    [MinimumAgeAuthorize(16)]\r\n    [HttpGet(\"hello\")]\r\n    public string Hello(ClaimsPrincipal user) =&gt; $\"Hello {(user.Identity?.Name ?? \"world\")}!\";\r\n}\r\n\r\nclass MinimumAgeAuthorizeAttribute : AuthorizeAttribute { }\r\n\r\nclass MinimumAgePolicyProvider : IAuthorizationPolicyProvider { }\r\n\r\nclass MinimumAgeRequirement : IAuthorizationRequirement { }\r\n\r\nclass MinimumAgeAuthorizationHandler : AuthorizationHandler&lt;MinimumAgeRequirement&gt; { }<\/code><\/pre>\n<p>This preview introduces the <code>IAuthorizationRequirementData<\/code> interface which allows the attribute definition to also specify the requirements associated with the authorization policy. By leveraging this change, we can reimplement our custom authorization policy with fewer lines of code. The <a href=\"https:\/\/gist.github.com\/captainsafia\/7c54e92d12df695ff0908e989fb8531f\">unabbreviated version<\/a> contains the complete code.<\/p>\n<pre><code class=\"language-csharp\">var builder = WebApplication.CreateBuilder();\r\n\r\nbuilder.Services.AddAuthentication().AddJwtBearer();\r\nbuilder.Services.AddAuthorization();\r\nbuilder.Services.AddSingleton&lt;IAuthorizationHandler, MinimumAgeAuthorizationHandler&gt;();\r\n\r\nvar app = builder.Build();\r\n\r\napp.MapControllers();\r\n\r\napp.Run();\r\n\r\n[ApiController]\r\n[Route(\"api\/[controller]\")]\r\npublic class GreetingsController : Controller\r\n{\r\n    [MinimumAgeAuthorize(16)]\r\n    [HttpGet(\"hello\")]\r\n    public string Hello(ClaimsPrincipal user) =&gt; $\"Hello {(user.Identity?.Name ?? \"world\")}!\";\r\n}\r\n\r\nclass MinimumAgeAuthorizeAttribute : AuthorizeAttribute, IAuthorizationRequirement, IAuthorizationRequirementData\r\n{\r\n    public MinimumAgeAuthorizeAttribute(int age) =&gt; Age =age;\r\n    public int Age { get; }\r\n\r\n    public IEnumerable&lt;IAuthorizationRequirement&gt; GetRequirements()\r\n    {\r\n        yield return this;\r\n    }\r\n}\r\n\r\nclass MinimumAgeAuthorizationHandler : AuthorizationHandler&lt;MinimumAgeAuthorizeAttribute&gt;\r\n{\r\n    protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, MinimumAgeAuthorizeAttribute requirement) { ... }\r\n}<\/code><\/pre>\n<p>&nbsp;<\/p>\n<h2>ASP.NET Core metrics<\/h2>\n<p>Metrics are measurements reported over time and are most often used to monitor the health of an app and to generate alerts. For example, a counter that reports failed HTTP requests could be displayed in dashboards or generate alerts when failures pass a threshold.<\/p>\n<p>This preview adds new metrics throughout ASP.NET Core using <a href=\"https:\/\/learn.microsoft.com\/dotnet\/core\/diagnostics\/compare-metric-apis#systemdiagnosticsmetrics\">System.Diagnostics.Metrics<\/a>. Metrics is a modern API for reporting and collecting information about your apps.<\/p>\n<p>Metrics offers a number of improvements compared to existing event counters:<\/p>\n<ul>\n<li>New kinds of measurements with counters, gauges and histograms<\/li>\n<li>Powerful reporting with multi-dimensional values<\/li>\n<li>Integration into the wider cloud native eco-system by aligning with OpenTelemetry standards<\/li>\n<\/ul>\n<p>Metrics have been added for <a href=\"https:\/\/github.com\/dotnet\/aspnetcore\/issues\/47536\">ASP.NET Core hosting, Kestrel and SignalR<\/a>. Expect more APIs across .NET to get metrics in the future.<\/p>\n<p>If you\u2019re interested in trying out metrics, we\u2019ve put together <a href=\"https:\/\/grafana.com\/\">Grafana<\/a> dashboards that report ASP.NET Core metrics collected by <a href=\"https:\/\/prometheus.io\/\">Prometheus<\/a>. You can get the dashboards at the <a href=\"https:\/\/github.com\/JamesNK\/aspnetcore-grafana\">aspnetcore-grafana repository<\/a> and import them into your own Grafana environment.<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/dotnet\/wp-content\/uploads\/sites\/10\/2023\/05\/grafana.png\" alt=\"ASP.NET Core Grafana dashboard\" \/><\/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<p>The post <a href=\"https:\/\/devblogs.microsoft.com\/dotnet\/asp-net-core-updates-in-dotnet-8-preview-4\/\" rel=\"nofollow\">ASP.NET Core updates in .NET 8 Preview 4<\/a> appeared first on <a href=\"https:\/\/devblogs.microsoft.com\/dotnet\" rel=\"nofollow\">.NET Blog<\/a>.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>.NET 8 Preview 4 is now available and includes many great new improvements to ASP.NET Core. Here\u2019s a summary of what\u2019s new in this preview release: Blazor Streaming rendering with Blazor components Handling form posts with Blazor SSR Route to named elements in Blazor Webcil packaging for Blazor WebAssembly apps API authoring Expanded support for [&hellip;]<\/p>\n","protected":false},"author":42,"featured_media":7215,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[3,438],"tags":[537,55,538],"class_list":["post-7156","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-asp-dot-net","category-technology","tag-net-8-0","tag-asp-net","tag-asp-net-features"],"acf":{"custom_meta_title":"Boost Apps with ASP.NET Core: Discover .NET 8 Preview 4","meta_description":"Supercharge your applications with ASP.NET Core! Dive into the exciting world of .NET 8 Preview 4 and unlock its powerful features. Elevate your development game and stay at the forefront of innovation. Read this Blog to Know more!","meta_keyword":"Top Features of ASP.NET Core, ASP.NET Core Updates, Preview of .NET 8.0","other_meta_tag":"<meta property=og:type content=\"article\" \/>\r\n<meta property=og:title content=\"Boost Apps with ASP.NET Core: Discover .NET 8 Preview 4\"\/>\r\n<meta property=og:description content=\"Supercharge your applications with ASP.NET Core! Dive into the exciting world of .NET 8 Preview 4 and unlock its powerful features. Elevate your development game and stay at the forefront of innovation. Read this Blog to Know more!\"\/>\r\n<meta property=\"og:image\" content=\"https:\/\/www.ntspl.co.in\/blog\/wp-content\/uploads\/2023\/05\/ASP.jpg\"\/>\r\n<meta property=og:url content=\"https:\/\/www.ntspl.co.in\/blog\/asp-net-core-updates-in-net-8-preview-4\/\"\/>\r\n<meta property=og:site_name content=NTSPL \/>\r\n<meta name=\"twitter:site\" content=\"@NTSPL\">\r\n<meta name=twitter:card content=\"summary\" \/>\r\n<meta name=twitter:description content=\"Supercharge your applications with ASP.NET Core! Dive into the exciting world of .NET 8 Preview 4 and unlock its powerful features. Elevate your development game and stay at the forefront of innovation. Read this Blog to Know more!\"\/>\r\n<meta name=twitter:title content=\"Boost Apps with ASP.NET Core: Discover .NET 8 Preview 4\"\/>"},"_links":{"self":[{"href":"https:\/\/www.ntspl.co.in\/blog\/wp-json\/wp\/v2\/posts\/7156"}],"collection":[{"href":"https:\/\/www.ntspl.co.in\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.ntspl.co.in\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.ntspl.co.in\/blog\/wp-json\/wp\/v2\/users\/42"}],"replies":[{"embeddable":true,"href":"https:\/\/www.ntspl.co.in\/blog\/wp-json\/wp\/v2\/comments?post=7156"}],"version-history":[{"count":4,"href":"https:\/\/www.ntspl.co.in\/blog\/wp-json\/wp\/v2\/posts\/7156\/revisions"}],"predecessor-version":[{"id":7872,"href":"https:\/\/www.ntspl.co.in\/blog\/wp-json\/wp\/v2\/posts\/7156\/revisions\/7872"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.ntspl.co.in\/blog\/wp-json\/wp\/v2\/media\/7215"}],"wp:attachment":[{"href":"https:\/\/www.ntspl.co.in\/blog\/wp-json\/wp\/v2\/media?parent=7156"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.ntspl.co.in\/blog\/wp-json\/wp\/v2\/categories?post=7156"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.ntspl.co.in\/blog\/wp-json\/wp\/v2\/tags?post=7156"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}