.NET 8 Preview 6 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:
- Improved startup debugging experience
- Blazor
- Form model binding & validation with server-side rendering
- Enhanced page navigation & form handling
- Preserve existing DOM elements with streaming rendering
- Specify component render mode at the call site
- Interactive rendering with Blazor WebAssembly
- Sections improvements
- Cascade query string values to Blazor components
- Blazor Web App template option for enabling server interactivity
- Blazor template consolidation
- Metrics
- Testing metrics in ASP.NET Core apps
- New, improved, and renamed counters
- API authoring
- Complex form binding support in minimal APIs
- Servers & middleware
- HTTP.sys kernel response buffering
- Redis-based output-cache
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 6, install the .NET 8 SDK.
If you’re on Windows using Visual Studio, we recommend installing the latest Visual Studio 2022 preview. If you’re using Visual Studio Code, you can try out the new C# Dev Kit. If you are on macOS, you can now develop using Visual Studio for Mac 17.6.1 after enabling the preview feature for .NET 8 in Preferences.
Upgrade an existing project
To upgrade an existing ASP.NET Core app from .NET 8 Preview 5 to .NET 8 Preview 6:
- Update the target framework of your app to
net8.0
. - Update all Microsoft.AspNetCore.* package references to
8.0.0-preview.6.*
. - Update all Microsoft.Extensions.* package references to
8.0.0-preview.6.*
.
See also the full list of breaking changes in ASP.NET Core for .NET 8.
Improved startup debugging experience
Last preview we introduced debugging improvements to HttpContext
and friends. In .NET 8 Preview 6 we’ve improved the debugging experience for the WebApplication
type.
WebApplication
is the default way to configure and start ASP.NET Core apps in Program.cs
. Debug customization attributes have been applied to WebApplication
to highlight important information, such as configured endpoints, middleware, and IConfiguration
values in your IDE’s debugger.
.NET 7
.NET 8
See the ASP.NET Core ❤️ Debugging GitHub issue for more information about debugging improvements in .NET 8.
Blazor
Form model binding & validation with server-side rendering
Blazor’s new server-side rendering mode can now model bind and validate HTTP form post values.
To bind data from a form request, apply the [SupplyParameterFromForm]
attribute to a component property. Data in the request that matches the name of the property will be bound to the property. The property can be a primitive type, complex type, collection, or dictionary. Server-side validation using data annotations is also supported as well.
Movie.cs
public class Movie
{
public int Id { get; set; }
public string? Title { get; set; }
public DateOnly? ReleaseDate { get; set; }
public string? Genre { get; set; }
public decimal Price { get; set; }
}
Pages/Movies/Create.razor
@page "/movies/create"
@inject BlazorMovieContext DB
<PageTitle>Create</PageTitle>
<h1>Create</h1>
<h4>Movie</h4>
<hr />
<div class="row">
<div class="col-md-4">
<EditForm method="post" Model="Movie" OnValidSubmit="AddMovie">
<DataAnnotationsValidator />
<ValidationSummary class="text-danger" />
<div class="mb-3">
<label for="title" class="form-label">Title:</label>
<InputText id="title" @bind-Value="Movie.Title" class="form-control" />
<ValidationMessage For="() => Movie.Title" class="text-danger" />
</div>
<div class="mb-3">
<label for="release-date" class="form-label">Release date:</label>
<InputDate id="release-date" @bind-Value="Movie.ReleaseDate" class="form-control" />
<ValidationMessage For="() => Movie.ReleaseDate" class="text-danger" />
</div>
<div class="mb-3">
<label for="genre" class="form-label">Genre:</label>
<InputText id="genre" @bind-Value="Movie.Genre" class="form-control" />
<ValidationMessage For="() => Movie.Genre" class="text-danger" />
</div>
<div class="mb-3">
<label for="price" class="form-label">Price:</label>
<InputNumber id="price" @bind-Value="Movie.Price" min="0" step="0.01" class="form-control" />
<ValidationMessage For="() => Movie.Price" class="text-danger" />
</div>
<button type="submit" class="btn btn-primary">Create</button>
</EditForm>
</div>
</div>
<div>
@if (movieAdded)
{
<span>
Movie was added.
</span>
}
<a href="/movies">Back to List</a>
</div>
@code {
[SupplyParameterFromForm]
public Movie Movie { get; set; } = new();
private bool movieAdded = false;
public async Task AddMovie()
{
DB.Movie.Add(Movie);
await DB.SaveChangesAsync();
movieAdded = true;
}
}
If there are multiple forms on a page they can be distinguished using the Name
parameter, and you can use the Name
property on the [SupplyParameterFromForm]
to indicate which form you wish to bind data from.
You no longer need to set up a CascadingModelBinder
component to enable model binding. It’s now set up for you automatically.
Enhanced page navigation & form handling
Blazor will now enhance page navigation and form handling by intercepting the request in order to apply the response to the existing DOM preserving as much as possible. The enhancement avoids the need to fully load the page and provides a much smoother user experience, similar to a single page app (SPA), even though the app is still being server-side rendered.
In this preview release, enhanced navigation and form handling isn’t yet compatible with having interactive (Server or WebAssembly) components on the page at the same time. If your app uses interactive components, enhanced navigation will automatically be disabled. This limitation will be addressed in an upcoming preview before the .NET 8 GA release.
Preserve existing DOM elements with streaming rendering
Blazor streaming rendering will now preserve existing DOM elements when streaming updates into the page, which provides a faster and smoother user experience.
Specify component render mode at the call site
You can now specify the render mode for a component instance using the @rendermode
directive attribute. The render mode will then apply to the component and its children. For example,
<Counter @rendermode="@RenderMode.Server" />
To enable call site @rendermode
usage, make sure to set the Razor Language Version in the project file to 8.0
. This will be handled internally in the framework and won’t be necessary from the next preview release. To do this, edit your project’s .csproj
file, adding the following line into the first <PropertyGroup>
element:
<RazorLangVersion>8.0</RazorLangVersion>
Interactive rendering with Blazor WebAssembly
You can now enable interactive rendering of components with Blazor WebAssembly. While this option is not yet exposed on the Blazor Web App template, you can enable it manually.
To enable support for the WebAssembly render mode in your Blazor project, add the related services by calling app.Services.AddRazorComponents().AddWebAssemblyComponents()
and add the WebAssembly render mode by calling app.MapRazorComponents<App>().AddWebAssemblyRenderMode()
. Any components you wish to render on WebAssembly will need to be downloaded along with all of their dependencies to the browser. You’ll need to setup a separate Blazor WebAssembly project to handle building any WebAssembly specific code and reference it from your Blazor app.
You can specify the WebAssembly interactive render mode for a component by adding the [RenderModeWebAssembly]
attribute to the component definition or by specifying @rendermode="@RenderMode.WebAssembly"
on a component instance. Components that you setup to render on WebAssembly will also be prerendered from the server by default, so be sure either to author your components so they render correctly in either environment or disable prerendering when specifying the render mode: [RenderModeWebAssembly(prerender: false)]
or @rendermode="@(new WebAssemblyRenderMode(prerender: false))
.
Here’s a sample showcasing how to set up WebAssembly-based interactivity for a Counter
component that is rendered from the Index
page.
Note that there’s currently a limitation where components with routes must be defined in the same assembly as the App
component passed to MapRazorComponents<App>()
, so they cannot currently be defined in the client assembly. This will be addressed in a future update.
Blazor sections improvements
We’ve made the following improvements to how Blazor sections interact with other Blazor features:
- Cascading values: Cascading values will now flow into section content from where the content is defined instead of where it is rendered in a section outlet.
- Error boundaries: Unhandled exceptions will now be handled by error boundaries defined around the section content instead of around the section outlet.
- Streaming rendering: Whether section content will use streaming rendering is now determined by the component where the section content is defined instead of by the component that defines the section outlet.
Cascade query string values to Blazor components
You can now receive query string parameter values in any component, not just @page
components, using the [SupplyParameterFromQuery]
attribute. For example:
[SupplyParameterFromQuery]
public int PageIndex { get; set; }
It is no longer necessary to add the [Parameter]
attribute to any property that declares [SupplyParameterFromQuery]
.
Blazor Web App template option for enabling server interactivity
The Blazor Web App template now provides an option in Visual Studio for enabling interactivity using the server render mode:
The same option is already available from the command-line:
dotnet new blazor --use-server
Blazor template consolidation
As part of unifying the various Blazor hosting models into a single model in .NET 8, we’re also consolidating the number of Blazor project templates. In this preview release we’ve removed the Blazor Server template and the “ASP.NET Core hosted” option from the Blazor WebAssembly template. Both of these scenarios will be represented by options when using the new Blazor Web App template.
Metrics
Testing metrics in ASP.NET Core apps
In an earlier .NET 8 preview, we introduced ASP.NET Core metrics. It’s now easier to test metrics in ASP.NET Core apps.
ASP.NET Core uses the IMeterFactory
API to create and obtain meters. The meter factory integrates metrics with dependency injection, making isolating and collecting metrics easy. IMeterFactory
is especially useful for unit testing, where multiple tests can run side-by-side and you want to only gather data for your test.
The sample below shows how to use IMeterFactory
and MetricCollector<T>
(a simplified way to collect a counter’s data) in an ASP.NET Core functional test:
public class BasicTests : IClassFixture<WebApplicationFactory<Program>>
{
private readonly WebApplicationFactory<Program> _factory;
public BasicTests(WebApplicationFactory<Program> factory) => _factory = factory;
[Fact]
public async Task Get_RequestCounterIncreased()
{
// Arrange
var meterFactory = _factory.Services.GetRequiredService<IMeterFactory>();
var collector = new MetricCollector<double>(meterFactory, "Microsoft.AspNetCore.Hosting", "http-server-request-duration");
var client = _factory.CreateClient();
// Act
var response = await client.GetAsync("/");
// Assert
Assert.Equal("Hello World!", await response.Content.ReadAsStringAsync());
await collector.WaitForMeasurementsAsync(minCount: 1);
Assert.Collection(collector.GetMeasurementSnapshot(),
measurement =>
{
Assert.Equal("http", measurement.Tags["scheme"]);
Assert.Equal("GET", measurement.Tags["method"]);
Assert.Equal("/", measurement.Tags["route"]);
});
}
}
New, improved, and renamed counters
ASP.NET continues to improve its support for metrics by adding new counters and improving existing counters. We want to make ASP.NET Core apps observable in reporting dashboards and to enable custom alerts.
New counters in this preview:
routing-match-success
androuting-match-failure
report how the request was routed in the app. If the request successfully matches a route, the counter includes information about the route pattern and whether it was a fallback route.diagnostics-handler-exception
is added to the exception handling middleware. The counter reports how unhandled exceptions are processed, and includes information about the exception name and handler result.http-server-unhandled-requests
is a new counter in ASP.NET Core hosting. It reports when an HTTP request reaches the end of the middleware pipeline without being handled by the app.- Various new rate limiting middleware counters make it possible to observe the number of requests holding leases, the number of requests queued, queue duration, and more.
Improved counters:
kestrel-connection-duration
now includes the connection HTTP protocol and TLS protocol.signalr-http-transport-current-connections
now includes the connection transport type.
Finally, based on testing ASP.NET Core with cloud-native tools, we’ve renamed all ASP.NET Core counters to include more information in the name. Counters were renamed to make them identifiable by name alone and to reduce the chance of naming conflicts. For example, request-duration
was renamed to http-server-request-duration
.
API authoring
Complex form binding support in minimal APIs
In .NET 8 Preview 4 we expanded support for form binding in minimal APIs to handle certain form-based parameters without the need of the FromForm
attribute. This was limited to parameter types including
IFormCollection
, IFormFile
, and IFormFileCollection
. Minimal APIs now supports form-binding for more complex scenarios, including:
- Collections, like
List
andDictionary
- Complex types, like
Todo
orProject
The sample below showcases a minimal endpoint that binds a multi-part form input to a complex object. It also outlines how to use the anti-forgery services in ASP.NET to support the generation and validation of anti-forgery tokens in minimal APIs. Key points to note in this sample include:
- The target parameter must be annotated with the
[FromForm]
attribute to disambiguate from parameters that should be read from the JSON body. - Binding to
record
types is not currently supported, so complex types must be implemented as a class. - Recursive binding is not supported, so the
Todo
type does not contain any recursive references.
using Microsoft.AspNetCore.Antiforgery;
using Microsoft.AspNetCore.Mvc;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddAntiforgery();
var app = builder.Build();
app.MapGet("/", (HttpContext context, IAntiforgery antiforgery) =>
{
var token = antiforgery.GetAndStoreTokens(context);
var html = $"""
<html>
<body>
<form action="/todo" method="POST" enctype="multipart/form-data">
<input name="{token.FormFieldName}" type="hidden" value="{token.RequestToken}" />
<input type="text" name="name" />
<input type="date" name="dueDate" />
<input type="checkbox" name="isCompleted" />
<input type="submit" />
</form>
</body>
</html>
""";
return Results.Content(html, "text/html");
});
app.MapPost("/todo", async Task<Results<Ok<Todo>, BadRequest<string>>> ([FromForm] Todo todo, HttpContext context, IAntiforgery antiforgery) =>
{
try
{
await antiforgery.ValidateRequestAsync(context);
return Results.Ok(todo);
}
catch (AntiforgeryValidationException e)
{
return TypedResults.BadRequest("Invalid anti-forgery token");
}
});
app.Run();
class Todo
{
public string Name { get; set; } = string.Empty;
public bool IsCompleted { get; set; } = false;
public DateTime DueDate { get; set; } = DateTime.Now.Add(TimeSpan.FromDays(1));
}
Servers & middleware
HTTP.sys kernel response buffering
You can now enable kernel-based response buffering when using HTTP.sys using the EnableKernelResponseBuffering
option. This option can improve response times, particularly when writing large responses with lots of small writes to a client with high latency. In affected scenarios, this can drastically improve response times from minutes (or outright failure) to seconds.
Redis-based output caching
Output caching was introduced in .NET 7 and allows entire responses to be cached and replayed, reducing server processing. By default, cached responses are stored in-process, so each server node has a separate and isolated cache that is lost whenever the server process is restarted. As an alternative, we’re now introducing the ability to use a Redis backend for output caching, providing consistency between server nodes via a shared cache that outlives individual server processes.
To setup Redis-based output caching, add a package reference to Microsoft.Extensions.Caching.StackExchangeRedis
, then configure the required services by calling app.Services.AddStackExchangeRedisOutputCache(...)
. The available configuration options are identical to the existing Redis-based distributed caching options. You can provide your own Redis server, or use a hosted offering such as Azure Cache for Redis.
Give feedback
We hope that 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!
I hope there will be some excellent WASM/Core API Authentication and Authentication tutorials for Azure. The current offerings always seem to leave me feeling around in the dark and hoping that it will work.
Hola Daniel,
Can we use hybrid blazor in .net 8?
What rendering tipp should we use if we sharing blazor components in a razor component library project?
Thanks
Hi Manuel. Yes, Blazor Hybrid is supported with .NET 8. You'll need to get setup with .NET MAUI first: https://devblogs.microsoft.com/dotnet/announcing-dotnet-maui-in-dotnet-8-preview-6/.
Blazor components should generally work across all hosting models and rendering modes including Blazor Hybrid. We generally recommend against tying a components implementation to a particular render mode unless absolutely necessary. You can apply a render mode to a component instance in a Blazor web app using the attribute.
The method AddWebAssemblyComponents doesn’t seem to be available yet. Is this expected? The article reads as if it should already be available.
Thanks for all your hard work adding all these great capabilities.
sorry, I didn’t read all the words 😉 i see that you have to add a package and a reference to a WebAssembly project.
Thanks again.
Hi, My project has RCL share for Blazor WASM and Blazor Hybrid on .NET 7.
The performance is so good. Can I upgrade my project to .NET8 for both RCL, WASM and Hybrid? What will I change to upgrade to NET8?
Thanks
Hi Dan,
Any plans on replacing the Microsoft Identity Razor pages with Blazor components?
Hi Michalis. Yes, the related work is tracked by https://github.com/dotnet/aspnetcore/issues/48786
I have implemented my own. It was pretty straightforward to do.
https://github.com/marinasundstrom/Blazor8Test/tree/main/src/Server/Pages/Authentication
(ServerNavigationManager is just a temp workaround)
HI Dan
A question about handling Tokens. I currently have an app that handles tokens according to this article.
Tokens in Blazor
I was viewing your github sample
Net 8 Blazor Server Sample
I cant for the life of me get the 2 things to integrate. Moving the token handling code over from _host.cshtml to host.razor causes issues with an invalid reference to HttpContext.
Any guidance would be appreciated. Looking forward to porting my app to .Net 8.0. I only...
We don’t currently surface HttpContext from Blazor components. You currently need to use the IHttpContextAccessor to get access to the HttpContext. See https://github.com/dotnet/aspnetcore/issues/48769 for the related discussion.
Consider a scenario where there is a parent component rendered on the server, and a child component rendered with web assembly. Will it be possible for an event fired in the child component to call an event handler in the parent component? I have a few use cases where such a feature would be lovely.
Unfortunately, no, with the functionality planned for .NET 8 this won’t be possible. The parameters that you pass from a server-side rendered (SSR) component to an interactive WebAssembly component I believe need to be serializable.
Then what would be the best practice for a Web Assembly Rendered component to send a message to a Server Rendered component?
I'm very excited for the full release, I'm a big fan of blazor so especially the new blazor features look very promising!
I have a question related to authentication in blazor. Recently i tried to use the identity SignInManager in blazor server but it was not possible to log a user in due Identity being originally made for standard http requests and not the web-socket connection you get with a SingalR in blazor server.
Here is the...
Yup, using SignInManager with server-side rendering in a Blazor app should work pretty much the same as it does with MVC or Razor Pages.
Goodnight.
I would like to know when Native AOT Deployment will be fully available for all features of c#/asp net?
It would be great to use in aws functions lamdas.
As previously stated, the scope for .NET 8.0 for ASP.NET Core native AOT support is limited to minimal APIs, gRPC, and most middleware. Native AOT imposes a number of compatibility requirements such that there will never be a time when "all features of C#/asp.net" will be compatible, but we absolutely intend to make more features of ASP.NET Core compatible with native AOT in .NET 9 and we encourage customers to provide feedback on which compatibility...
Hi, i was playing with the default template testing StreamRendering on the Fetch Data Page, and i notice that if i switch from the Counter page (RenderModeServer) to the Fetch Data Streaming looks not to be working, If i go to the Home page, and then to the Fetch Data it does. Do we need to add something for it to work. Same if i refresh the fetch data page.
Thanks, and amazing work !
Hi Diego. Thanks for sharing this feedback! Could you please open a GitHub issue describing in more detail the problem you are seeing? https://github.com/dotnet/aspnetcore/issues/new.
I tried to reproduce what you described but streaming rendering seems to be working fine for me when I navigate back and forth between the counter and fetch data pages. One known issue you might be hitting is that CSS hot reload will prevent streaming rendering from working, so you need to...
Hi Daniel, thanks for the reply ill test its without hot reload and let you know 🙂
UPDATE: Tested and confirmed. With Hot Reload disabled, it worked as expected, and stopped
seeing this request
aspnetcore-browser-refresh.js
on the showdata page. Thanks again!