Create an account

Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
ASP.NET Core updates in .NET 5 Release Candidate 1

ASP.NET Core updates in .NET 5 Release Candidate 1

<div style="margin: 5px 5% 10px 5%;"><img src="" width="150" height="150" title="" alt="" /></div><div><div class="row justify-content-center">
<div class="col-md-4">
<div><img decoding="async" loading="lazy" src="" width="58" height="58" alt="Daniel Roth" class="avatar avatar-58 wp-user-avatar wp-user-avatar-58 alignnone photo"></p>
<div class="entry-meta entry-meta-layout">
<p>September 14th, 2020</p>
<p><!-- .entry-meta --> </p>
<p><a href="">.NET 5 Release Candidate 1 (RC1) is now available</a> and is ready for evaluation. Here’s what’s new in this release:</p>
<li>Blazor WebAssembly performance improvements</li>
<li>Blazor component virtualization</li>
<li>Blazor WebAssembly prerendering</li>
<li>Browser compatibility analyzer for Blazor WebAssembly</li>
<li>Blazor JavaScript isolation and object references</li>
<li>Blazor file input support</li>
<li>Custom validation class attributes in Blazor</li>
<li>Blazor support for <code>ontoggle</code> event</li>
<li>Model binding <code>DateTime</code> as UTC</li>
<li>Control <code>Startup</code> class activation</li>
<li>Open API Specification (Swagger) on-by-default in ASP.NET Core API projects</li>
<li>Better F5 Experience for ASP.NET Core API Projects</li>
<li>SignalR parallel hub invocations</li>
<li>Added Messagepack support in SignalR Java client</li>
<li>Kestrel endpoint-specific options via configuration</li>
<p>See the <a href="">.NET 5 release notes</a> for additional details and known issues.</p>
<h2 id="get-started">Get started</h2>
<p>To get started with ASP.NET Core in .NET 5 RC1 <a href="">install the .NET 5 SDK</a>. .NET RC1 also is included with Visual Studio 2019 16.8 Preview 3.</p>
<p>You need to use <a href="">Visual Studio 2019 16.8 Preview 3</a> or newer to use .NET 5 RC1. .NET 5 is also supported with the latest <a href="">preview</a> of <a href="">Visual Studio for Mac</a>. To use .NET 5 with <a href="">Visual Studio Code</a>, install the latest version of the <a href="">C# extension</a>.</p>
<h2 id="upgrade-an-existing-project">Upgrade an existing project</h2>
<p>To upgrade an existing ASP.NET Core app from .NET 5 Preview 8 to .NET 5 RC1:</p>
<li>Update all Microsoft.AspNetCore.* package references to <code>5.0.0-rc.1.*</code>.
<li>If you’re using the new Microsoft.AspNetCore.Components.Web.Extensions package, update to version <code>5.0.0-preview.9.*</code>. This package doesn’t have an RC version number yet because we expect to make a few more design changes to the components it contains before it’s ready to ship.</li>
<li>Update all Microsoft.Extensions.* package references to <code>5.0.0-rc.1.*</code>.</li>
<li>Update System.Net.Http.Json package references to <code>5.0.0-rc.1.*</code>.</li>
<p>In Blazor WebAssembly projects, also make the follwowing updates to the project file:</p>
<li>Update the SDK from “Microsoft.NET.Sdk.Web” to “Microsoft.NET.Sdk.BlazorWebAssembly”</li>
<li>Remove the <code>&lt;RuntimeIdentifier&gt;browser-wasm&lt;/RuntimeIdentifier&gt;</code> and <code>&lt;UseBlazorWebAssembly&gt;true&lt;/UseBlazorWebAssembly&gt;</code> properties.</li>
<p>That’s it! You should be all ready to go.</p>
<p>See also the full list of <a href="">breaking changes</a> in ASP.NET Core for .NET 5.</p>
<h2 id="whats-new">What’s new?</h2>
<h3 id="blazor-webassembly-performance-improvements">Blazor WebAssembly performance improvements</h3>
<p>For .NET 5, we’ve made significant improvements to Blazor WebAssembly runtime performance, with a specific focus on complex UI rendering and JSON serialization. In our performance tests, Blazor WebAssembly in .NET 5 is 2-3x faster for most scenarios.</p>
<p>Runtime code execution in Blazor WebAssembly in .NET 5 is generally faster than Blazor WebAssembly 3.2 due to optimizations in the core framework libraries and improvements to the .NET IL interpreter. Things like string comparisons, dictionary lookups, and JSON handling are generally much faster in .NET 5 on WebAssembly.</p>
<p>As shown in the chart below, JSON handling is almost twice as fast in .NET 5 on WebAssembly:</p>
<p><img decoding="async" src="" alt="Blazor WebAssembly 1kb JSON handling"></p>
<p>We also optimized the performance of Blazor component rendering, particularly for UI involving lots of components, like when using high-density grids.</p>
<p>To test the performance of grid component rendering in .NET 5, we used three different grid component implementations, each rendering 200 rows with 20 columns:</p>
<li><strong>Fast Grid:</strong> A minimal, highly optimized implementation of a grid</li>
<li><strong>Plain Table:</strong> A minimal but not optimized implementation of a grid.</li>
<li><strong>Complex Grid:</strong> A maximal, not optimized implementation of a grid, using a wide range of Blazor features at once, deliberately intended to create a bad case for the renderer.</li>
<p>From our tests, grid rendering is 2-3x faster in .NET 5:</p>
<p><img decoding="async" src="" alt="Blazor WebAssembly grid rendering"></p>
<p>You can find the code for these <a href="">performance tests</a> in the ASP.NET Core GitHub repo.</p>
<p>You can expect ongoing work to improve Blazor WebAssembly performance. Besides optimizing the Blazor WebAssembly runtime and framework, the .NET team is also working with browser implementers to further speed up WebAssembly execution. And for .NET 6, we expect to ship support for ahead-of-time (AoT) compilation to WebAssembly, which should further improve performance.</p>
<h3 id="blazor-component-virtualization">Blazor component virtualization</h3>
<p>You can further improve the perceived performance of component rendering using the new built-in virtualization support. Virtualization is a technique for limiting the UI rendering to just the parts that are currently visible, like when you have a long list or table with many rows and only a small subset is visible at any given time. Blazor in .NET 5 adds a new <code>Virtualize</code> component that can be used to easily add virtualization to your components.</p>
<p>A typical list or table-based component might use a C# foreach loop to render each item in the list or each row in the table, like this:</p>
<pre><code>@foreach (var employee in employees)
{ &lt;tr&gt; &lt;td&gt;@employee.FirstName&lt;/td&gt; &lt;td&gt;@employee.LastName&lt;/td&gt; &lt;td&gt;@employee.JobTitle&lt;/td&gt; &lt;/tr&gt;
<p>If the list grew to include thousands of rows, then rendering it may take a while, resulting in a noticeable UI lag.</p>
<p>Instead, you can replace the foreach loop with the <code>Virtualize</code> component, which only renders the rows that are currently visible.</p>
<pre><code class="razor">&lt;Virtualize Items="employees" Context="employee"&gt; &lt;tr&gt; &lt;td&gt;@employee.FirstName&lt;/td&gt; &lt;td&gt;@employee.LastName&lt;/td&gt; &lt;td&gt;@employee.JobTitle&lt;/td&gt; &lt;/tr&gt;
<p>The <code>Virtualize</code> component calculates how many items to render based on the height of the container and the size of the rendered items.</p>
<p>If you don’t want to load all items into memory, you can specify an <code>ItemsProvider</code>, like this:</p>
<pre><code class="razor">&lt;Virtualize ItemsProvider="LoadEmployees" Context="employee"&gt; &lt;tr&gt; &lt;td&gt;@employee.FirstName&lt;/td&gt; &lt;td&gt;@employee.LastName&lt;/td&gt; &lt;td&gt;@employee.JobTitle&lt;/td&gt; &lt;/tr&gt;
<p>An items provider is a delegate method that asynchronously retrieves the requested items on demand. The items provider receives an <code>ItemsProviderRequest</code>, which specifies the required number of items starting at a specific start index. The items provider then retrieves the requested items from a database or other service and returns them as an <code>ItemsProviderResult&lt;TItem&gt;</code> along with a count of the total number of items available. The items provider can choose to retrieve the items with each request, or cache them so they are readily available.</p>
<pre><code class="csharp">async ValueTask&lt;ItemsProviderResult&lt;Employee&gt;&gt; LoadEmployees(ItemsProviderRequest request)
{ var numEmployees = Math.Min(request.Count, totalEmployees - request.StartIndex); var employees = await EmployeesService.GetEmployeesAsync(request.StartIndex, numEmployees, request.CancellationToken); return new ItemsProviderResult&lt;Employee&gt;(employees, totalEmployees);
<p>Because requesting items from a remote data source might take some time, you also have the option to render a placeholder until the item data is available.</p>
<pre><code class="razor">&lt;Virtualize ItemsProvider="LoadEmployees" Context="employee"&gt; &lt;ItemContent&gt; &lt;tr&gt; &lt;td&gt;@employee.FirstName&lt;/td&gt; &lt;td&gt;@employee.LastName&lt;/td&gt; &lt;td&gt;@employee.JobTitle&lt;/td&gt; &lt;/tr&gt; &lt;/ItemContent&gt; &lt;Placeholder&gt; &lt;tr&gt; &lt;td&gt;Loading...&lt;/td&gt; &lt;/tr&gt; &lt;/Placeholder&gt;
<h3 id="blazor-webassembly-prerendering">Blazor WebAssembly prerendering</h3>
<p>The component tag helper now supports two additional render modes for prerendering a component from a Blazor WebAssembly app:</p>
<li><strong>WebAssemblyPrerendered:</strong> Prerenders the component into static HTML and includes a marker for a Blazor WebAssembly app to later use to make the component interactive when loaded in the browser.</li>
<li><strong>WebAssembly:</strong> Renders a marker for a Blazor WebAssembly app to use to include an interactive component when loaded in the browser. The component is not prerendered. This option simply makes it easier to render different Blazor WebAssembly components on different <code>cshtml</code> pages.</li>
<p>To setup prerendering in an Blazor WebAssembly app:</p>
<li>Host the Blazor WebAssembly app in an ASP.NET Core app.</li>
<li>Replace the default static <em>index.html</em> file in the client project with a <em>_Host.cshtml</em> file in the server project.</li>
<li>Update the server startup logic to fallback to <em>_Host.cshtml</em> instead of <em>index.html</em> (similar to how the Blazor Server template is set up).</li>
<p>Update <em>_Host.cshtml</em> to use the component tag helper to prerender the root <code>App</code> component:</p>
<pre><code class="cshtml">&lt;component type="typeof(App)" render-mode="WebAssemblyPrerendered" /&gt;
<p>You can also pass parameters to the component tag helper when using the WebAssembly-based render modes if the parameters are serializable. The parameters must be serializable so that they can be transferred to the client and used to initialize the component in the browser. If prerendering, you’ll also need to be sure to author your components so that they can gracefully execute server-side without access to the browser.</p>
<pre><code class="cshtml">&lt;component type="typeof(Counter)" render-mode="WebAssemblyPrerendered" param-IncrementAmount="10" /&gt;
<p>In additional to improving the perceived load time of a Blazor WebAssembly app, you can also use the component tag helper with the new render modes to add multiple components on different pages and views. You don’t need to configure these components as root components in the app or add your own marker tags on the page – the framework handles that for you.</p>
<h3 id="browser-compatibility-analyzer-for-blazor-webassembly">Browser compatibility analyzer for Blazor WebAssembly</h3>
<p>Blazor WebAssembly apps in .NET 5 target the full .NET 5 API surface area, but not all .NET 5 APIs are supported on WebAssembly due to browser sandbox constraints. Unsupported APIs throw <code>PlatformNotSupportedException</code> when running on WebAssembly. .NET 5 now includes a platform compatibility analyzer that will warn you when your app uses APIs that are not supported by your target platforms. For Blazor WebAssembly apps, this means checking that APIs are supported in browsers.</p>
<p>We haven’t added all of the annotations yet to the core libraries in .NET 5 to indicate which APIs are not supported in browsers, but some APIs, mostly Windows specific APIs, are already annotated:</p>
<p><img decoding="async" src="" alt="Platform compatibility analyzer"></p>
<p>To enable browser compatibilty checks for libraries, add “browser” as a supported platform in your project file (Blazor WebAssembly projects and Razor class library projects do this for you):</p>
<pre><code class="xml">&lt;SupportedPlatform Include="browser" /&gt;
<p>When authoring a library, you can optionally indicate that a particular API is not supported in browsers by applying the <code>UnsupportedOSPlatformAttribute</code>:</p>
<pre><code class="csharp">[UnsupportedOSPlatform("browser")]
private static string GetLoggingDirectory()
{ // ...
<h3 id="blazor-javascript-isolation-and-object-references">Blazor JavaScript isolation and object references</h3>
<p>Blazor now enables you to isolate your JavaScript as standard JavaScript modules. This has a couple of benefits:</p>
<li>Imported JavaScript no longer pollutes the global namespace.</li>
<li>Consumers of your library and components no longer need to manually import the related JavaScript.</li>
<p>For example, the following JavaScript module exports a simple JavaScript function for showing a browser prompt:</p>
<pre><code class="js">export function showPrompt(message) { return prompt(message, 'Type anything here');
<p>You can add this JavaScript module to your .NET library as a static web asset (<em>wwwroot/exampleJsInterop.js</em>) and then import the module into your .NET code using the <code>IJSRuntime</code> service:</p>
<pre><code class="csharp">var module = await jsRuntime.InvokeAsync&lt;JSObjectReference&gt;("import", "./_content/MyComponents/exampleJsInterop.js");
<p>The “import” identifier is a special identifier used specifically for importing a JavaScript module. You specify the module using its stable static web asset path: <em>_content/[LIBRARY NAME]/[PATH UNDER WWWROOT]</em>.</p>
<p>The <code>IJSRuntime</code> imports the module as a <code>JSObjectReference</code>, which represents a reference to a JavaScript object from .NET code. You can then use the <code>JSObjectReference</code> to invoke exported JavaScript functions from the module:</p>
<pre><code class="csharp">public async ValueTask&lt;string&gt; Prompt(string message)
{ return await module.InvokeAsync&lt;string&gt;("showPrompt", message);
<p><code>JSObjectReference</code> greatly simplifies interacting with JavaScript libraries where you want to capture JavaScript object references, and then later invoke their functions from .NET.</p>
<h3 id="blazor-file-input-support">Blazor file input support</h3>
<p>Blazor now offers an <code>InputFile</code> component for handling file uploads, or more generally for reading browser file data into your .NET code.</p>
<p>The <code>InputFile</code> component renders as an HTML input of type “file”. By default, the user can select single files, or if you add the “multiple” attribute then the user can supply multiple files at once. When one or more files is selected by the user, the <code>InputFile</code> component fires an <code>OnChange</code> event and passes in an <code>InputFileChangeEventArgs</code> that provides access to the selected file list and details about each file.</p>
<pre><code class="razor">&lt;InputFile OnChange="OnInputFileChange" multiple /&gt; &lt;div class="image-list"&gt; @foreach (var imageDataUrl in imageDataUrls) { &lt;img src="@imageDataUrl" /&gt; }
&lt;/div&gt; @code { IList&lt;string&gt; imageDataUrls = new List&lt;string&gt;(); async Task OnInputFileChange(InputFileChangeEventArgs e) { var imageFiles = e.GetMultipleFiles(); var format = "image/png"; foreach (var imageFile in imageFiles) { var resizedImageFile = await imageFile.RequestImageFileAsync(format, 100, 100); var buffer = new byte[resizedImageFile.Size]; await resizedImageFile.OpenReadStream().ReadAsync(buffer); var imageDataUrl = $"data:{format};base64,{Convert.ToBase64String(buffer)}"; imageDataUrls.Add(imageDataUrl); } }
<p>To read data from a user-selected file, you call <code>OpenReadStream</code> on the file and read from the returned stream. In a Blazor WebAssembly app, the data is streamed directly into your .NET code within the browser. In a Blazor Server app, the file data is streamed to your .NET code on the server as you read from the stream. In case you’re using the component to receive an image file, Blazor also provides a <code>RequestImageFileAsync</code> convenience method for resizing images data within the browser’s JavaScript runtime before they’re streamed into your .NET application.</p>
<h3 id="custom-validation-class-attributes-in-blazor">Custom validation class attributes in Blazor</h3>
<p>You can now specify custom validation class names in Blazor. This is useful when integrating with CSS frameworks, like Bootstrap.</p>
<p>To specify custom validation class names, create a class derived from <code>FieldCssClassProvider</code> and set it on the <code>EditContext</code> instance.</p>
<pre><code class="csharp">var editContext = new EditContext(model);
editContext.SetFieldCssClassProvider(new MyFieldClassProvider()); // ... class MyFieldClassProvider : FieldCssClassProvider
{ public override string GetFieldCssClass(EditContext editContext, in FieldIdentifier fieldIdentifier) { var isValid = !editContext.GetValidationMessages(fieldIdentifier).Any(); return isValid ? "legit" : "totally-bogus"; }
<h3 id="blazor-support-for-ontoggle-event">Blazor support for <code>ontoggle</code> event</h3>
<p>Blazor now has support for the <code>ontoggle</code> event:</p>
<pre><code class="razor">&lt;div&gt; @if (detailsExpanded) { &lt;p&gt;Read the details carefully!&lt;/p&gt; } &lt;details id="details-toggle" @ontoggle="OnToggle"&gt; &lt;summary&gt;Summary&lt;/summary&gt; &lt;p&gt;Detailed content&lt;/p&gt; &lt;/details&gt;
&lt;/div&gt; @code { bool detailsExpanded; string message { get; set; } void OnToggle() { detailsExpanded = !detailsExpanded; }
<p>Thank you <a href="">Vladimir Samoilenko</a> for this contribution!</p>
<h3 id="model-binding-datetime-as-utc">Model binding <code>DateTime</code> as UTC</h3>
<p>Model binding in ASP.NET Core now supports correctly binding UTC time strings to <code>DateTime</code>. If the request contains a UTC time string (for example <code></code>), model binding will correctly bind it to a UTC <code>DateTime</code> without the need for further customization.</p>
<h3 id="control-startup-class-activation">Control <code>Startup</code> class activation</h3>
<p>We’ve provided an additional <code>UseStartup</code> overload that lets you provide a factory method for controlling <code>Startup</code> class activation. This is useful if you want to pass additional parameters to <code>Startup</code> that are initialized along with the host.</p>
<pre><code class="csharp">public class Program
{ public static async Task Main(string[] args) { var logger = CreateLogger(); var host = Host.CreateDefaultBuilder() .ConfigureWebHost(builder =&gt; { builder.UseStartup(context =&gt; new Startup(logger)); }) .Build(); await host.RunAsync(); }
<h3 id="open-api-specification-on-by-default">Open API Specification On-by-default</h3>
<p><a href="">Open API Specification</a> is a industry-adopted convention for describing HTTP APIs and integrating them into complex business processes or with 3rd parties. Open API is widely supported by all cloud providers and many API registries, so developers who emit Open API documents from their Web APIs have a variety of new opportunities in which those APIs can be used. In partnership with the maintainers of the open-source project <a href="">Swashbuckle.AspNetCore</a>, we’re excited to announce that the ASP.NET Core API template in RC1 comes pre-wired with a NuGet dependency on Swashbuckle, a popular open-source NuGet package that emits Open API documents dynamically. Swashbuckle does this by introspecting over your API Controllers and generating the Open API document at run-time, or at build time using the <a href="">Swashbuckle CLI</a>.</p>
<p>In .NET 5 RC1, running <code>dotnet new webapi</code> will result in the Open API output being enabled by default, but if you prefer to have Open API disabled, use <code>dotnet new webapi --no-openapi true</code>. All <code>.csproj</code> files that are created for Web API projects will come with the NuGet package reference.</p>
<pre><code class="xml">&lt;ItemGroup&gt; &lt;PackageReference Include="Swashbuckle.AspNetCore" Version="5.5.1" /&gt;
<p>In addition to the NuGet package reference being in the <code>.csproj</code> file we’ve added code to both the <code>ConfigureServices</code> method in <code>Startup.cs</code> that activates Open API document generation.</p>
<pre><code class="csharp">public void ConfigureServices(IServiceCollection services)
{ services.AddControllers(); services.AddSwaggerGen(c =&gt; { c.SwaggerDoc("v1", new OpenApiInfo { Title = "WebApplication1", Version = "v1" }); });
<p>The <code>Configure</code> method is also pre-wired to enlist in the Swashbuckle middleware. This lights up the document generation process <strong>and</strong> turns on the Swagger UI page by default in development mode. This way you’re confident that the out-of-the-box experience doesn’t accidentally expose your API’s description when you publish to production.</p>
<pre><code class="csharp">public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{ if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); app.UseSwagger(); app.UseSwaggerUI(c =&gt; c.SwaggerEndpoint("/swagger/v1/swagger.json", "WebApplication1 v1")); } // ...
<h3 id="azure-api-management-import">Azure API Management Import</h3>
<p>When ASP.NET Core API projects are wired to output Open API in this way, the Visual Studio 2019 version 16.8 Preview 2.1 publishing experience will automatically offer an additional step in the publishing flow. Developers who use <a href="">Azure API Management</a> have an opportunity to automatically import their APIs into Azure API Management during the publish flow.</p>
<p><img decoding="async" src="" alt="Publising APIs"></p>
<p>This additional publishing step reduces the number of steps HTTP API developers need to execute to get their APIs published and used with <a href="">Azure Logic Apps</a> or <a href="">PowerApps</a>.</p>
<h3 id="better-f5-experience-for-web-api-projects">Better F5 Experience for Web API Projects</h3>
<p>With Open API enabled by default, we were able to significantly improve the F5 experience for Web API developers. With .NET 5 RC1, the Web API template comes pre-configured to load up the Swagger UI page. The Swagger UI page provides both the documentation you’ve added for your API, but enables you to test your APIs with a single click.</p>
<p><img decoding="async" src="" alt="Swagger UI page"></p>
<h3 id="signalr-parallel-hub-invocations">SignalR parallel hub invocations</h3>
<p>In .NET 5 RC1, ASP.NET Core SignalR is now capable of handling parallel hub invocations. You can change the default behavior and allow clients to invoke more than one hub method at a time.</p>
<pre><code class="csharp">public void ConfigureServices(IServiceCollection services)
{ services.AddSignalR(options =&gt; { options.MaximumParallelInvocationsPerClient = 5; });
<h3 id="added-messagepack-support-in-signalr-java-client">Added Messagepack support in SignalR Java client</h3>
<p>We’re introducing a new package, <code></code>, that adds messagepack support to the SignalR java client. To use the messagepack hub protocol, add <code>.withHubProtocol(new MessagePackHubProtocol())</code> to the connection builder.</p>
<pre><code class="java">HubConnection hubConnection = HubConnectionBuilder.create("http://localhost:53353/MyHub") .withHubProtocol(new MessagePackHubProtocol()) .build();
<h3 id="kestrel-endpoint-specific-options-via-configuration">Kestrel endpoint-specific options via configuration</h3>
<p>We have added support for configuring Kestrel’s endpoint-specific options via configuration. The endpoint-specific configurations includes the Http protocols used, the TLS protocols used, the certificate selected, and the client certificate mode.</p>
<p>You are able to configure the which certificate is selected based on the specified server name as part of the Server Name Indication (SNI) extension to the TLS protocol as indicated by the client. Kestrel’s configuration also support a wildcard prefix in the host name.</p>
<p>The example belows shows you how to specify endpoint-specific using a configuration file:</p>
<pre><code class="json">{ "Kestrel": { "Endpoints": { "EndpointName": { "Url": "https://*", "Sni": { "": { "Protocols": "Http1AndHttp2", "SslProtocols": [ "Tls11", "Tls12"], "Certificate": { "Path": "testCert.pfx", "Password": "testPassword" }, "ClientCertificateMode" : "NoCertificate" }, "*": { "Certificate": { "Path": "testCert2.pfx", "Password": "testPassword" } }, "*": { // At least one subproperty needs to exist per SNI section or it // cannot be discovered via IConfiguration "Protocols": "Http1", } } } } }
<h2 id="give-feedback">Give feedback</h2>
<p>We hope you enjoy this release of ASP.NET Core in .NET 5! We are eager to hear about your experiences with this latest .NET 5 release. Let us know what you think by filing issues on <a href="">GitHub</a>.</p>
<p>Thanks for trying out ASP.NET Core!</p>

Forum Jump:

Users browsing this thread:
1 Guest(s)

Forum software by © MyBB Theme © iAndrew 2016