ASP.NET Core updates in .NET 8 Release Candidate 1
.NET 8 Release Candidate 1 (RC1) is now available and includes many great new improvements to ASP.NET Core!
This is the first of two release candidates that we plan to share before the final .NET 8 release later this year. Most of the planned features and changes for .NET 8 are part of this release candidate and are ready for you to try out. You can find the full list of what’s new in ASP.NET Core in .NET 8 in the docs. A few areas (particularly Blazor) still have some significant changes pending. We expect to complete those changes for the next .NET 8 release candidate.
Here’s a summary of what’s new in this preview release:
- Servers & middleware
- HTTP/3 disabled by default
- API authoring
- Support for keyed services in minimal APIs, MVC, and SignalR
- Blazor
- Blazor Web App template updates
- Discover components from additional assemblies for static server rendering
- Routing improvements
- Trigger a page refresh
- Pass through arbitrary attributes to
QuickGrid
- Determine if a form field is valid
- Configure the .NET WebAssembly runtime
- Trim .NET IL after ahead-of-time (AOT) compilation
- Identity
- Removed
username
property
- Removed
- Single page apps (SPA)
- Standard .NET template options
- Metrics
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 RC1, 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.
Upgrade an existing project
To upgrade an existing ASP.NET Core app from .NET 8 Preview 7 to .NET 8 RC1:
- Update the target framework of your app to
net8.0
. - Update all Microsoft.AspNetCore.* package references to
8.0.0-rc.1.*
. - Update all Microsoft.Extensions.* package references to
8.0.0-rc.1.*
.
See also the full list of breaking changes in ASP.NET Core for .NET 8.
Servers & middleware
HTTP/3 disabled by default
HTTP/3 is no longer enabled by default in Kestrel. This change returns the Kestrel HTTP protocol behavior back to its .NET 7 state, but differs from all .NET 8 previews.
We reverted to the .NET 7 behavior because enabling HTTP/3 caused some anti-virus software to prompt whether network access is allowed when an app is launched with debugging. This isn’t a good experience, so we turned HTTP/3 off by default until we can improve the developer experience.
You can re-enable HTTP/3 per endpoint by setting the protocols your endpoint allows:
var builder = WebApplication.CreateBuilder(args);
builder.WebHost.ConfigureKestrel((context, options) =>
{
options.ListenAnyIP(5001, listenOptions =>
{
listenOptions.Protocols = HttpProtocols.Http1AndHttp2AndHttp3;
listenOptions.UseHttps();
});
});
Or, by configuring the default protocols:
var builder = WebApplication.CreateBuilder(args);
builder.WebHost.ConfigureKestrel((context, options) =>
{
options.ConfigureEndpointDefaults(listenOptions =>
{
listenOptions.Protocols = HttpProtocols.Http1AndHttp2AndHttp3;
listenOptions.UseHttps();
});
});
See Use HTTP/3 with the ASP.NET Core Kestrel web server for more information about HTTP/3 requirements and configuration.
API authoring
Support for keyed services in minimal APIs, MVC, and SignalR
In .NET 8 Preview 7, we introduced support for keyed services in DI. Starting in .NET 8 RC1, it’s now possible to use keyed services in apps using minimal APIs, controller-based APIs, and SignalR hubs. To leverage the new keyed services support, annotate the target parameter with the [FromKeyedServices("keyName")]
attribute.
Note: Resolving keyed services in the constructor of an MVC controller or SignalR hub is not currently supported.
The following sample showcases this support in minimal APIs and controllers:
using Microsoft.AspNetCore.Mvc;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddKeyedSingleton<ICache, BigCache>("big");
builder.Services.AddKeyedSingleton<ICache, SmallCache>("small");
builder.Services.AddControllers();
var app = builder.Build();
app.MapGet("/big", ([FromKeyedServices("big")] ICache bigCache) => bigCache.Get("date"));
app.MapGet("/small", ([FromKeyedServices("small")] ICache smallCache) => smallCache.Get("date"));
app.MapControllers();
app.Run();
public interface ICache
{
object Get(string key);
}
public class BigCache : ICache
{
public object Get(string key) => $"Resolving {key} from big cache.";
}
public class SmallCache : ICache
{
public object Get(string key) => $"Resolving {key} from small cache.";
}
[ApiController]
[Route("/cache")]
public class CustomServicesApiController : Controller
{
[HttpGet("big-cache")]
public ActionResult<object> GetOk([FromKeyedServices("big")] ICache cache)
{
return cache.Get("data-mvc");
}
}
public class MyHub : Hub
{
public void Method([FromKeyedServices("small")] ICache cache)
{
Console.WriteLine(cache.Get("signalr"));
}
}
Blazor
Blazor Web App template updates
In .NET 8 we’ve been adding capabilities to Blazor so that you can use Blazor components full stack for all of your web UI needs. You can now render Blazor components statically from the server in response to requests, progressively enhance the experience with enhanced navigation & form handling, stream server-rendered updates, and add rich interactivity where it’s needed using Blazor Server or Blazor WebAssembly. To optimize the app load time, Blazor can also auto-select whether to use Blazor Server or Blazor WebAssembly at runtime.
These new Blazor capabilities are now all setup for you by the Blazor Web App project template. In this release, the Blazor Web App template has been cleaned up and improved with several new options to configure different scenarios.
The Blazor Web App now has the following options:
- Use interactive WebAssembly components: Enables support for the interactive WebAssembly render mode, based on Blazor WebAssembly.
- Use interactive Server components: Enables support for the interactive Server render mode, based on Blazor Server.
- Include sample pages: If this option is selected, the project will include sample pages and a layout based on Bootstrap styling. Disable this option if you just want an empty project to start with.
If both the WebAssembly and Server render modes are selected, then the template will use the Auto render mode. The Auto render model will initially use the Server mode while the .NET runtime and app bundle is download to the browser. Once the runtime is download, Auto will switch to start using the WebAssembly render mode instead.
By default, the Blazor Web App template will enable both static and interactive server rendering using a single project. If you also enable the WebAssembly render mode, then the project will include an additional client project for your WebAssembly-based components. The built output from the client project will be downloaded to the browser and executed on the client. Any components using the WebAssembly or Auto render modes must be built from the client project.
The Blazor Web App template has a cleaned up folder structure:
- The new Components folder contains all the components in the server project.
- The Components/Layout folder contains the app layout.
- The Components/Pages folder contains the routable page components.
The component names and content have been cleaned up to match their function:
- Index.razor -> Home.razor
- Counter.razor is unchanged
- FetchData.razor -> Weather.razor
The App
component is now clean and simple:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
<base href="/" />
<link rel="stylesheet" href="bootstrap/bootstrap.min.css" />
<link rel="stylesheet" href="app.css" />
<link rel="stylesheet" href="BlazorApp51.styles.css" />
<link rel="icon" type="image/png" href="favicon.png" />
<HeadOutlet />
</head>
<body>
<Routes />
</body>
</html>
We made several change to the App
component to clear it up:
- We removed the Bootstrap icons and switched to custom SVG icons instead.
- We moved the Blazor router to the new
Routes
component and removed itsNotFound
parameter as it is never used. - We moved the default Blazor error UI to the
MainLayout
component. - We removed the
surpress-error
attribute on thescript
tag for the Blazor script, as it is no longer required.
The new Routes
component in the template simplifies making the entire app interactive: simply apply the desired render mode to the Routes
and HeadOutlet
components. The root App
component needs to be static, because it renders the Blazor script and script tags cannot be dynamically removed. You also can’t make the Blazor router directly interactive from the App
component, because it has parameters that are render fragments, which are not serializable. Interactive components rendered from static components must have serializable parameters. The Routes
component provides an appropriate boundary for enabling interactivity.
Discover components from additional assemblies for static server rendering
You can now configure additional assemblies to use for discovering routable Blazor components for static server rendering using the AddAdditionalAssemblies()
method:
app.MapRazorComponents<App>()
.AddAdditionalAssemblies(typeof(Counter).Assembly);
Routing improvements
We’ve unified the Blazor routing implementation with ASP.NET Core routing. This unification adds to the Blazor router support for the following features:
- Complex segments (
"/a{b}c{d}"
) - Default values (
"/{tier=free}"
) - All built-in route constraints
Trigger a page refresh
You can now call NavigationManager.Refresh()
to trigger a page refresh. This will refresh the page using an enhanced page navigation if possible. Otherwise, it will trigger a full page refresh. To force a full page refresh, use NavigationManager.Refresh(forceReload: true)
.
Pass through arbitrary attributes to QuickGrid
The QuickGrid
component will now pass through any additional attributes to the the rendered table
element:
<QuickGrid Items="@FilteredPeople" custom-attribute="somevalue" class="custom-class-attribute">
Thank you @ElderJames for this contribution!
Determine if a form field is valid
The new EditContext.IsValid(FieldIdentifier)
API can be used to determine if a field is valid without having to get the validation messages.
Thank you @ElderJames for this contribution!
Configure the .NET WebAssembly runtime
You can now configure various .NET runtime options during startup when running on WebAssembly using the configureRuntime
function:
<script>
Blazor.start({
configureRuntime: dotnet => {
dotnet.withEnvironmentVariable("CONFIGURE_RUNTIME", "true");
}
});
</script>
The .NET runtime instance can now accessed from Blazor.runtime
.
For more details on the .NET runtime options and APIs when running on WebAssembly, see https://github.com/dotnet/runtime/blob/main/src/mono/wasm/runtime/dotnet.d.ts.
Trim .NET IL after ahead-of-time (AOT) compilation
The new WasmStripILAfterAOT
MSBuild option enables removing the .NET IL for compiled methods after performing ahead-of-time (AOT) compilation to WebAssembly. This new stripping mode reduces the size of _framework folder by 1.7% – 4.2% based on our tests.
<PropertyGroup>
<RunAOTCompilation>true</RunAOTCompilation>
<WasmStripILAfterAOT>true</WasmStripILAfterAOT>
</PropertyGroup>
This setting will trim away the IL code for most compiled methods, including methods from libraries and methods in the app. Not all compiled methods can be trimmed, as some are still needed by the .NET interpreter at runtime.
If you hit any issues using this new trimming option for AOT compiled WebAssembly apps, let us know by opening issues on GitHub in the dotnet/runtime repo.
Identity
Removed username
property from Identity API JSON payloads
To simplify MapIdentityApi<TUser>()
and align more closely with the existing Identity UIs, the username
property has been removed from request and response JSON payloads. Username and email are now the same and the field will be named Email
moving forward (or NewEmail
in the case of registering a user).
Single page apps (SPA)
Standard .NET template options
The Visual Studio templates for using ASP.NET Core with popular frontend JavaScript frameworks like Angular, React, and Vue now support the standard .NET template options, including specifying a target .NET framework version, enabling OpenAPI support, and much more.
Metrics
In .NET 8 RC1, we’ve renamed new metrics to follow the OpenTelemetry Semantic Conventions. This change is based on feedback from users and library authors about what to name their own counters. OpenTelemetry is an existing established standard, and it is beneficial for .NET’s built-in metrics and the broader .NET ecosystem to follow that standard.
- ASP.NET Core’s primary HTTP metrics now exactly match OpenTelemetry’s
http.server.request.duration
andhttp.server.active_requests
counters. - Other counters in ASP.NET Core use the semantic convention’s naming standard. For example, the rate-limiting middleware has metrics that record the number of HTTP requests waiting for a lease and lease duration.
- Renamed the lease queue length counter from
rate-limiting-current-queued-requests
toaspnetcore.rate_limiting.queued_requests
. - Renamed the lease queue duration counter from
rate-limiting-queued-request-duration
toaspnetcore.rate_limiting.request.time_in_queue
.
- Renamed the lease queue length counter from
After updating to .NET 8 RC1, you may need to update to use the names in dashboards and alerts that use them.
For more information about available metrics in .NET 8, including a complete list of the counters available and their names, see Semantic Conventions for .NET metrics.
Known Issues
ASP.NET Redis-based output-cache
There is a known regression in the Redis-based output-cache for ASP.NET (new in .NET 8, announced in Preview 6); this feature will not work in RC1. The cause has been identified and resolved for RC2.
Blazor Web App template creates multiple counter components
The Blazor Web App uses an unnecessary workaround when enabling interactive WebAssembly components. The template generates two Counter
components: 1. A Counter
component in the client project with the render mode attribute, and 2. A Counter
page in the server project that uses the Counter
from the client. This workaround is unnecessary. The Counter
component in the server project can be removed after copying its @page
directive to the Counter
in the client project. Then call AddAdditionalAssemblies(typeof(Counter).Assembly)
in Program.cs so that the Counter
component can be discovered.
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!
60 comments
The first link “.NET 8 Release Candidate 1 (RC1) is now available” has a typo and goes to a 404 page.
The correct link: .NET 8 Release Candidate 1 (RC1) is now available
(ends with ‘rc1’ insted of ‘rc-1’)
Whoops, sorry about that! Should be fixed now.
VS2022 17.8 preview 2 download is also not available. So cannot try .net 8 rc1.
Unfortunately, there was a last-minute delay with the Visual Studio 17.8 Preview 2 release. Current estimates are that it will be available on Sept 14th.
Ah, I was wondering where the new templates were in VS Preview.. fortunately the
command line is available
Yes you can. Close VS, install RC1 SDK, relaunch and upgrade your projects. The new template is also available for new Blazor web app
Awesome news and useful info Daniel. Found Chris Sainty’s recent article on rendering modes super useful too.
What is the status of the SSR -> WebAssembly rendering persistance mechanism? Is it still coming for Razor components in .NET 8?
Hi Mark. We have support already in .NET 7 for persisting prerendered state so that it can be read and reused by an interactive component. Is that what you mean? Or are you referring to something else?
Doesn’t that only work with the Razor Pages (.cshtml) style server host files? And there you can use the render-mode=”WebAssemblyPrerendered” with persist-component-state tag helper?
Those are not usable in the new App.razor style server host files.
I found this github issue: dotnet/aspnetcore/issues/49733, is the fix still in progress?
This is crucial for any serious web application using WASM for client interactivity.
Ah! Yes, we still have work to do in .NET 8 to enable persisting prerendered state from a statically rendered Blazor component. That work is tracked by https://github.com/dotnet/aspnetcore/issues/49733 and is on track to be delivered for the next .NET 8 update.
You turned off HTTP3 by default for all environments (production, staging, development) only because some anti-malware software is misbehaving on the developer machine? Why not only in development on Windows?
Hi Sebastiaan, more of our rationale is explained here. We enabled HTTP/3 by default in some 8.0 previews to get a sense of how much usage it would see and how mature the environment was. Our conclusion was that there were still too many rough edges to make it part of the default configuration. It’s true that the most glaring problem was specific to local development on Windows (I might have characterized it as a firewall rule, rather than anti-virus/-malware software) and we could have made it opt-out in more scenarios, but we worried that would lead to confusion (e.g. because it would behave differently between dev and deployed environments). Since opting in is straightforward, we thought it would be safest to keep things as in 7.0 for the time being.
Good work!
I don’t like the idea of introducing a new term, “Static-Server Rendering”. Adding new terms tend to make things more complicated.
Hi Shannon. Blazor actually supports two forms of server-side rendering: static and interactive. This has been a source of confusion as users try to understand whether we mean traditional SSR or Blazor Server. So, we need some way of distinguishing between the two.
Is there a way for a component to tell if it is being pre-rendered or actually rendered in blazor app? For example, having an SSR app with one webassembly component that can only render itself properly in a browser, but I can generate a nice placeholder until the browser actually renders it?
Hi Laszlo. You can do a runtime platform check to see if you’re currently running on WebAssembly. But we don’t have a clean way to detect the specific render mode that is currently being used. We’re tracking adding an API for that with https://github.com/dotnet/aspnetcore/issues/49401. Give the issue a 👍 if this functionality is important to you!
This is how I solved it:
I have an abstract RenderingContext class with two deriving implementations:
For Server: https://github.com/marinasundstrom/Blazor8Test/blob/main/src/Server/ServerRenderingContext.cs
For Client: https://github.com/marinasundstrom/Blazor8Test/blob/main/src/Client/ClientRenderingContext.cs
These are, of course, registered depending on context.
You can inject RenderingContext into your component, and it will resolve to the correct implementation depending on context. When the component is running on the server, the Server-specific implementation has a property that return a value indicating whether it is pre-rendering.
You can then just check the IsPrerendering property in your component.
“We’ve unified the Blazor routing implementation with ASP.NET Core routing. ”
Does this mean we can use custom route constraints now in Blazor?
Hi John. Blazor still doesn’t support custom route constraints. Let us know on GitHub if that’s an important feature for you! Here’s the related issue: https://github.com/dotnet/aspnetcore/issues/28938.
Wow, amazing Daniel, and as always, thanks for all the hard work you and the rest of the ASP.NET team put into dot net!
Question: Do you have any estimate on when the Blazor migration guide for dot net 7 to dot net 8 will be published? I just looked and noticed that it still says “coming soon”: https://learn.microsoft.com/en-us/aspnet/core/migration/70-80?view=aspnetcore-7.0&tabs=visual-studio
I think we’ll be ready to publish the migration guide for the next .NET 8 release candidate next month. Note that upgrading existing Blazor apps should be as simple as changing the target framework to net8.0 and updating to the .NET 8 packages. .NET 8 still supports the existing Blazor Server and Blazor WebAssembly hosting models. You only need to make additional changes if you want to take advantage of the new Blazor full stack web UI features in .NET 8.
Are there any downsides to creating all of our components inside .Client and using RenderModeAuto on all of them, and not use any components in .Server (also no RenderModeServer)? That seems to me the best option.
Hi Danny. That’s a valid pattern and likely to be a common scenario. We’re actually planning to add an option to the Blazor Web App template for enabling interactivity at the root of the app, just like you’re describing. The downsides are that there is generally a cost for enabling interactivity even with the Auto render mode, whether it’s handling circuits or downloading the .NET runtime for WebAssembly. If you can make a page use Static rendering it’s generally a good idea as the page will then render very fast and be very light weight. For some apps it also might make sense to use the Server interactive render mode at the root because it simplifies the app architecture. For example, with Server rendering you don’t need to figure out how to get data to the client. So how you set up your app will depend on your scenarios and requirements.
Congrats Daniel and team on another great release.
What about the revamped authentication solution? It was partially outlined in earlier releases’ blog posts, and I believe was supposed to hit with RC1, but you didn’t mention it this time.
Hi Gabor. The ASP.NET Core Identity endpoints are available to try out with .NET 8 RC1. For .NET 8 RC2 we’re also working to include in the Blazor templates an ASP.NET Core Identity UI implementation using Blazor components. We’re also working to provide samples and docs for using ASP.NET Core Identity with popular frontend JavaScript frameworks using the new Identity endpoints. Those samples and docs will be available closer to the .NET 8 release after we’ve finished up all the framework and SDK work. That’s all we plan to deliver for .NET 8. Let me know if you were expecting anything else.
Identity included in the Blazor template will be very nice, looking forward to it!
Will these components include support for oidc like current templates? I suppose It will have cookies on server and token for web assembly.
There will be no OIDC like that which Identity Server has implemented. It is gone.
But I think that you will be able to add it (back) if you want to. It is just not default anymore because of its license, and that developers want something simple.
The Identity endpoints can give you either a JSON token, or a cookie (depending on a query parameter)
If you have a mixed mode app, Server and Client (WebAssembly), you can configure HttpClient on the Client to use the cookie for auth. That will be easy, and enough for most apps, in my opinion.