ASP.NET Core updates in .NET 8 Preview 3

Daniel Roth

.NET 8 Preview 3 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:

  • ASP.NET Core support for native AOT
  • Server-side rendering with Blazor
  • Render Razor components outside of ASP.NET Core
  • Sections support in Blazor
  • Monitor Blazor Server circuit activity
  • SIMD enabled by default for Blazor WebAssembly apps
  • Request timeouts
  • Short circuit routes

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 3, 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 2 to .NET 8 Preview 3:

  • Update the target framework of your app to net8.0.
  • Update all Microsoft.AspNetCore.* package references to 8.0.0-preview.3.*.
  • Update all Microsoft.Extensions.* package references to 8.0.0-preview.3.*.

See also the full list of breaking changes in ASP.NET Core for .NET 8.

ASP.NET Core support for native AOT

In .NET 8 Preview 3, we’re very happy to introduce native AOT support for ASP.NET Core, with an initial focus on cloud-native API applications. It’s now possible to publish an ASP.NET Core app with native AOT, producing a self-contained app that’s ahead-of-time (AOT) compiled to native code.

Native AOT apps can have a smaller deployment size, start up very quickly, and use less memory. The application can be run on a machine that doesn’t have the .NET runtime installed. The benefit of native AOT is most significant for workloads with many deployed instances, such as cloud infrastructure and hyper-scale services.

Benefits of using native AOT with ASP.NET Core

Publishing and deploying a native AOT app can provide the following benefits:

  • Reduced disk footprint: When publishing using native AOT, a single executable is produced containing the program along with the subset of code from external dependencies that the program uses. Reduced executable size can lead to:
    • Smaller container images, for example in containerized deployment scenarios.
    • Reduced deployment time due to smaller images.
  • Reduced startup time: Native AOT applications can show reduced start-up times, in part due to the removal of JIT compilation. Reduced start-up means:
    • The app is ready to service requests quicker.
    • Improved deployment with container orchestrators that manage transitions from one version of the app to another.
  • Reduced memory demand: Native AOT apps can have reduced memory demands depending on the work being performed by the app. Reduced memory consumption can lead to greater deployment density and improved scalability.

As an example, 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:

Publish kind Startup time (ms) App size (MB)
Default 169 88.5
Native AOT 34 11.3

The table above shows that publishing the app as native AOT dramatically improves startup time and app size. Startup time was reduced by 80%! And app size was reduced by 87%!

You can explore these and more metrics on our public benchmarks dashboard.

ASP.NET Core and native AOT compatibility

Not all features in ASP.NET Core are compatible with native AOT. Similarly, not all libraries commonly used in ASP.NET Core are compatible with native AOT. .NET 8 represents the start of work to enable native AOT in ASP.NET Core, with an initial focus on enabling support for apps using Minimal APIs or gRPC, and deployed in cloud-native environments. Your feedback will help guide our efforts during .NET 8 previews and beyond, to ensure we focus on the places where the benefits of native AOT can have the largest impact.

Native AOT applications come with a few fundamental compatibility requirements. The key ones include:

  • No dynamic loading (for example, Assembly.LoadFile)
  • No runtime code generation via JIT (for example, System.Reflection.Emit)
  • No C++/CLI
  • No built-in COM (only applies to Windows)
  • Requires trimming, which has limitations
  • Implies compilation into a single file, which has known incompatibilities
  • Apps include required runtime libraries (just like self-contained apps, increasing their size as compared to framework-dependent apps)

Reflection is a commonly used feature of .NET, allowing for runtime discovery and inspection of type information, dynamic invocation, and code generation. While reflection over type information is supported in native AOT, the trimming performed often can’t statically determine that a type has members that are only accessed via reflection, and are thus removed, leading to runtime exceptions. Developers can annotate their code with instructional attributes, such as [DynamicallyAccessedMembers] to indicate that members are dynamically accessed and should be left untrimmed.

Developers should also be aware that it’s not always immediately obvious that code is relying on reflection’s runtime code generation capabilities and thus can introduce native AOT incompatibilties, e.g. methods like Type.MakeGenericType rely on capabilities not available in native AOT. Roslyn source generators allow code to be generated at compile time with similar type discovery and inspection capabilities as runtime-based reflection, and are a useful alternative when preparing for native AOT compatibility.

The following table summarizes ASP.NET Core feature compatibility with native AOT:

Feature Fully Supported Partially Supported Not Supported
gRPC Fully supported
Minimal APIs Partially supported
MVC Not supported
Blazor Not supported
SignalR Not supported
Authentication Not supported (JWT soon)
CORS Fully supported
Health checks Fully supported
Http logging Fully supported
Localization Fully supported
Output caching Fully supported
Rate limiting Fully supported
Request decompression Fully supported
Response caching Fully supported
Response compression Fully supported
Rewrite Fully supported
Session Not supported
SPA Not supported
Static files Fully supported
WebSockets Fully supported

During .NET 8, you can keep track of current known issues regarding ASP.NET Core and native AOT compatibility here.

It is important to test your application thoroughly when moving to a native AOT deployment model to ensure that functionality observed during development (when the app is untrimmed and JIT-compiled) is preserved in the native executable. When building your application, keep an eye out for AOT warnings. An application that produces AOT warnings during publishing is not guaranteed to work correctly. If you don’t get any AOT warnings at publish time, you should be confident that your application will work consistently after publishing for AOT as it did during your F5 / dotnet run development workflow.

Minimal APIs and native AOT

In order to make Minimal APIs compatible with native AOT, we’re introducing the Request Delegate Generator (RDG). The RDG is a source generator that performs similar work to the RequestDelegateFactory (RDF), turning the various MapGet(), MapPost(), etc., calls in your application into RequestDelegates associated with the specified routes, but rather than doing it in-memory in your application when it starts, it does it at compile-time and generates C# code directly into your project. This removes the runtime generation of this code, and ensures the types used in your APIs are rooted in your application code in a way that is statically analyzable by the native AOT tool-chain, ensuring that required code is not trimmed away. We’re working to ensure that as many as possible of the Minimal API features you enjoy today are supported by the RDG and thus compatible with native AOT.

The RDG is enabled automatically in your project when you enable publishing with native AOT. You can also manually enable RDG even when not using native AOT by setting <EnableRequestDelegateGenerator>true</EnableRequestDelegateGenerator> in your project file. This can be useful when initially evaluating your project’s readiness for native AOT, or potentially to reduce the startup time of your application.

Minimal APIs is optimized for receiving and returning JSON payloads using System.Text.Json, and as such the compatibility requirements for JSON and native AOT apply too. This requires the use of the System.Text.Json source generator. All types accepted as parameters to or returned from request delegates in your Minimal APIs must be configured on a JsonSerializerContext that is registered via ASP.NET Core’s dependency injection, e.g.:

// Register the JSON serializer context with DI
builder.Services.ConfigureHttpJsonOptions(options =>
{
    options.SerializerOptions.AddContext<AppJsonSerializerContext>();
});

...

// Add types used in your Minimal APIs to source generated JSON serializer content
[JsonSerializable(typeof(Todo[]))]
internal partial class AppJsonSerializerContext : JsonSerializerContext
{

}

gRPC and native AOT

gRPC supports native AOT in .NET 8. Native AOT enables publishing gRPC client and server apps as small, fast native executables. Learn more about gRPC and native AOT in the related docs.

Libraries and native AOT

Many of the common libraries you enjoy using in your ASP.NET Core projects today will have some compatibility issues when used in a project targeting native AOT. Popular libraries often rely on the dynamic capabilities of .NET reflection to inspect and discover types, conditionally load libraries at runtime, and generate code on the fly to implement their functionality. As stated earlier, these behaviors can cause compatibility issues with native AOT, and as such, these libraries will need to be updated in order to work with native AOT by using tools like Roslyn source generators.

Library authors wishing to learn more about preparing their libraries for native AOT are encouraged to start by preparing their library for trimming and learning more about the native AOT compatibility requirements.

Getting started with native AOT deployment in ASP.NET Core

Native AOT is a publishing option. AOT compilation happens when the app is published. A project that uses Native AOT publishing will use JIT compilation when debugging or running as part of the developer inner-loop, but there are some observable differences:

  • Some features that aren’t compatible with native AOT are disabled and throw exceptions at runtime.
  • A source analyzer is enabled to highlight project code that isn’t compatible with Native AOT. At publish time, the entire app, including NuGet packages, is analyzed for compatibility again.

Native AOT analysis during publish includes all code from the app and the libraries the app depends on. Review native AOT warnings and take corrective steps. It’s a good idea to test publishing apps frequently to discover issues early in the development lifecycle.

The following prerequisites need to be installed before publishing .NET projects with native AOT.

On Windows, install Visual Studio 2022, including Desktop development with C++ workload with all default components.

On Linux, install the compiler toolchain and developer packages for libraries that the .NET runtime depends on.

  • Ubuntu (18.04+)
    sudo apt-get install clang zlib1g-dev
  • Alpine (3.15+)
    sudo apk add clang build-base zlib-dev

Note that at this time, cross-platform native AOT publishing is not supported, meaning you need to perform the publish on the same platform type as the intended target, e.g. if targeting a deployment to Linux, perform the publish on Linux.

Native AOT published ASP.NET Core apps can be deployed and run anywhere native executables can. Containers are a popular choice for this. Native AOT published .NET applications have the same platform requirements as .NET self-contained applications, and as such should set mcr.microsoft.com/dotnet/runtime-deps as their base image.

Native AOT-ready project templates

Options for the new ASP.NET Core API project template in Visual Studio

In this preview, there are two native AOT-enabled project templates to help get you started trying out ASP.NET Core with native AOT.

The “ASP.NET Core gRPC Service” project template has been updated to include a new “Enable native AOT publish” option that, when selected, configures the new project to publish as native AOT. This is done by setting <PublishAot>true</PublishAot> in the project’s .csproj file.

There is also a brand new “ASP.NET Core API” project template, that produces a project more directly focused on cloud-native, API-first scenarios. This also has the “Enable native AOT publish” option, and differs from the existing “Web API” project template in the following ways:

  • Uses Minimal APIs only, as MVC is not yet native AOT compatible
  • Uses the new WebApplication.CreateSlimBuilder API to ensure only the essential features are enabled by default, minimzing the app’s deployed size
  • Configured to listen on HTTP only, as HTTPS traffic is commonly handled by an ingress service in cloud-native deployments
  • Does not include a launch profile for running under IIS or IIS Express
  • Enables the JSON serializer source generator when “Enable native AOT publish” is specified during project creation
  • Includes a sample “Todos API” instead of the weather forecast sample
  • Configured to use Workstation GC in order to minimize memory use. Note this aspect is temporary as we work on GC improvements in .NET 8 intended to provide more dynamic scaling of memory use based on application load. Learn more about memory use and GC in ASP.NET Core apps here.

You can create a new API project configured to publish as native AOT using the dotnet CLI:

$ dotnet new api -aot

Here is the content of Program.cs in a project created with the new “ASP.NET Core API” template:

using System.Text.Json.Serialization;
using MyApiApplication;

var builder = WebApplication.CreateSlimBuilder(args);
builder.Logging.AddConsole();

builder.Services.ConfigureHttpJsonOptions(options =>
{
    options.SerializerOptions.AddContext<AppJsonSerializerContext>();
});

var app = builder.Build();

var sampleTodos = TodoGenerator.GenerateTodos().ToArray();

var todosApi = app.MapGroup("/todos");
todosApi.MapGet("/", () => sampleTodos);
todosApi.MapGet("/{id}", (int id) =>
    sampleTodos.FirstOrDefault(a => a.Id == id) is { } todo
        ? Results.Ok(todo)
        : Results.NotFound());

app.Run();

[JsonSerializable(typeof(Todo[]))]
internal partial class AppJsonSerializerContext : JsonSerializerContext
{

}

Native AOT call to action

Native AOT deployment is not suitable for every application, but in the scenarios where the benefits that native AOT offers are compelling, it can have a huge impact. While it’s still early, we’d love for you try out native AOT support for ASP.NET Core in .NET 8 Preview 3, and share any feedback you have by leaving a comment here, or logging an issue on GitHub. Be sure to read the current known issues regarding ASP.NET Core and native AOT compatibility.

In future previews, we’re working to enable more features of ASP.NET Core and supporting technologies with native AOT, including JWT authentication, options validation, ADO.NET data access for SQLite and PostgreSQL, and OpenTelemetry. We’re also working on improving the Visual Studio experience for configuring and working on ASP.NET Core projects targeting native AOT.

Server-side rendering with Blazor components

This preview adds initial support for server-side rendering with Blazor components. This is the beginnings of the Blazor unification effort to enable using Blazor components for all your web UI needs, client-side and server-side. This is an early preview of the functionality, so it’s still somewhat limited, but our goal is to enable using reusable Blazor components no matter how you choose to architect your app.

Server-side rendering (SSR) is when the server generates HTML in response to a request. Apps that use SSR load fast because all of the hard work of rendering the UI is being done on the server without the need to download a large JavaScript bundle. ASP.NET Core has existing support for SSR with MVC and Razor Pages, but these frameworks lack a component model for building reusable pieces of web UI. That’s where Blazor comes in! We’re adding support for building server-rendered UI using Blazor components that can then also be extended to the client to enable rich interactivity.

In this preview you can use Blazor components to do server-side rendering without the need for any .cshtml files. The framework will discover routable Blazor components and set them up as endpoints. There’s no WebAssembly or WebSocket connections involved. You don’t need to load any JavaScript. Each request is handled independently by the Blazor component for the corresponding endpoint.

To try out server-side rendering with Blazor:

  1. Create a new empty ASP.NET Core web app:

    dotnet new web -o WebApp1
    cd WebApp1
  2. Add a simple Razor component to the project:

    dotnet new razorcomponent -n MyComponent
  3. Update MyComponent.razor to make it a proper HTML page with a route:

    @page "/"
    @implements IRazorComponentApplication<MyComponent>
    
    <!DOCTYPE html>
    <html lang="en">
    <body>
        <h1>Hello Blazor!</h1>
        <p>The time is @DateTime.Now.ToShortTimeString()</p>
    </body>
    </html>

    You’ll also need to implement the IRazorComponentApplication interface on this component, which is currently used to aid in discovering component endpoints within the app. This design is likely to change in a later update, but for now this interface is required.

  4. In Program.cs setup the Razor component services by calling AddRazorComponents().

    builder.Services.AddRazorComponents();
  5. Map endpoints for you components by calling MapRazorComponents<TComponent>(). You’ll need to add a using directive for your component:

    @using WebApp1
    ...
    app.MapRazorComponents<MyComponent>();

    Routable components will be automatically discovered within the assembly MyComponent resides in. Again, note that TComponent must currently implement IRazorComponentApplication, but this design is likely to change in a later update.

  6. Run the app and browse to the app root to see your component rendered:

    Blazor server-side rendering

If you take a look at what’s happening on the network in the browser dev tools, you’ll notice that you don’t see any WebSocket connections or WebAssembly being downloaded. It’s just a single request returning fully rendered HTML from the server. This also means there isn’t any support for interactivity yet. For example, if you add a button with an @onclick handler it won’t do anything when clicked because there’s nothing setup to execute the handler. Integration with client interactivity using Blazor Server or Blazor WebAssembly is forthcoming.

All of the routing to the Blazor component endpoints is being done with ASP.NET Core endpoint routing. The Blazor router currently isn’t involved at all. This means that if you want to use a layout then you’ll need to manually apply it using the the @layout directive. A convenient way to do this is using a _Imports.razor file, which will apply directives to an entire folder . We’re looking at integrating the Blazor router with endpoint routing to make this experience a bit more seamless.

We’ve also added RazorComponentResult and RazorComponentResult<T> types that implement IResult for rendering Razor components. These result types can be returned from a manually configured endpoint:

app.MapGet("/my-component", () => new RazorComponentResult<MyComponent>());

You can also return them from an MVC controller action if you want to leverage Blazor components from an existing MVC app:

public class HomeController : Controller
{
    public IResult MyComponent()
    {
        return new RazorComponentResult<MyComponent>();
    }
}

You can find a complete sample of the default Blazor project template implemented purely with server-side rendering (but without client-side interactivity) in the ASP.NET Core GitHub repo.

This is just the beginnings of server-side rendering support with Blazor in .NET 8. You can expect plenty of improvements and enhancements in upcoming preview releases. Stay tuned!

Render Razor components outside of ASP.NET Core

A convenient side-effect of the work to enable server-side rendering with Blazor components is that you can now render Blazor components outside the context of an HTTP request. You can render Razor components as HTML directly to a string or stream independently of the ASP.NET Core hosting environment. This is convenient for scenarios where you want to generate HTML fragments, like for a generated email, or even for generating static site content.

For example, here’s how you render a Razor component to an HTML string from a console app:

  1. Create a new console app project:

    dotnet new console -o ConsoleApp1
    cd ConsoleApp1
  2. Add package references to Microsoft.AspNetCore.Components.Web and Microsoft.Extensions.Logging:

    dotnet add package Microsoft.AspNetCore.Components.Web --prerelease
    dotnet add package Microsoft.Extensions.Logging --prerelease
  3. Update your console app project to use the Razor SDK:

    <Project Sdk="Microsoft.NET.Sdk.Razor">
    ...
    </Project>
  4. Add a Razor component to the project that you want to render:

    dotnet new razorcomponent -n MyComponent
  5. Update Program.cs to create an HtmlRender and render your component by calling RenderComponentAsync. You’ll need to setup dependency injection and logging first. Also note that any calls to RenderComponentAsync must be made in the context of calling InvokeAsync on a component dispatcher. A component dispatcher is readily available from the HttmlRender.Dispatcher property.

    using Microsoft.AspNetCore.Components;
    using Microsoft.AspNetCore.Components.Web;
    using Microsoft.Extensions.DependencyInjection;
    using Microsoft.Extensions.Logging;
    using ConsoleApp1
    
    IServiceCollection services = new ServiceCollection();
    services.AddLogging();
    
    IServiceProvider serviceProvider = services.BuildServiceProvider();
    ILoggerFactory loggerFactory = serviceProvider.GetRequiredService<ILoggerFactory>();
    
    await using var htmlRenderer = new HtmlRenderer(serviceProvider, loggerFactory);
    var html = await htmlRenderer.Dispatcher.InvokeAsync(async () =>
    {
        var parameters = ParameterView.Empty;
        var output = await htmlRenderer.RenderComponentAsync<MyComponent>(parameters);
        return output.ToHtmlString();
    });
    
    Console.WriteLine(html);

    Alternatively, you can write the HTML to a TextWriter by calling output.WriteHtmlTo(textWriter).

The task returned by RenderComponentAsync will complete when the component has fully rendered, including completing any async lifecycle methods. If you want to observe the rendered HTML earlier you can call BeginRenderComponentAsync instead. You can then wait for the component rendering to complete by awaiting WaitForQuiescenceAsync on the returned HtmlComponent instance.

Sections support in Blazor

The new SectionOutlet and SectionContent components in Blazor add support for specifying outlets for content that can be filled in later. Sections are often used to define placeholders in layouts that are then filled in by specific pages. Sections are referenced either by a unique name, or using a unique object ID.

For example, try adding a SectionOutlet to the top row of the MainLayout component in the default Blazor template. You’ll need to first add a using directive for Microsoft.AspNetCore.Components.Sections, which is easiest to do in the root _Imports.razor file:

@using Microsoft.AspNetCore.Components.Sections
...
<div class="top-row px-4">
    <SectionOutlet SectionName="TopRowSection" />
    <a href="https://docs.microsoft.com/aspnet/" target="_blank">About</a>
</div>

Pages can then specify what content to display in the TopRowSection using the SectionContent component. For example, in Counter.razor you might add another button to the top row that can increment the counter, like this:

<SectionContent SectionName="TopRowSection">
    <button class="btn btn-primary" @onclick="IncrementCount">Click me</button>
</SectionContent>

Monitor Blazor Server circuit activity

You can now monitor inbound circuit activity in Blazor Server apps using the new CreateInboundActivityHandler method on CircuitHandler. Inbound circuit activity is any activity sent from the browser to the server, like UI events or JavaScript-to-.NET interop calls.

For example, you can use a circuit activity handler to detect if the client is idle, like this:

public sealed class IdleCircuitHandler : CircuitHandler, IDisposable
{
    readonly Timer timer;
    readonly ILogger logger;

    public IdleCircuitHandler(IOptions<IdleCircuitOptions> options, ILogger<IdleCircuitHandler> logger)
    {
        timer = new Timer();
        timer.Interval = options.Value.IdleTimeout.TotalMilliseconds;
        timer.AutoReset = false;
        timer.Elapsed += CircuitIdle;
        this.logger = logger;
    }

    private void CircuitIdle(object? sender, System.Timers.ElapsedEventArgs e)
    {
        logger.LogInformation(nameof(CircuitIdle));
    }

    public override Func<CircuitInboundActivityContext, Task> CreateInboundActivityHandler(Func<CircuitInboundActivityContext, Task> next)
    {
        return context =>
        {
            timer.Stop();
            timer.Start();
            return next(context);
        };
    }

    public void Dispose()
    {
        timer.Dispose();
    }
}

public class IdleCircuitOptions
{
    public TimeSpan IdleTimeout { get; set; } = TimeSpan.FromMinutes(5);
}

public static class IdleCircuitHandlerServiceCollectionExtensions
{
    public static IServiceCollection AddIdleCircuitHandler(this IServiceCollection services, Action<IdleCircuitOptions> configureOptions)
    {
        services.Configure(configureOptions);
        services.AddIdleCircuitHandler();
        return services;
    }

    public static IServiceCollection AddIdleCircuitHandler(this IServiceCollection services)
    {
        services.AddScoped<CircuitHandler, IdleCircuitHandler>();
        return services;
    }
}

In a future update we plan to add APIs for evicting idle circuits so they no longer consume server resources unnecessarily.

Circuit activity handlers also provide a way to access scoped Blazor services from other non-Blazor dependency injection (DI) scopes, like scopes created using IHttpClientFactory. There is an existing pattern for accessing circuit scoped services from other DI scopes, but it requires using a custom base component type. With circuit activity handlers we can use a better approach:

public class CircuitServicesAccessor
{
    static readonly AsyncLocal<IServiceProvider> blazorServices = new();

    public IServiceProvider? Services
    {
        get => blazorServices.Value;
        set => blazorServices.Value = value;
    }
}

public class ServicesAccessorCircuitHandler : CircuitHandler
{
    readonly IServiceProvider services;
    readonly CircuitServicesAccessor circuitServicesAccessor;

    public ServicesAccessorCircuitHandler(IServiceProvider services, CircuitServicesAccessor servicesAccessor)
    {
        this.services = services;
        this.circuitServicesAccessor = servicesAccessor;
    }

    public override Func<CircuitInboundActivityContext, Task> CreateInboundActivityHandler(Func<CircuitInboundActivityContext, Task> next)
    {
        return async context =>
        {
            circuitServicesAccessor.Services = services;
            await next(context);
            circuitServicesAccessor.Services = null;
        };
    }
}

public static class CircuitServicesServiceCollectionExtensions
{
    public static IServiceCollection AddCircuitServicesAccessor(this IServiceCollection services)
    {
        services.AddScoped<CircuitServicesAccessor>();
        services.AddScoped<CircuitHandler, ServicesAccessorCircuitHandler>();
        return services;
    }
}

You can then access the circuit scoped services by injecting the CircuitServicesAccessor where it’s needed. For example, here’s how you can access the AuthenticationStateProvider from a DelegatingHandler setup using IHttpClientFactory:

public class AuthenticationStateHandler : DelegatingHandler
{
    readonly CircuitServicesAccessor circuitServicesAccessor;

    public AuthenticationStateHandler(CircuitServicesAccessor circuitServicesAccessor)
    {
        this.circuitServicesAccessor = circuitServicesAccessor;
    }

    protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
    {
        var authStateProvider = circuitServicesAccessor.Services.GetRequiredService<AuthenticationStateProvider>();
        var authState = await authStateProvider.GetAuthenticationStateAsync();

        // ...

        return await base.SendAsync(request, cancellationToken);
    }
}

SIMD enabled by default for Blazor WebAssembly apps

WebAssembly fixed-width SIMD (Single Instruction, Multiple Data) support is now available with all major browsers and we’ve enabled it by default for ahead-of-time (AOT) compiled Blazor WebAssembly apps. SIMD can improve the throughput of vectorized computations by performing an operation on multiple pieces of data, in parallel, using a single instruction.

Request timeouts

In this preview release, we’ve also added a new middleware for supporting request timeouts. You can set request timeouts for individual endpoints, controllers, or dynamically per request.

To apply request timeouts, first add the request timeout services:

builder.Services.AddRequestTimeouts();

You can then apply request timeouts using middleware by calling UseRequestTimeouts():

app.UseRequestTimeouts();

To apply request timeouts to a particular endpoint call WithRequestTimeout(timeout) or add [RequestTimeout(timeout)] to the controller or action.

The timeouts are cooperative; when they expire, the HttpContext.RequestAborted cancellation token will trigger but the request will not be forcibly aborted. It’s up to the application to monitor the token and decide how to end the request processing.

Thank you @Kahbazi for contributing this feature!

Short circuit routes

When routing matches an endpoint it typically lets the rest of the middleware pipeline run before invoking the endpoint logic. If that’s not necessary or desirable, there’s a new option that will cause routing to invoke the endpoint logic immediately and then end the request. This can be used to efficiently respond to requests that don’t require additional features like authentication, CORS, etc., such as requests for robots.txt or favicon.ico.

app.MapGet("/", () => "Hello World").ShortCircuit();

You can also use the MapShortCircuit method to setup endpoints that send a quick 404 or other status code for matched resources that you don’t want to further process.

app.MapShortCircuit(404, "robots.txt", "favicon.ico");

This was another great feature contribution from @Kahbazi. Thank you!

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!

33 comments

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

  • Marie storch 1

    typo in MapRazorComponents there is MayRazorComponents May instead of Map.
    anyways great release!

    • Daniel RothMicrosoft employee 0

      Thanks for pointing that out! Should be fixed now.

  • Alexandre Henrique 2

    Very impressive!

  • MATTIAS ENGMAN 2

    Wow! Huge! 🤩

  • Stevie White 1

    Really exciting changes – I especially like the circuit management features. Thanks again for all the hard work you, Steve and the rest of the ASP.NET team do, Daniel!

  • Tony Quach 0

    Great works! Excited about the strong focus on performance, AOT compilation, and cloud-native support. Btw, does “Not supported” mean the .NET team does not plan on supporting the features, or will it be supported eventually in the future?

    • Damian EdwardsMicrosoft employee 0

      “Not supported” means it’s not supported right now. We don’t have firm plans on which ASP.NET Core features we’ll onboard to native AOT support in what order beyond the scope we’ve shared for .NET 8. Your feedback will help us prioritize where we focus our native AOT work in future versions, so please log an issue (or upvote an existing one) to indicate which features you’d like to see native AOT support for.

  • JinShil 0

    It would be great for many of my use cases if Native AoT on ARM64 worked for Blazor Hybrid apps. The startup time for such apps on low spec ARM devices is quite poor.

    • Daniel RothMicrosoft employee 0

      Hi JInShil. .NET MAUI has its own support for AOT that you should be able to use with Blazor Hybrid apps. On which platforms are you seeing startup performance issues (Windows, macOS, iOS, Android)? Can you open a GitHub issue in the .NET MAUI repo with more details on what you are seeing? There are efforts to look at using Native AOT with .NET MAUI on iOS specifically, but that’s a long lead effort (post .NET 8). Hopefully we can address your issue faster than that.

      • JinShil 0

        We’re using Linux (ARM embedded systems for the industrial sector). Think Windows CE, but with a future.

        Since Microsoft has no interest in MAUI on Linux, MAUI is not an option. Instead I created my own at Blazor Hybrid Linux solution at https://github.com/JinShil/BlazorWebView and it seems to work well. Startup for the most basic application that just shows a window and displays the process’s runtime in the DOM is about 8~9 seconds from a cold cache, and about 5~6 seconds for subsequent runs. That’s too long given that a C Webkit application can startup in about 2 seconds from a cold cache.

        I’m creating a WebKit solution that doesn’t use Blazor at all, just manipulating the DOM from C#, and that can start up in about 5 seconds without AoT, but is about 2.5 seconds with AoT. So, AoT for Blazor Hybrid using my Linux WebKit BlazorWebView solution would prevent me from having to create the Blazor-less WebKit DOM solution, and should be able to achieve startup times of about 2~3 seconds.

  • Marvin KleinMusic 1

    Do the Blazor sections also work within _Host.cshtml?

    • Daniel RothMicrosoft employee 1

      Hi Marvin. Yes, you can setup a SectionOutlet in _Host.cshtml using the component tag helper, similar to how the existing Blazor Server templates use HeadOutlet in _Host.cshtml.

  • Laszlo Deak 0

    1st question: Why is called

    MapRazorComponents()

    when it is a Blazor component? The naming feels a little bit confusing to me.

    2nd question: “Configured to listen on HTTP only, as HTTPS traffic is commonly handled by an ingress service in cloud-native deployments” – where do you see this evolving on the long run? Is HTTPS going to be supported eventually? I am asking because HTTP/2 still works without TLS, HTTP3 requires it in ASP.NET Core.

    • Daniel RothMicrosoft employee 0

      Hi Laszlo. We avoid using the name “Blazor” in any of our APIs just in case someone ever decides that the Blazor name needs to change to something else. We want to make sure the framework APIs we ship can withstand the test of time and stay backwards compatible. So, the official name for Blazor components is actually “Razor components” even though we often informally refer to them as Blazor components.

      • Nick Antoniou 0

        Does this mean that Microsoft is not sure about the name Blazor yet?

        • Daniel RothMicrosoft employee 1

          Hi Nick. We like the name Blazor and we have no plans to change it. But sometime names need to change due to marketing or business reasons and we don’t want that to impact the names of our APIs and cause unnecessary compatibility issues for users.

          • Michael Taylor 0

            To Nick’s point though, Razor is also the name of a technology. So the fact that Razor has been around for 2 decades makes it safe but Blazor having been around for less than a decade makes it not safe? I would agree that Blazor and Razor are really too similar and should probably be called something else because it is so easy for someone to post something (question, answer, comment, etc) and accidentally leave the ‘B’ off.

  • James Wil 0

    We started using NativeAOT extensively for all of our CLIs, please talk to your Windows Defender team as they are always getting flagged as “Trojan”, your machine learning system is broken…. this is frustrating to explain to clients..

    • Andy GockeMicrosoft employee 0

      Hi, the Defender team recommends that if you see false positives you should upload binaries to https://aka.ms/wdsi and they can investigate.

      • James Wil 0

        Thanks!

  • Tanveer Badar 0

    The native AOT feature looks like very incomplete if all it supports is minimal API, and those partially.

    I can’t get my application fully migrated minimal APIs on .net 7 due to the inability to handle form posts with files and scalar fields. This will be a long road to walk, in many years to come.

    That aside, does it support commonly used libraries like EF Core, automapper, autofac etc.? Does it support using types from System.Linq.Expressions namespace?

    • Andy GockeMicrosoft employee 1

      Regarding the API support for of ASP.NET, that is slowly expanding. It was previously zero, so even Minimal APIs is significantly more than was previously available, and it will likely expand further.

      That aside, does it support commonly used libraries like EF Core, automapper, autofac etc.?

      None of these things are supported at the moment. Automapper and Autofac are external libraries, so they will have to adapt to the Native AOT limitations or new libraries that are AOT compatible will have to take their place.

      Does it support using types from System.Linq.Expressions namespace?

      System.Linq.Expressions will use an interpreter in Native AOT. This will be significantly slower than compiled expression trees. If you are primarily using expression trees for high-performance, that will never be available. You will have to move to a technology without dynamic code generation (like source generation).

Feedback usabilla icon