ASP.NET Core updates in .NET 8 Preview 2

Daniel Roth

.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 in ObjectPool
  • 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:

  1. Add reference to the Microsoft.AspNetCore.Components.QuickGrid package.

    dotnet add package Microsoft.AspNetCore.Components.QuickGrid --prerelease
  2. 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();
    }

    QuickGrid

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 the Paginator component to State
  • Rename the IsDefaultSort attribute on columns to InitialSortDirection and add IsDefaultSortColumn=true to indicate the column should still be sorted by default.
  • Remove the ResizableColumns attribute on QuickGrid. 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:

Jiterpreter performance for low level operations

These improvements add up and translate into better performance for higher layer features. In our JSON serialization tests, the jiterpreter is 40.8% faster:

Jiterpreter performance for JSON serialization

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) => ...);

FromBody analyzer

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!

15 comments

Discussion is closed. Login to edit/delete existing comments.

  • Tony Henrique 3

    Very cool!
    I am on a plan to migrate a project from React Native to Blazor Hybrid on .NET 8 .

  • Craig Johnson 0

    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.

    • James Newton-KingMicrosoft employee 1

      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/

        • James Newton-KingMicrosoft employee 1

          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.

      • Craig Johnson 1

        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:

        using (ObjectPools.Rent<StringBuilder>(out var sb))
        {
          // StringBuilder-specific policy calls .Clear()
        } // IDisposable returns instance

        My secret hope is that IResettable might be the first step in a change to C# itself, namely:

        rent (StringBuilder sb)
        {
         // invokes IResettable
         // use sb
        } // returns instance
        

        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.

        • anonymous 0

          this comment has been deleted.

  • Esben Sundgaard 1

    Will Blazor United be included in Preview 3?

    • Daniel RothMicrosoft employee 4

      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.

      • Thomas Glaser 1

        Very excited for Blazor United! Looking forward to testing that in the coming previews 🙂

  • Andriy Savin 1

    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!

    • Daniel RothMicrosoft employee 0

      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?

  • Paul Marangoni 0

    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.

    • Daniel RothMicrosoft employee 0

      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.

Feedback usabilla icon