.NET 8 Preview 2 is now available and includes many great new improvements to ASP.NET Core.
Here’s a summary of what’s new in this preview release:
- Blazor
QuickGrid
component - Improved Blazor WebAssembly performance with the jiterpreter
- New analyzer to detect multiple
FromBody
attributes - New APIs in
ProblemDetails
to support more resilient integrations - New
IResettable
interface inObjectPool
- Performance improvements to named pipes transport
For more details on the ASP.NET Core work planned for .NET 8 see the full ASP.NET Core roadmap for .NET 8 on GitHub.
Get started
To get started with ASP.NET Core in .NET 8 Preview 2, install the .NET 8 SDK.
If you’re on Windows using Visual Studio, we recommend installing the latest Visual Studio 2022 preview. Visual Studio for Mac support for .NET 8 previews isn’t available at this time.
Upgrade an existing project
To upgrade an existing ASP.NET Core app from .NET 8 Preview 1 to .NET 8 Preview 2:
- Update the target framework of your app to
net8.0
. - Update all Microsoft.AspNetCore.* package references to
8.0.0-preview.2.*
. - Update all Microsoft.Extensions.* package references to
8.0.0-preview.2.*
.
See also the full list of breaking changes in ASP.NET Core for .NET 8.
Blazor QuickGrid
component
The Blazor QuickGrid
component is now part of .NET 8! QuickGrid
is a high performance grid component for displaying data in tabular form. QuickGrid
is built to be a simple and convenient way to display your data, while still providing powerful features like sorting, filtering, paging, and virtualization.
To get started with QuickGrid
:
-
Add reference to the Microsoft.AspNetCore.Components.QuickGrid package.
dotnet add package Microsoft.AspNetCore.Components.QuickGrid --prerelease
-
Add the following Razor code to render a very simple grid.
<QuickGrid Items="@people"> <PropertyColumn Property="@(p => p.PersonId)" Title="ID" Sortable="true" /> <PropertyColumn Property="@(p => p.Name)" Title="Name" Sortable="true" /> <PropertyColumn Property="@(p => p.BirthDate)" Title="Birth date" Format="yyyy-MM-dd" Sortable="true" /> </QuickGrid> @code { record Person(int PersonId, string Name, DateOnly BirthDate); IQueryable<Person> people = new[] { new Person(10895, "Jean Martin", new DateOnly(1985, 3, 16)), new Person(10944, "António Langa", new DateOnly(1991, 12, 1)), new Person(11203, "Julie Smith", new DateOnly(1958, 10, 10)), new Person(11205, "Nur Sari", new DateOnly(1922, 4, 27)), new Person(11898, "Jose Hernandez", new DateOnly(2011, 5, 3)), new Person(12130, "Kenji Sato", new DateOnly(2004, 1, 9)), }.AsQueryable(); }
You can see various examples of QuickGrid
in action on the QuickGrid demo site.
QuickGrid
was originally introduced as an experimental package based on .NET 7. As part of bringing QuickGrid
into .NET 8 we’ve made some changes and improvements to the API. To update an existing Blazor app that uses QuickGrid
to the .NET 8 version, you may need to make the following adjustments:
- Rename the
Value
attribute on thePaginator
component toState
- Rename the
IsDefaultSort
attribute on columns toInitialSortDirection
and addIsDefaultSortColumn=true
to indicate the column should still be sorted by default. - Remove the
ResizableColumns
attribute onQuickGrid
. Built-in support for resizable columns was removed.
Improved Blazor WebAssembly performance with the jiterpreter
The jiterpreter is a new runtime feature in .NET 8 that enables partial JIT support in the .NET IL interpreter to achieve improved runtime performance.
Blazor WebAssembly apps are able to run .NET code in browser thanks to a small .NET runtime implemented in WebAssembly that gets downloaded with the app. This runtime is a .NET IL interpreter that is fully functional, reasonably small in size, and allows for fast developer iteration, but lacks the runtime performance benefits of native code execution through just-in-time (JIT) compilation. JITing to WebAssembly requires creating new WebAssembly modules on the fly and instantiating them, which poses unique challenges for the runtime. Blazor WebAssembly apps can instead choose to compile ahead-of-time (AOT) to WebAssembly to improve runtime performance but at the expense of a much larger download size. Since some common .NET coding patterns are incompatible with AOT, the .NET IL interpreter is still needed as a fallback mechanism to maintain full functionality.
The jiterpreter optimizes execution of interpreter bytecodes by replacing them with tiny blobs of WebAssembly code. By leveraging the interpreter as a baseline, we’re able to optimize the most important parts of the app without having to handle more complex or obscure cases and without overly complicating the runtime. While the jiterpreter isn’t a full JIT implementation, it significantly improves runtime performance without the size and build time overhead of AOT. The jiterpreter helps when using AOT too by optimizing cases where the runtime has to fallback to the interpreter.
In .NET 8 Preview 2 The jiterpreter is automatically enabled for your Blazor WebAssembly apps. You don’t have to do anything extra to turn it on.
The jiterpreter can significantly speed up the performance of low level operations. For example, the following micro benchmark test for Span<byte>.Reverse()
and String.Normalize()
ran 46.7% and 86.9% faster respectively:
These improvements add up and translate into better performance for higher layer features. In our JSON serialization tests, the jiterpreter is 40.8% faster:
We’re still working to improve the jiterpreter with additional optimizations, so the performance of the jiterpreter when we ship .NET 8 may differ from what we’re currently measuring, but so far the results are looking very promising!
New analyzer to detect multiple FromBody
attributes
In addition to the analyzers added in Preview 1, we’re introducing a new analyzer in this release that provides a helpful warning if you are attempting to resolve more than one parameter from the body in a minimal API. For example, the new analyzer will warn on the following code.
// ASP0024
app.MapPost("/todos", ([FromBody] Todo todo, [FromBody] User user) => ...);
To resolve the analyzer warning, limit each handler to have one parameter resolved from the body.
app.MapPost("/todos", ([FromBody] Todo todo, ClaimsPrincipal user) => ...);
New APIs in ProblemDetails
to support more resilient integrations
In .NET 7, we introduced the ProblemDetailsService
to improve the experience for generating error responses that comply with the ProblemDetails specification. In this release, we’ve introduced a new API to make it easier for implementers to implement fallback behavior if the ProlemDetailsService
was not able to generate a ProblemDetail
. The new TryWriteAsync
API can be used as follows in user middleware:
var problemDetailsService = httpContext.RequestServices.GetService<IProblemDetailsService>();
if (problemDetailsService == null ||
!await problemDetailsService.TryWriteAsync(new() { HttpContext = httpContext }))
{
// Your fallback behavior, since problem details was not able to be written.
}
New IResettable
interface in ObjectPool
Microsoft.Extensions.ObjectPool provides support for pooling object instances in memory. Apps can use an object pool if the values are expensive to allocate or initialize.
In Preview 2 we’re making the object pool easier to use by adding the IResettable
interface. Reusable types often need to be reset back to a default state between uses. IResettable
types are automatically reset when returned to an object pool.
public class ReusableBuffer : IResettable
{
public byte[] Data { get; } = new byte[1024 * 1024]; // 1 MB
public bool TryReset()
{
Array.Clear(Data);
return true;
}
}
var bufferPool = ObjectPool.Create<ReusableBuffer>();
var buffer = bufferPool.Get();
try
{
await ProcessDataAsync(buffer.Data);
}
finally
{
bufferPool.Return(buffer); // Data is automatically reset
}
Performance improvements to named pipes transport
In Preview 1 we announced support for using named pipes with Kestrel.
In preview 2 we’ve improved named pipe connection performance. Kestrel’s named pipe transport now accepts connections in parallel, and reuses NamedPipeServerStream
instances.
Time to create 100,000 connections:
- Before: 5.916 seconds
- After: 2.374 seconds
These improvements were suggested by the community. Thanks to the folks at Unity for helping contribute to this area!
Give feedback
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 GitHub.
Thanks for trying out ASP.NET Core!
What’s the namespace for
IResettable
?Microsoft.Extensions.ObjectPool.IResettable
The documentation for the Quickgrid has been updated for .NET 8, but I am currently working with .NET 7 and would appreciate the documentation that supported that. I’m not able to install the .NET 8 Preview SDK just yet.
Hi Paul. We don’t typically maintain docs for earlier preview versions, but we can make the source code for the QuickGrid demo site publicly available so that you can consult the commit history. We’ll try to make the sample repo public in the next week or two. In the meantime, you can still find the archived content on the internet archive.
The quick grid sample wasn’t working in Edge initially (didn’t react to mouse clicks) until I disabled the “Added security” feature of Edge. Beware!
Hi Andriy. Thanks for letting us know about this issue. I'd like to follow up with the Edge team to understand why you were impacted. Could you please let me know which specific Edge security setting you found to be problematic? Did you mean the Edge enhanced security mode? If yes, which level did you have it set at: Basic, Balanced, or Strict? Have you already reported this Edge issue using their feedback tool?
Will Blazor United be included in Preview 3?
Hi Esben. Parts of Blazor United will start to land in .NET 8 Preview 3 and then addition pieces will come in with later previews. The first step is to land server-side rendering for Blazor components, which we do expect to land with Preview 3. Streaming rendering, progressive enhancement, and the integration with client rendering will happen in later previews.
Very excited for Blazor United! Looking forward to testing that in the coming previews 🙂
This is great. Regarding IResettable – could StringBuilder please implement this? We have an ObjectPool policy now that calls .Clear() but would be better to leverage this new interface.
StringBuilder can't implement IResettable because IResettable is part of the Microsoft.Extensions.ObjectPool library.
However, you could create your own type that wraps StringBuilder (like the example in the blog post with a data array) and clears it on return. Even easier is there is a CreateStringBuilderPool method that creates a pool that automatically clears the builder on return for you.
See https://www.c-sharpcorner.com/article/speeding-up-the-stringbuilder-using-an-objectpool/
Thanks James and for your incredible gRPC work of late.
I have an abstraction on ObjectPool that gives back both an instance and an IDisposable and then returns it. Example:
<code>
My secret hope is that IResettable might be the first step in a change to C# itself, namely:
<code>
That's ok that ObjectPool is up the stack for now. Might be useful to pursue the above though - I'll check existing LDM proposals.
this comment has been deleted.
This looks super useful! Are there plans to add better official docs for it? These docs don’t tell me much:
https://learn.microsoft.com/en-us/dotnet/api/microsoft.extensions.objectpool.stringbuilderpooledobjectpolicy?view=dotnet-plat-ext-7.0
The sample here shows using a StringBuilder pool.
There aren’t plans for more documentation in this area, but you could create an issue in the dotnet/aspnetcore.docs repository if there is something that’s unclear.
Very cool!
I am on a plan to migrate a project from React Native to Blazor Hybrid on .NET 8 .