{"id":37164,"date":"2021-09-14T11:24:55","date_gmt":"2021-09-14T18:24:55","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/aspnet\/?p=25139"},"modified":"2021-09-14T11:24:55","modified_gmt":"2021-09-14T18:24:55","slug":"asp-net-core-updates-in-net-6-rc-1","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/dotnet\/asp-net-core-updates-in-net-6-rc-1\/","title":{"rendered":"ASP.NET Core updates in .NET 6 Release Candidate 1"},"content":{"rendered":"<p><a href=\"https:\/\/devblogs.microsoft.com\/dotnet\/announcing-net-6-rc1\/\">.NET 6 Release Candidate 1 (RC1) is now available<\/a> and includes many great new improvements to ASP.NET Core.<\/p>\n<p>Here&#8217;s what&#8217;s new in this preview release:<\/p>\n<ul>\n<li>Render Blazor components from JavaScript<\/li>\n<li>Blazor custom elements<\/li>\n<li>Manipulate the query string from Blazor<\/li>\n<li>.NET to JavaScript streaming<\/li>\n<li><code>PageX<\/code> and <code>PageY<\/code> in <code>MouseEventArgs<\/code><\/li>\n<li>Blazor templates updated to set page titles<\/li>\n<li>Disabled long-polling transport for Blazor Server<\/li>\n<li>Collocate JavaScript files with pages, views, and components<\/li>\n<li>JavaScript initializers<\/li>\n<li>Customize Blazor WebAssembly packaging<\/li>\n<li>Template improvements<\/li>\n<li>Minimal API updates<\/li>\n<li>Support for Latin1 encoded request headers in <code>HttpSysServer<\/code><\/li>\n<li>Emit <code>KestrelServerOptions<\/code> via <code>EventSource<\/code> event<\/li>\n<li>Add timestamps and PID to ASP.NET Core Module logs<\/li>\n<li>New <code>DiagnosticSource<\/code> event for rejected HTTP requests<\/li>\n<li>Create a <code>ConnectionContext<\/code> from an Accept Socket<\/li>\n<li>Streamlined HTTP\/3 setup<\/li>\n<li>Upgrade to Duende Identity Server<\/li>\n<\/ul>\n<h2>Get started<\/h2>\n<p>To get started with ASP.NET Core in .NET 6 RC1, <a href=\"https:\/\/dotnet.microsoft.com\/download\/dotnet\/6.0\">install the .NET 6 SDK<\/a>.<\/p>\n<p>If you&#8217;re on Windows using Visual Studio, <a href=\"https:\/\/aka.ms\/vs2022preview\">install the latest preview of Visual Studio 2022<\/a>. Support for .NET 6 in Visual Studio for Mac is coming soon, and is currently available as a <a href=\"https:\/\/visualstudio.microsoft.com\/vs\/mac\/preview\/\">private preview<\/a>.<\/p>\n<p>To get setup with .NET MAUI &amp; Blazor for cross-platform native apps, see the latest instructions in the <a href=\"https:\/\/docs.microsoft.com\/dotnet\/maui\/get-started\/installation\">.NET MAUI getting started guide<\/a>. Please also read <a href=\"https:\/\/aka.ms\/maui-update\">this important update on .NET MAUI<\/a>.<\/p>\n<p>To install the .NET WebAssembly build tools, run the following command from an elevated command prompt:<\/p>\n<pre><code>dotnet workload install wasm-tools\n<\/code><\/pre>\n<p>Alternative, use the Visual Studio Installer to enable the &#8220;.NET WebAssembly build tools&#8221; optional component in the &#8220;ASP.NET and web development&#8221; workload.<\/p>\n<h2>Upgrade an existing project<\/h2>\n<p>To upgrade an existing ASP.NET Core app from .NET 6 Preview 7 to .NET 6 RC1:<\/p>\n<ul>\n<li>Update all Microsoft.AspNetCore.* package references to <code>6.0.0-rc.1.*<\/code>.<\/li>\n<li>Update all Microsoft.Extensions.* package references to <code>6.0.0-rc.1.*<\/code>.<\/li>\n<\/ul>\n<p>To upgrade a .NET MAUI Blazor app from .NET 6 Preview 7 to .NET 6 RC1 we recommend starting from a new .NET MAUI Blazor project created with the .NET 6 RC1 SDK and then copying code over from your original project.<\/p>\n<p>See the full list of <a href=\"https:\/\/docs.microsoft.com\/dotnet\/core\/compatibility\/6.0#aspnet-core\">breaking changes<\/a> in ASP.NET Core for .NET 6.<\/p>\n<h2>Render Blazor components from JavaScript<\/h2>\n<p>Blazor is great for building client-side web UI using just .NET, but what if you already have existing JavaScript apps that you need to maintain and evolve? How can you avoid having to build common components twice, in .NET and JavaScript?<\/p>\n<p>In .NET 6, you can now dynamically render Blazor components from JavaScript. This capability enables you to integrate Blazor components with existing JavaScript apps.<\/p>\n<p>To render a Blazor component from JavaScript, first register it as a root component for JavaScript rendering and assign it an identifier:<\/p>\n<p><em>Blazor Server<\/em><\/p>\n<pre><code class=\"csharp\">builder.Services.AddServerSideBlazor(options =&gt;\n{\n    options.RootComponents.RegisterForJavaScript&lt;Counter&gt;(identifier: \"counter\");\n});\n<\/code><\/pre>\n<p><em>Blazor WebAssembly<\/em><\/p>\n<pre><code class=\"csharp\">builder.RootComponents.RegisterForJavaScript&lt;Counter&gt;(identifier: \"counter\");\n<\/code><\/pre>\n<p>Load Blazor into your JavaScript app (<em>blazor.server.js<\/em> or <em>blazor.webassembly.js<\/em>) and then render the component from JavaScript into a container element using the registered identifier, passing component parameters as needed:<\/p>\n<pre><code class=\"js\">let containerElement = document.getElementById('my-counter');\nawait Blazor.rootComponents.add(containerElement, 'counter', { incrementAmount: 10 });\n<\/code><\/pre>\n<h2>Blazor custom elements<\/h2>\n<p>Experimental support is also now available for building custom elements with Blazor using the <a href=\"https:\/\/www.nuget.org\/packages\/microsoft.aspnetcore.components.customelements\">Microsoft.AspNetCore.Components.CustomElements<\/a> NuGet package. Custom elements use <a href=\"https:\/\/html.spec.whatwg.org\/multipage\/custom-elements.html#custom-elements\">standard HTML interfaces<\/a> to implement custom HTML elements.<\/p>\n<p>To create a custom element using Blazor, register a Blazor root component as custom elements like this:<\/p>\n<pre><code class=\"csharp\">options.RootComponents.RegisterAsCustomElement&lt;Counter&gt;(\"my-counter\");\n<\/code><\/pre>\n<p>You can then use this custom element with any other web framework you&#8217;d like. For example, here&#8217;s how you would use this Blazor counter custom element in a React app:<\/p>\n<pre><code class=\"html\">&lt;my-counter increment-amount={incrementAmount}&gt;&lt;\/my-counter&gt;\n<\/code><\/pre>\n<p>See the <a href=\"https:\/\/github.com\/aspnet\/AspLabs\/tree\/main\/src\/BlazorCustomElements\">Blazor Custom Elements<\/a> sample project for a complete example of how to create custom elements with Blazor.<\/p>\n<p>This feature is experimental because we&#8217;re still working out some of the details for how best to support custom elements with Blazor. We welcome your feedback on how well this particular approach meets your requirements.<\/p>\n<h2>Generate Angular and React components using Blazor<\/h2>\n<p>You can also now generate framework specific JavaScript components from Blazor components for frameworks like Angular or React. This capability isn&#8217;t included with .NET 6, but is enabled by the new support for rendering Blazor components from JavaScript. The <a href=\"https:\/\/aka.ms\/blazor-js-components\">JavaScript component generation sample<\/a> on GitHub demonstrates how you can generate Angular and React components from Blazor components.<\/p>\n<p>In this sample, you attribute Blazor components to generate Angular or React component wrappers:<\/p>\n<pre><code class=\"razor\">@*Generate an Angular component*@\n@attribute [GenerateAngular]\n\n@*Generate an React component*@\n@attribute [GenerateReact]\n<\/code><\/pre>\n<p>You then register the Blazor components as Angular or React components:<\/p>\n<pre><code class=\"csharp\">options.RootComponents.RegisterForAngular&lt;Counter&gt;();\n<\/code><\/pre>\n<pre><code class=\"csharp\">options.RootComponents.RegisterForReact&lt;Counter&gt;();\n<\/code><\/pre>\n<p>When the project gets built, it generates Angular and React components based on your Blazor components. You then use the generated Angular and React components like you would normally:<\/p>\n<pre><code class=\"html\">\/\/ Angular\n&lt;counter [incrementAmount]=\"incrementAmount\"&gt;&lt;\/counter&gt;\n<\/code><\/pre>\n<pre><code class=\"html\">\/\/ React\n&lt;Counter incrementAmount={incrementAmount}&gt;&lt;\/Counter&gt;\n<\/code><\/pre>\n<p>This sample isn&#8217;t a complete solution for generating Angular and React components from Blazor components, but we hope it demonstrates what&#8217;s possible. We welcome and encourage community efforts to build on this functionality more fully. We&#8217;re excited to see what the community does with this feature!<\/p>\n<h2>Manipulate the query string from Blazor<\/h2>\n<p>New <code>GetUriWithQueryParameter<\/code> and <code>GetUriWithQueryParameters<\/code> extension methods on <code>NavigationManager<\/code> facilitate updating the query string of the browser URL.<\/p>\n<p>To add or update a single query string parameter:<\/p>\n<pre><code class=\"csharp\">\/\/ Create a new URI based on the current address\n\/\/ with the specified query string parameter added or updated.\nvar newUri = NavigationManager.GetUriWithQueryParameter(\"page\", 3);\n\n\/\/ Navigate to the new URI with the updated query string\nNavigationManager.NavigateTo(newUri);\n<\/code><\/pre>\n<p>Use <code>GetUriWithQueryParameters<\/code> to add, update, or remove multiple parameters based on a dictionary of parameter values (a <code>null<\/code> value removes the parameter).<\/p>\n<h2>.NET to JavaScript streaming<\/h2>\n<p>Blazor now supports streaming data from .NET to JavaScript. A .NET stream can be passed to JavaScript as a <code>DotNetStreamReference<\/code>.<\/p>\n<pre><code class=\"csharp\">using var data = new System.IO.MemoryStream(new byte[100 * 1024]);\nusing var streamRef = new DotNetStreamReference(stream: data, leaveOpen: false);\nawait JS.InvokeVoidAsync(\"consumeStream\", streamRef);\n<\/code><\/pre>\n<p>In JavaScript, the data stream can then be read as an array buffer or as a readable stream:<\/p>\n<pre><code class=\"js\">async function consumeStream(streamRef) {\n    const data = await streamRef.arrayBuffer();    \/\/ ArrayBuffer\n    \/\/ or\n    const stream = await streamRef.stream();       \/\/ ReadableStream\n}\n<\/code><\/pre>\n<p>Additional details on this feature are available in the Blazor <a href=\"https:\/\/docs.microsoft.com\/en-us\/aspnet\/core\/blazor\/javascript-interoperability\/call-javascript-from-dotnet?view=aspnetcore-6.0#stream-from-net-to-javascript\">JavaScript interop docs<\/a>.<\/p>\n<h2><code>PageX<\/code> and <code>PageY<\/code> in <code>MouseEventArgs<\/code><\/h2>\n<p><code>MouseEventArgs<\/code> now has <code>PageX<\/code> and <code>PageY<\/code> properties corresponding to the standard <a href=\"https:\/\/developer.mozilla.org\/docs\/Web\/API\/MouseEvent\/pageX\">pagex<\/a> and <a href=\"https:\/\/developer.mozilla.org\/docs\/Web\/API\/MouseEvent\/pageY\">pagey<\/a> on the <code>MouseEvent<\/code> interface. Thank you <a href=\"https:\/\/github.com\/TonyLugg\">TonyLugg<\/a> for helping us fill this functional gap.<\/p>\n<h2>Blazor templates updated to set page title<\/h2>\n<p>The Blazor project templates have been updated to support updating the page title as the user navigates to different pages using the new <code>PageTitle<\/code> and <code>HeadOutlet<\/code> components.<\/p>\n<p>In the Blazor WebAssembly template, the <code>HeadOutlet<\/code> component is added as a root component that appends to the HTML head tag. Each page in the template sets the title using the <code>PageTitle<\/code> component.<\/p>\n<p>The Blazor Server template required a bit more refactoring in order to support modifying the head when prerendering. The <em>_Host.cshtml<\/em> page now has its own layout, <em>_Layout.cshtml<\/em>, that adds the <code>HeadOutlet<\/code> component to the HTML head using the component tag helper. This ensures that the <code>HeadOutlet<\/code> is rendered before any components that want to modify the head.<\/p>\n<h2>Disabled long-polling transport for Blazor Server<\/h2>\n<p>Prior to .NET 6, Blazor Server apps would fall back to long-polling when WebSockets weren&#8217;t available, which often led to a degraded user experience. In .NET 6 we&#8217;ve disabled the long-polling transport for Blazor Server apps by default so that it&#8217;s easier to know when WebSockets haven&#8217;t been correctly configured. If your Blazor Server app still requires support for long-polling, you can reenable it. See the related <a href=\"https:\/\/docs.microsoft.com\/en-us\/dotnet\/core\/compatibility\/aspnet-core\/6.0\/blazor-long-polling-fallback\">breaking change notification<\/a> for details.<\/p>\n<h2>Collocate JavaScript files with pages, views, and components<\/h2>\n<p>You can now collocate a JavaScript file with pages, views, and components using the <em>.cshtml.js<\/em> and <em>.razor.js<\/em> conventions. This is a convenient way to organize your code when you have JavaScript code that is specific to a page, view, or component. These files are publicly addressable using the path to the file in the project (<code>Pages\/Index.cshtml.js<\/code> or <code>_content\/{LIBRARY NAME}\/Pages\/Index.cshtml.js<\/code> if the file is coming from a library).<\/p>\n<p>For example, if you have a component implemented by <em>Pages\/Counter.razor<\/em>, you can add a JavaScript module for that component at <em>Pages\/Counter.razor.js<\/em> and then load it like this:<\/p>\n<pre><code class=\"csharp\">var module = await JS.InvokeAsync&lt;IJSObjectReference&gt;(\"import\", \".\/Pages\/Counter.razor.js\");\n<\/code><\/pre>\n<h2>JavaScript initializers<\/h2>\n<p>JavaScript initializers provide a way to execute some logic before and after a Blazor app loads. This is useful for customizing how a Blazor app loads, initializing libraries before Blazor starts up, and configuring Blazor settings.<\/p>\n<p>To define a JavaScript initializer, add a JavaScript module to the web root of your project named <em>{LIBRARY NAME}.lib.module.js<\/em>. Your module can export the following well-known functions:<\/p>\n<ul>\n<li><code>beforeStart<\/code>: Called before Blazor boots up on the .NET side. Used to customize the loading process, logging level, and other hosting model specific options. \n<ul>\n<li>In Blazor WebAssembly, <code>beforeStart<\/code> receives the Blazor WebAssembly options and any extensions added during publishing.<\/li>\n<li>In Blazor Server, <code>beforeStart<\/code> receives the circuit start options.<\/li>\n<li>In BlazorWebViews, no options are passed.<\/li>\n<\/ul>\n<\/li>\n<li><code>afterStarted<\/code>: Called after Blazor is ready to receive calls from JavaScript. Used to initialize libraries by making .NET interop calls, registering custom elements, etc. \n<ul>\n<li>The <code>Blazor<\/code> instance is always passed to <code>afterStarted<\/code> as an argument.<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<p>A basic JavaScript initializer looks like this:<\/p>\n<p><em>RazorClassLibrary1.lib.module.js<\/em><\/p>\n<pre><code class=\"js\">export function beforeStart(options) {\n    console.log(\"beforeStart\");\n}\nexport function afterStarted(blazor) {\n    console.log(\"afterStarted\");\n}\n<\/code><\/pre>\n<p>JavaScript initializers are detected as part of the build and then imported automatically in Blazor apps. This removes the need in many cases for manually adding script references when using Blazor libraries.<\/p>\n<h2>Customize Blazor WebAssembly packaging<\/h2>\n<p>In some environments, firewalls or other security software block the download of .NET assemblies, which prevents the execution of Blazor WebAssembly apps. To enable support for Blazor WebAssembly in these environments, we&#8217;ve made the publishing and loading process for Blazor WebAssembly apps extensible so that you can customize the packaging and loading of the app. We&#8217;ll share more details on how to do this in a future post.<\/p>\n<h2>Template improvements<\/h2>\n<h3>Implicit usings<\/h3>\n<p>Based on feedback from Preview 7, <a href=\"https:\/\/github.com\/dotnet\/sdk\/issues\/19521\">changes to the implicit usings feature were made as part of this release<\/a>, including the requirement to opt-in to implicit usings in the project file, rather than them being included by default based on the project targeting .NET 6. This will ensure existing projects being migrated to .NET 6 aren&#8217;t impacted by the implicit usings until the author is ready to enable the feature.<\/p>\n<p>You can read more about this change in its <a href=\"https:\/\/docs.microsoft.com\/en-us\/dotnet\/core\/compatibility\/sdk\/6.0\/implicit-namespaces-rc1\">breaking changes document<\/a>.<\/p>\n<h3>Randomized port allocation<\/h3>\n<p>New ASP.NET Core projects will now have random ports assigned during project creation for use by the Kestrel web server, matching the existing behavior when using IIS Express. This helps to minimize the chance that new projects end up using ports that are already in use on the machine, which results in a failure of the app to start when it&#8217;s launched from Visual Studio, or via <code>dotnet run<\/code>.<\/p>\n<p>A port from 5000-5300 will be selected for HTTP, and from 7000-7300 for HTTPS, at the time the project is created. As always, the ports used during development can be easily changed by editing the project&#8217;s <em>launchSettings.json<\/em> file. When the app is run after publishing, Kestrel still defaults to using ports 5000 and 5001 (for HTTP and HTTPS respectively) if not otherwise configured. You can read more about <a href=\"https:\/\/docs.microsoft.com\/en-us\/aspnet\/core\/fundamentals\/servers\/kestrel\/endpoints\">configuring Kestrel in the docs<\/a>.<\/p>\n<h3>New logging defaults<\/h3>\n<p>New ASP.NET Core projects have a simplified logging configuration in their <em>appsettings.json<\/em> and <em>appsettings.Development.json<\/em> files.<\/p>\n<pre><code class=\"json\">{\n  \"Logging\": {\n    \"LogLevel\": {\n      \"Default\": \"Information\",\n      \"Microsoft.AspNetCore\": \"Warning\"\n    }\n  }\n}\n<\/code><\/pre>\n<p>The net effect of this change is that log messages at the &#8220;Information&#8221; level from sources other than ASP.NET Core, will now be emitted by default. This includes messages related to relational database querying from Entity Framework Core, which are now clearly visible by default in new applications:<\/p>\n<pre><code>info: Microsoft.Hosting.Lifetime[14]\n      Now listening on: https:\/\/localhost:7297\ninfo: Microsoft.Hosting.Lifetime[14]\n      Now listening on: http:\/\/localhost:5131\ninfo: Microsoft.Hosting.Lifetime[0]\n      Application started. Press Ctrl+C to shut down.\ninfo: Microsoft.Hosting.Lifetime[0]\n      Hosting environment: Development\ninfo: Microsoft.Hosting.Lifetime[0]\n      Content root path: C:\\Users\\MyName\\source\\repos\\WebApplication45\\WebApplication45\ninfo: Microsoft.EntityFrameworkCore.Database.Command[20101]\n      Executed DbCommand (25ms) [Parameters=[], CommandType='Text', CommandTimeout='30']\n      SELECT [w].[Id], [w].[Name]\n      FROM [Widget] AS [w]\n<\/code><\/pre>\n<h2>Minimal API updates<\/h2>\n<h3>Improved support for OpenAPI<\/h3>\n<p>In RC1, we improved support for OpenAPI by adding ways to define metadata on a minimal endpoint either imperatively via extensions methods or declaratively via attributes.<\/p>\n<p>We added support for the following metadata:<\/p>\n<ul>\n<li><code>WithName<\/code> metadata maps the endpoint name to an operationId in generated OpenAPI documents. \n<ul>\n<li>Note the endpoint name is also used when using <code>LinkGenerator<\/code> to generate URL\/links for endpoints<\/li>\n<li>When the user does not specify the endpoint name using the <code>WithName<\/code> metadata, the operation id will default to the name of the function (<code>SayHello<\/code>) as shown in the following example:<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<pre><code class=\"csharp\">string SayHello(string name) =&gt; $\"Hello, {name}!\";\napp.MapGet(\"\/hello\/{name}\", SayHello);\n<\/code><\/pre>\n<ul>\n<li><code>WithGroupName<\/code> metadata maps the endpoint group name to the document name in generated OpenAPI documents (typically used for versioning, e.g. &#8220;v1&#8221;, &#8220;v2&#8221;)<\/li>\n<li><code>ExcludeFromDescription<\/code> metadata indicates that the API should be excluded\/ignored from OpenAPI document generation<\/li>\n<li><code>ProducesValidationProblem<\/code> indicates that the endpoint will produce 4xx http status codes and error details with <code>application\/validationproblem+json<\/code> content type<\/li>\n<li><code>Produces&lt;T&gt;(...)<\/code> metadata indicates what response types a method produces, where each response is the combination of: \n<ul>\n<li>One HTTP status code<\/li>\n<li>One or more content types, e.g. &#8220;application\/json&#8221;<\/li>\n<li>An optional schema per content type<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<p><strong>Examples<\/strong><\/p>\n<p>OpenAPI extension methods can be used to imperatively add the required metadata to the endpoint:<\/p>\n<pre><code class=\"csharp\">app.MapGet(\"\/admin\", () =&gt; \"For admins only\")\n   .WithName(\"AdminDetails\")\n   .RequiresAuthorization(\"Admins\")\n   .ExcludeFromDescription();\n\napp.MapPost(\"\/todos\", async (Todo todo, TodoDb db) =&gt;\n    {\n        db.Todos.Add(todo);\n        await db.SaveChangesAsync();\n\n        return Results.CreatedAtRoute(\"GetTodoById\", new { todo.Id }, todo);\n    })\n    .WithName(\"AddTodo\")\n    .WithGroupName(\"v1\")\n    .ProducesValidationProblem()\n    .Produces&lt;Todo&gt;(StatusCodes.Status201Created);\n<\/code><\/pre>\n<p>In addition to extension methods, attributes can be used to add metadata declaratively on endpoints:<\/p>\n<pre><code class=\"csharp\">app.MapGet(\"\/admin\", AdminDetails);\napp.MapPost(\"\/todos\", AddTodo);\n\n[Authorized(Policy = \"Admins\")]\n[ExcludeFromDescription]\nstring AdminDetails()\n{\n    return \"For admins only\";\n}\n\n[EndpointGroupName(\"v1\")]\n[ProducesResponseType(typeof(ValidationProblemDetails), StatusCodes.Status400BadRequest, \"application\/problem+json\")]\n[ProducesResponseType(typeof(Todo), StatusCodes.Status201Created)]\nasync Task&lt;IResult&gt; AddTodo(Todo todo, TodoDb db)\n{\n    db.Todos.Add(todo);\n    await db.SaveChangesAsync();\n\n    return Results.Created($\"\/todos\/{todo.Id}\", todo);\n}\n<\/code><\/pre>\n<h3>Parameter Binding improvements<\/h3>\n<h4>Allow optional parameters in endpoint actions<\/h4>\n<p>We introduced support to allow developers to specify if parameters in their minimal action are optional.<\/p>\n<p>For example, we can designate <code>name<\/code> as an optional route parameter in the sample below:<\/p>\n<pre><code class=\"csharp\">app.MapGet(\"\/sayHello\/{name?}\", (string? name) =&gt; $\"Hello World from {name}\");\n<\/code><\/pre>\n<p>This indicates that both of the following calls will succeed by returning 2xx status code since the <code>name<\/code> parameter is optional.<br \/>\n<code>curl localhost:5000\/sayHello\/John<\/code> and <code>curl localhost:5000\/sayHello<\/code>.<\/p>\n<p>The same behavior applies for request bodies. The following example will call the method with a <code>null<\/code> todo when there is no a request body sent in a post\/put call:<\/p>\n<pre><code class=\"csharp\">app.MapPost(\"\/todos\", (Todo? todo) =&gt; () =&gt; { });\n<\/code><\/pre>\n<p>Route parameters, query parameters, and body parameters can all be designated as optional by using a nullability annotation or providing a default value. When a required parameter is not provided, the delegate will return a 400 status.<\/p>\n<p>As part of the changes, we also improved error messages when parameters fail to bind.<\/p>\n<h4>Fix issue with <code>struct<\/code> support in parameter binding<\/h4>\n<p>In Preview 7, binding a <code>struct<\/code> parameter did not work and would throw an <code>System.InvalidOperationException: The binary operator Equal is not defined for the types 'Contact' and 'System.Object'<\/code>. In RC1, we fixed the issue.<\/p>\n<p>Now it&#8217;s possible for developers to write the code below for a minimal API:<\/p>\n<pre><code class=\"csharp\">var app = WebApplication.Create(args);\n\napp.MapPost(\"\/api\/contact\", (Contact contact) =&gt; $\"{contact.PhoneNumber} {contact.Email}\");\n\napp.Run();\n\nrecord struct Contact(string PhoneNumber, string Email);\n<\/code><\/pre>\n<h3>Developer Exception Page Middleware change<\/h3>\n<p>With RC1, the <code>DeveloperExceptionPageMiddleware<\/code> will now be registered as the first middleware if the current environment is development. This means when <code>IWebHostEnvironment.IsDevelopment()<\/code> is true. This removes the need to manually register the middleware by developers as shown in the example below.<\/p>\n<p><strong>Before<\/strong><\/p>\n<pre><code class=\"csharp\">var builder = WebApplication.CreateBuilder(args);\nvar app = builder.Build();\n\nif (app.Environment.IsDevelopment())\n{\n    app.UseDeveloperExceptionPage();\n}\napp.MapGet(\"\/\", \"Hello World\");\n\napp.Run();\n<\/code><\/pre>\n<p><strong>After<\/strong><\/p>\n<pre><code class=\"csharp\">var builder = WebApplication.CreateBuilder(args);\nvar app = builder.Build();\n\napp.MapGet(\"\/\", \"Hello World\");\n\napp.Run();\n<\/code><\/pre>\n<h3>Other Improvements in minimal APIs<\/h3>\n<p>Modifying the host configuration after the <code>WebApplicationBuilder<\/code> has been created is no longer supported. Instead, the <code>Create<\/code> and <code>CreateBuilder<\/code> calls now support taking a <code>WebApplicationBuilderOptions<\/code> which can be used to specify properties like the environment name, content root path, and so on.<\/p>\n<pre><code class=\"csharp\">var config = new WebApplicationOptions \n{\n    Args = args,\n    EnvironmentName = Environments.Staging,\n    ContentRootPath = \"www\/\"\n};\n\nvar app = WebApplication.Create(options);\n\napp.MapGet(\"\/\", (IHostEnvironment env) =&gt; env.EnvironmentName);\n\napp.Run();\n<\/code><\/pre>\n<p>In addition to configuring hosting settings using the <code>WebApplicationOptions<\/code> class, minimal APIs now support customizing the host configuration using command-line args. For example, the following can be used to set the environment name for a running app.<\/p>\n<pre><code class=\"bash\">$ dotnet run --environment=Development\n<\/code><\/pre>\n<p>To support a wider variety of middleware, minimal API apps now support multiple calls to the <code>UseRouting<\/code> method without overriding existing endpoints. This enables registering middleware like the Developer Exception page (which is enabled by default now) in the app.<\/p>\n<p>Minimal APIs now support using <code>MapFallback<\/code> to define behavior for fallback routes in apps.<\/p>\n<pre><code class=\"csharp\">var app = WebApplication.Create(options);\n\napp.MapFallback(\"\/subroute\", (string shareCode) =&gt; { ... };\n\napp.Run();\n\n<\/code><\/pre>\n<h2>Support for Latin1 encoded request headers in <code>HttpSysServer<\/code><\/h2>\n<p><code>HttpSysServer<\/code> is now capable of decoding request headers that are Latin1 encoded. To do so, you must the set the <code>UseLatin1RequestHeaders<\/code> property on <code>HttpSysOptions<\/code> to <code>true<\/code>.<\/p>\n<pre><code class=\"csharp\">var builder = WebApplication.CreateBuilder(args);\nbuilder.WebHost.UseHttpSys(o =&gt; o.UseLatin1RequestHeaders = true);\n<\/code><\/pre>\n<h2>Emit <code>KestrelServerOptions<\/code> via <code>EventSource<\/code> event<\/h2>\n<p>The <code>KestrelEventSource<\/code> now emits a new event containing the JSON-serialized <code>KestrelServerOptions<\/code> when enabled (with verbosity <code>EventLevel.LogAlways<\/code>). This event makes it easier to reason about the server behavior when analyzing collected traces. Here&#8217;s an example of the event payload:<\/p>\n<pre><code class=\"json\">{\n  \"AllowSynchronousIO\": false,\n  \"AddServerHeader\": true,\n  \"AllowAlternateSchemes\": false,\n  \"AllowResponseHeaderCompression\": true,\n  \"EnableAltSvc\": false,\n  \"IsDevCertLoaded\": true,\n  \"RequestHeaderEncodingSelector\": \"default\",\n  \"ResponseHeaderEncodingSelector\": \"default\",\n  \"Limits\": {\n    \"KeepAliveTimeout\": \"00:02:10\",\n    \"MaxConcurrentConnections\": null,\n    \"MaxConcurrentUpgradedConnections\": null,\n    \"MaxRequestBodySize\": 30000000,\n    \"MaxRequestBufferSize\": 1048576,\n    \"MaxRequestHeaderCount\": 100,\n    \"MaxRequestHeadersTotalSize\": 32768,\n    \"MaxRequestLineSize\": 8192,\n    \"MaxResponseBufferSize\": 65536,\n    \"MinRequestBodyDataRate\": \"Bytes per second: 240, Grace Period: 00:00:05\",\n    \"MinResponseDataRate\": \"Bytes per second: 240, Grace Period: 00:00:05\",\n    \"RequestHeadersTimeout\": \"00:00:30\",\n    \"Http2\": {\n      \"MaxStreamsPerConnection\": 100,\n      \"HeaderTableSize\": 4096,\n      \"MaxFrameSize\": 16384,\n      \"MaxRequestHeaderFieldSize\": 16384,\n      \"InitialConnectionWindowSize\": 131072,\n      \"InitialStreamWindowSize\": 98304,\n      \"KeepAlivePingDelay\": \"10675199.02:48:05.4775807\",\n      \"KeepAlivePingTimeout\": \"00:00:20\"\n    },\n    \"Http3\": {\n      \"HeaderTableSize\": 0,\n      \"MaxRequestHeaderFieldSize\": 16384\n    }\n  },\n  \"ListenOptions\": [\n    {\n      \"Address\": \"https:\/\/127.0.0.1:7030\",\n      \"IsTls\": true,\n      \"Protocols\": \"Http1AndHttp2\"\n    },\n    {\n      \"Address\": \"https:\/\/[::1]:7030\",\n      \"IsTls\": true,\n      \"Protocols\": \"Http1AndHttp2\"\n    },\n    {\n      \"Address\": \"http:\/\/127.0.0.1:5030\",\n      \"IsTls\": false,\n      \"Protocols\": \"Http1AndHttp2\"\n    },\n    {\n      \"Address\": \"http:\/\/[::1]:5030\",\n      \"IsTls\": false,\n      \"Protocols\": \"Http1AndHttp2\"\n    }\n  ]\n}\n<\/code><\/pre>\n<h2>Add timestamps and PID to ASP.NET Core Module logs<\/h2>\n<p>The ASP.NET Core Module (ANCM) enhanced diagnostic logs now include timestamps and PID of the process emitting the logs. This makes it easier to diagnose issues with overlapping process restarts in IIS when you may have multiple IIS worker processes running.<\/p>\n<p>The resulting logs now resemble the sample output included below:<\/p>\n<pre><code>[2021-07-28T19:23:44.076Z, PID: 11020] [aspnetcorev2.dll] Initializing logs for 'C:\\&lt;path&gt;\\aspnetcorev2.dll'. Process Id: 11020. File Version: 16.0.21209.0. Description: IIS ASP.NET Core Module V2. Commit: 96475a2acdf50d7599ba8e96583fa73efbe27912.\n[2021-07-28T19:23:44.079Z, PID: 11020] [aspnetcorev2.dll] Resolving hostfxr parameters for application: '.\\InProcessWebSite.exe' arguments: '' path: 'C:\\Temp\\e86ac4e9ced24bb6bacf1a9415e70753\\'\n[2021-07-28T19:23:44.080Z, PID: 11020] [aspnetcorev2.dll] Known dotnet.exe location: ''\n<\/code><\/pre>\n<h2>New <code>DiagnosticSource<\/code> event for rejected HTTP requests<\/h2>\n<p>Kestrel now emits a new <code>DiagnosticSource<\/code> event for HTTP requests rejected at the server layer. Prior to this change, there was no way to observe these rejected requests. The new DiagnosticSource event <code>Microsoft.AspNetCore.Server.Kestrel.BadRequest<\/code> now contains a <code>IBadRequestExceptionFeature<\/code> that can be used to introspect the reason for rejecting the request.<\/p>\n<pre><code class=\"csharp\">var builder = WebApplication.CreateBuilder(args);\nvar app = builder.Build();\nvar diagnosticSource = app.Services.GetRequiredService&lt;DiagnosticListener&gt;();\nusing var badRequestListener = new BadRequestEventListener(diagnosticSource, (badRequestExceptionFeature) =&gt;\n{\n    app.Logger.LogError(badRequestExceptionFeature.Error, \"Bad request received\");\n});\napp.MapGet(\"\/\", () =&gt; \"Hello world\");\n\napp.Run();\n\nclass BadRequestEventListener : IObserver&lt;KeyValuePair&lt;string, object&gt;&gt;, IDisposable\n{\n    private readonly IDisposable _subscription;\n    private readonly Action&lt;IBadRequestExceptionFeature&gt; _callback;\n\n    public BadRequestEventListener(DiagnosticListener diagnosticListener, Action&lt;IBadRequestExceptionFeature&gt; callback)\n    {\n        _subscription = diagnosticListener.Subscribe(this!, IsEnabled);\n        _callback = callback;\n    }\n    private static readonly Predicate&lt;string&gt; IsEnabled = (provider) =&gt; provider switch\n    {\n        \"Microsoft.AspNetCore.Server.Kestrel.BadRequest\" =&gt; true,\n        _ =&gt; false\n    };\n    public void OnNext(KeyValuePair&lt;string, object&gt; pair)\n    {\n        if (pair.Value is IFeatureCollection featureCollection)\n        {\n            var badRequestFeature = featureCollection.Get&lt;IBadRequestExceptionFeature&gt;();\n\n            if (badRequestFeature is not null)\n            {\n                _callback(badRequestFeature);\n            }\n        }\n    }\n    public void OnError(Exception error) { }\n    public void OnCompleted() { }\n    public virtual void Dispose() =&gt; _subscription.Dispose();\n}\n<\/code><\/pre>\n<h2>Create a <code>ConnectionContext<\/code> from an Accept Socket<\/h2>\n<p>The newly introduced <code>SocketConnectionContextFactory<\/code> now makes it possible to create a <code>ConnectionContext<\/code> from an already accepted socket. This makes it possible to build a custom Socket-based <code>IConnectionListenerFactory<\/code> without losing out on all the performance work and pooling happening in SocketConnection.<\/p>\n<p>Look at <a href=\"https:\/\/github.com\/davidfowl\/TcpProxy\/blob\/main\/Backend\/DelegatedConnectionListenerFactory.cs\">this example of a custom IConnectionListenerFactory<\/a> for an example of how to use this new API.<\/p>\n<h2>Streamlined HTTP\/3 setup<\/h2>\n<p>RC1 introduces an easier setup experience for using HTTP\/3 in Kestrel. All that&#8217;s needed is to configure Kestrel to use the proper protocol.<\/p>\n<p>HTTP\/3 can be enabled on all ports using <a href=\"https:\/\/docs.microsoft.com\/aspnet\/core\/fundamentals\/servers\/kestrel\/endpoints#configureendpointdefaultsactionlistenoptions\">ConfigureEndpointDefaults<\/a>, or for an individual port, as in the sample below.<\/p>\n<pre><code class=\"csharp\">var builder = WebApplication.CreateBuilder(args);\nbuilder.WebHost.ConfigureKestrel((context, options) =&gt;\n{\n    options.Listen(IPAddress.Any, 5001, listenOptions =&gt;\n    {\n        \/\/ Use HTTP\/3\n        listenOptions.Protocols = HttpProtocols.Http1AndHttp2AndHttp3;\n        listenOptions.UseHttps();\n    });\n});\n<\/code><\/pre>\n<p>HTTP\/3 is not supported everywhere. See <a href=\"https:\/\/docs.microsoft.com\/aspnet\/core\/fundamentals\/servers\/kestrel\/http3\">Use HTTP\/3 with the ASP.NET Core Kestrel web server<\/a> for information on getting started with HTTP\/3 in Kestrel.<\/p>\n<h2>Upgrade to Duende Identity Server<\/h2>\n<p>Templates which use Identity Server have now be updated to use Duende Identity Server, as previously discussed in our <a href=\"https:\/\/devblogs.microsoft.com\/aspnet\/asp-net-core-6-and-authentication-servers\/\">announcement<\/a>.<\/p>\n<p>If you are extending the identity models and are updating existing projects you will need to update the namespaces in your code from <code>IdentityServer4.IdentityServer<\/code> to <code>Duende.IdentityServer<\/code> and follow their <a href=\"https:\/\/docs.duendesoftware.com\/identityserver\/v5\/upgrades\/\">migration instructions<\/a>.<\/p>\n<p>Please note the license model for Duende Identity Server has changed to a reciprocal license, which may require license fees if you use it commercially in production. You can check the <a href=\"https:\/\/duendesoftware.com\/products\/identityserver#pricing\">Duende license page<\/a> for more details.<\/p>\n<h2>Give feedback<\/h2>\n<p>We hope you enjoy this preview release of ASP.NET Core in .NET 6. We&#8217;re eager to hear about your experiences with this release. Let us know what you think by filing issues on <a href=\"https:\/\/github.com\/dotnet\/aspnetcore\/issues\">GitHub<\/a>.<\/p>\n<p>Thanks for trying out ASP.NET Core!<\/p>\n","protected":false},"excerpt":{"rendered":"<p>.NET 6 Release Candidate 1 is now available! Check out all the improvements in ASP.NET Core in this update.<\/p>\n","protected":false},"author":417,"featured_media":21380,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[197,7509,7251],"tags":[],"class_list":["post-37164","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-aspnet","category-aspnetcore","category-blazor"],"acf":[],"blog_post_summary":"<p>.NET 6 Release Candidate 1 is now available! Check out all the improvements in ASP.NET Core in this update.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/posts\/37164","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=37164"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/posts\/37164\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/media\/21380"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/media?parent=37164"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/categories?post=37164"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/tags?post=37164"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}