.NET 6 Preview 6 is now available and includes many great new improvements to ASP.NET Core.
Here’s what’s new in this preview release:
- Improved Blazor accessibility
- Required Blazor component parameters
- Efficient byte array transfers for JavaScript interop
- Optional parameters for view component tag helpers
- Angular template updated to Angular 12
- OpenAPI support for minimal APIs
- Inject services into minimal APIs without
[FromServices]
attribute - Configure the accept socket for Kestrel
IHttpActivityFeature
- Long running activity tag for SignalR connections
- WebSocket compression
- SignalR WebSockets TestServer support
- New
OnCheckSlidingExpiration
event for controlling cookie renewal - ClientCertificateMode.DelayCertificate
Get started
To get started with ASP.NET Core in .NET 6 Preview 6, install the .NET 6 SDK.
If you’re on Windows using Visual Studio, we recommend installing the latest preview of Visual Studio 2022. If you’re on macOS, we recommend installing the latest preview of Visual Studio 2019 for Mac 8.10.
To get setup with .NET MAUI & Blazor for cross-platform native apps, see the latest instructions in the .NET MAUI getting started guide. Be sure to also check out the Announcing .NET MAUI Preview 6 blog post for all the details on what’s new in .NET MAUI in this release.
To install the latest .NET WebAssembly tools for ahead-of-time (AOT) compilation and runtime relinking, run the following command from an elevated command prompt:
dotnet workload install microsoft-net-sdk-blazorwebassembly-aot
If you’ve installed the .NET WebAssembly tools workload previously, you can update it to .NET 6 Preview 5 by running the following command from an elevated command prompt:
dotnet workload update
Upgrade an existing project
To upgrade an existing ASP.NET Core app from .NET 6 Preview 5 to .NET 6 Preview 6:
- Update all Microsoft.AspNetCore.* package references to
6.0.0-preview.6.*
. - Update all Microsoft.Extensions.* package references to
6.0.0-preview.6.*
.
To upgrade a .NET MAUI Blazor app from .NET 6 Preview 5 to .NET 6 Preview 6 we recommend starting from a new .NET MAUI Blazor project created with the .NET 6 Preview 5 SDK and then copying code over from your original project.
See the full list of breaking changes in ASP.NET Core for .NET 6.
Improved Blazor accessibility
We made a number of changes to the default Blazor template to improve accessibility when using a screen reader:
- We added
role="alert"
attributes to messages that should be announced when navigating to a page and removedrole="alert"
from the survey prompt component to deemphasize its content. - We updated the
Counter
component to addrole="status"
so that the current count is read as the counter gets updated. - We switched to using more semantic markup elements where appropriate, like
main
andarticle
. - We swapped out the
ul
in theNavBar
component for anav
so that its semantics are easier to identify and so it can be jumped to directly using common screen reader keyboard shortcuts. - We added a
title
to theNavBar
toggle button so that it’s purpose is clearly announced.
We also added a new FocusOnNavigate
component to Blazor, that sets the UI focus to an element based on a CSS selector after navigating from one page to another. You can see the FocusOnNavigate
component at work in the App
component in the default Blazor template:
<Router AppAssembly="@typeof(Program).Assembly">
<Found Context="routeData">
<RouteView RouteData="@routeData" DefaultLayout="@typeof(MainLayout)" />
<FocusOnNavigate RouteData="@routeData" Selector="h1" />
</Found>
<NotFound>
<LayoutView Layout="@typeof(MainLayout)">
<p role="alert">Sorry, there's nothing at this address.</p>
</LayoutView>
</NotFound>
</Router>
When the Router
navigates to a new page, the FocusOnNavigate
component sets the focus on the top-level header for that page, which gets read by screen readers. This is a common strategy in single-page apps for making sure that page navigations are appropriately announced when using a screen reader.
We’re always looking for ways to to improve the accessibility of apps built with ASP.NET Core & Blazor. If you have ideas on how to further improve accessibility, you can share your suggestions with us on GitHub. You can also learn more about building accessible apps with .NET by checking out the recent ASP.NET Community Standup on Accessibility for Web Developers or by watching the recent Let’s Learn .NET: Accessibility event.
Required Blazor component parameters
To require that a Blazor component parameter be specified when using the component, use the new [EditorRequired]
attribute:
SurveyPrompt.razor
[EditorRequired]
[Parameter]
public string Title { get; set; }
If the user tries to use the component without specifying the required parameter, they get a warning:
The [EditorRequired]
attribute is enforced at design-time and as part of the build. It isn’t enforced at runtime and it doesn’t guarantee the the parameter value cannot be null.
Efficient byte array transfer in JavaScript interop
Blazor now has more efficient support for byte arrays when performing JavaScript interop. Previously, byte arrays sent to and from JavaScript were Base64 encoded so they could be serialized as JSON, which increased the transfer size and the CPU load. This encoding has now been optimized away in .NET 6. The new byte array optimization is transparent to the user when passing a Uint8Array
from JavaScript to .NET.
When passing a byte[]
from .NET to JavaScript, the bytes are now received as a Uint8Array
instead of as a Base64 encoded string. Code that previously decoded the Base64 encoded string will need to be removed. See the related announcement for details on this breaking change.
Optional parameters for view components tag helpers
View component tag helpers now support optional parameters. If your view component has an optional parameter, you no longer need to specify a value for that parameter as a tag helper attribute.
So, if you have a view component with an optional parameter like this:
class MyViewComponent
{
IViewComponentResult Invoke(bool showSomething = false) { ... }
}
then you can now invoke it as a tag helper without having to specify a value for the showSomething
parameter:
<vc:my />
Angular template updated to Angular 12
The ASP.NET Core template for Angular now uses Angular 12.
OpenAPI support in minimal APIs
In .NET 6 preview 4, we announced minimal APIs for hosting and routing in web applications. We shared how one could develop an API in a single file with just a few lines of code. Our new streamlined APIs provide the benefits of ASP.NET with less ceremony.
Today we are excited that minimal APIs now have support for OpenAPI. With OpenAPI (Swagger) support, you can now easily set up Swagger UI to visualize and interact with minimal APIs.
Configure Swagger UI with minimal APIs
To try OpenAPI with minimal APIs, create a new ASP.NET Core empty web app using the .NET CLI dotnet new web -o MyApi
or select “ASP.NET Core Empty” in Visual Studio.
Add Swagger UI to your application
Add the Swashbuckle.AspNetCore
package to your application
dotnet add package Swashbuckle.AspNetCore
Open Program.cs
and update the following configurations to set up Swagger in you application; you will need to update the following:
Dependency Injection: Add the Swagger document generator AddSwaggerGen
to builder.services
.
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen(c =>
{
c.SwaggerDoc("v1", new OpenApiInfo { Title = "My API", Description = "Docs for my API", Version = "v1" });
});
Middleware: Call app.UseSwagger
and app.UseSwaggerUI
to add the Swagger document and UI middleware to your application.
app.UseSwagger();
app.UseSwaggerUI(c =>
{
c.SwaggerEndpoint("/swagger/v1/swagger.json", "My API V1");
});
Run your application and navigate to this URL https://localhost:5001/swagger.
Now that Swagger UI is setup, you can visualize and interact with your API.
The screenshot below is for a more fully featured API that operates with a SQLite database. We will see more of these features in .NET 6 Preview 7.
Inject services into minimal APIs without [FromServices]
attribute
This preview also allows developers to inject services to their routing handlers without the need for the [FromServices]
attribute.
Before: Code with [FromServices]
attribute
app.MapGet("/todos", async ([FromServices] TodoDbContext db) =>
{
return await db.Todos.ToListAsync();
});
After: Code without [FromServices]
attribute
app.MapGet("/todos", async (TodoDbContext db) =>
{
return await db.Todos.ToListAsync();
});
We’ve added a new capability to the dependency injection container called IServiceProviderIsService
. This capability allows developers to query the container to determine if a type is resolvable. The new routing APIs use this capability to determine if a parameter can be bound from services.
The code below shows how you can use the IServiceProviderIsService
capability to detect if MyService
and NotAService
are considered services by the dependency injection container:
var serviceProvider = new ServiceCollection()
.AddSingleton<MyService>()
.BuildServiceProvider();
var detector = serviceProvider.GetService<IServiceProviderIsService>();
if (detector is not null)
{
Console.WriteLine($"MyService is a service = {detector.IsService(typeof(MyService))}");
Console.WriteLine($"NotAService is a service = {detector.IsService(typeof(NotAService))}");
}
class MyService { }
class NotAService { }
Configure the accept socket for Kestrel
We’ve added a callback on SocketTransportOptions
that allows you to control creation of the accept socket by creating your own socket and binding to the specified endpoint. If you only want to mutate the socket after it’s bound, you can call the CreateDefaultBoundListenSocket
static helper method on SocketTransportOptions
.
var builder = WebApplication.CreateBuilder(args);
builder.WebHost.UseSockets(options =>
{
options.CreateBoundListenSocket = (endpoint) =>
{
var socket = SocketTransportOptions.CreateDefaultBoundListenSocket(endpoint);
// Modify listen socket
return socket;
};
});
IHttpActivityFeature
Hosting creates an Activity
every request when there are diagnostic listeners present. There is now a feature to allow middleware to access this activity so additional information can be included during request processing.
app.Run(context =>
{
var activity = context.Features.Get<IHttpActivityFeature>()?.Activity;
if (activity is not null)
{
activity.AddTag("some_info", "true");
}
});
Long running activity tag for SignalR connections
SignalR uses the new IHttpActivityFeature
to add an “http.long_running” tag to the request activity. This will be used by APM services like Azure Monitor Application Insights to filter SignalR requests from creating long running request alerts.
WebSocket compression
You can now optionally accept WebSocket connections that use compression. Compression is off by default because enabling compression over encrypted connections can make the app subject to CRIME/BREACH attacks. It should only be enabled if you know that sensitive information isn’t being sent or if you turn off compression for the messages that contain sensitive information with the System.Net.WebSockets.WebSocketMessageFlags.DisableCompression
flag in the SendAsync
overload. Note: Clients would also need to disable compression when sending sensitive information which is not an option when using WebSockets in the browser.
app.Run(context =>
{
if (context.WebSockets.IsWebSocketRequest)
{
using var websocket = await context.WebSockets.AcceptWebSocketAsync(
new WebSocketAcceptContext() { DangerousEnableCompression = true });
await websocket.SendAsync(...);
await websocket.ReceiveAsync(...);
await websocket.CloseAsync(WebSocketCloseStatus.NormalClosure, null, default);
}
});
SignalR WebSockets TestServer Support
We have added WebSocketFactory
to the options when creating a .NET SignalR connection. This option can be used with TestServer
to allow testing with the WebSocket transport.
WebApplicationFactory<Startup> factory;
var connection = new HubConnectionBuilder()
.WithUrl("http://localhost:53353/echo", options =>
{
options.Transports = HttpTransportType.WebSockets;
options.HttpMessageHandlerFactory = _ =>
{
return factory.Server.CreateHandler();
};
options.WebSocketFactory = async (context, token) =>
{
var wsClient = factory.Server.CreateWebSocketClient();
return await wsClient.ConnectAsync(context.Uri, default);
};
})
.Build();
New OnCheckSlidingExpiration
event for controlling cookie renewal
Cookie authentication sliding expiration can now be customized or suppressed using the new OnCheckSlidingExpiration
. For example, this event can be used by a single-page app that needs to periodically ping the server without affecting the authentication session.
Delayed client certificate negotiation
Developers can now opt-in to using delayed client certificate negotiation by specifying ClientCertificateMode.DelayCertificate
on the HttpsConnectionAdapterOptions
. This will only work with HTTP/1.1 connections since HTTP/2 strictly forbids delayed certificate renegotiation. The caller of this API must buffer the request body before requesting the client certificate.
var builder = WebApplication.CreateBuilder(args);
builder.WebHost.UseKestrel(options =>
{
options.ConfigureHttpsDefaults(adapterOptions =>
{
adapterOptions.ClientCertificateMode = ClientCertificateMode.DelayCertificate;
});
});
var app = builder.Build();
app.Use(async (context, next) =>
{
// Check if your desired criteria is met
if (desiredState == true)
{
// Buffer the request body
context.Request.EnableBuffering();
var body = context.Request.Body;
await body.DrainAsync(context.RequestAborted);
body.Position = 0;
// Request client certificate
var cert = await context.Connection.GetClientCertificateAsync();
// Disable buffering on future requests if the client doesn't provide a cert
}
return next(context);
});
app.MapGet("/", () => "Hello World!");
app.Run();
Give feedback
We hope you enjoy this preview release of ASP.NET Core in .NET 6. We’re eager to hear about your experiences with this release. Let us know what you think by filing issues on GitHub.
Thanks for trying out ASP.NET Core!
Expected more on Blazor.NET! disappointing to know about smaller releases!
Hi Guruprasad. You can find out what Blazor features we’re planning to deliver for .NET 6 from the https://themesof.net site. We just shipped some more Blazor improvements in .NET 6 Preview 7: https://devblogs.microsoft.com/aspnet/asp-net-core-updates-in-net-6-preview-7 and there’s more still to come. If there are features you’d like to see prioritized let us know by giving a 👍 on the corresponding GitHub issue.
I love the new Minimal API and it is very nice that we can now use Swagger with it. However, when using url parameters Swagger doesn’t seams to work when specifying type and/or min value.
E.g. this does not work:
<code>
However, this is working:
<code>
Will this be fixed later on or is there some way to get it working already?
Thanks for reporting this. We do plan to fix this for .NET 6, but it’s not working yet. It’s being tracked by https://github.com/dotnet/aspnetcore/issues/34553.
Dan, My question is about speeding up deserializing xml from an api request in blazor webassembly. Will AOT in .net 6 in November be able to speed up deserialization? I’ve tried AOT with .net 6 preview and I’m receiving an error that I reported on GitHub.
Hi Diana. Could you please share with me the link to the GitHub issue you opened? AOT should speed up CPU intensive tasks in general, but I don’t think we’ve done any specific perf testing with XML deserialization.
Thank you for continuing to invest in server-side Razor with View Components and Tag Helpers 🤘🤘
That is great news!
Trying to add the WebView (WPF) to a newly created project and for some reason it fails
Error NU1202 Package Microsoft.AspNetCore.Components.WebView.Wpf 6.0.100-preview.6.1003 is not compatible with net6.0-windows7.0 (.NETCoreApp,Version=v6.0). Package Microsoft.AspNetCore.Components.WebView.Wpf 6.0.100-preview.6.1003 supports: net6.0-windows10.0.19041 (.NETCoreApp,Version=v6.0)
I do have latest SDK installed https://dotnet.microsoft.com/download/dotnet/thank-you/sdk-6.0.100-preview.6-windows-x64-installer
Is this some kind of bug ?
Thanks!
Hi Oleg, that does appear to be a bug. I logged https://github.com/dotnet/maui/issues/1685 and we’ll get that fixed as soon as possible. In the meantime as a workaround you can update the of your project (CSPROJ file) to be net6.0-windows10.0.19041. This means your project for now will require Windows 10, until we fix the bug, and then you can undo that change. Thanks for the bug report!
Np! Keep up good work guys! Very excited to see this features 🙂
Dan the Preview 4 link under Open API support .. is broken.. I think it should be https://devblogs.microsoft.com/aspnet/asp-net-core-updates-in-net-6-preview-4/#introducing-minimal-apis
You currently have https://devblogs.microsoft.com/aspnet/asp-net-core-updates-in-net-6-preview-6/evblogs.microsoft.com/aspnet/asp-net-core-updates-in-net-6-preview-4/#introducing-minimal-apis
Otherwise good work and thanks to the team..
Looking forward to seeing the improvements to the Razor Editor in VS2022 Preview 2 and VS2019 16.11 Preview 3 .. that's my only real pain point with developing in Blazor right now..
Hi Howard. Yup, the link should be fixed now. Thanks for letting us know!
We hope the new Razor editor in VS2022 addresses the pain points you’ve been hitting. If you still run into issues, please report them using the VS feedback tool.
The 2 most desired features in ASP.NET 6 for me are Blazor AOT and Blazor Desktop. Unfortunately, AOT doesn't work on my target platforms due to this bug, and it appears Blazor Desktop has been taken out of scope for my target platforms.
I suppose the AOT bug will be resolved eventually, but for Blazor Desktop on Linux I have the following suggestion:
Anyone could create a WebView/WebWindow/WebKit control relatively easily by learning the public, well-documented...
Hi JinShil, we do have a sample built on Photino.NET for testing purposes: https://github.com/dotnet/aspnetcore/tree/main/src/Components/WebView/Samples/PhotinoPlatform. You could use that as a starting point for any project you're working on. We'd love to support Linux in the future, but right now we are focusing on .NET MAUI for WinUI/MacCatalyst/iOS/Android and also WPF/WinForms. There should be enough public API surface for others to add their own platforms, just like the Photino.NET sample. If you feel there are any...
So excited!
EDITED: Sorry Dan, as I recreate the project from scratch to report the issue, the issue went away when I updated all the packages to preview 6. I didn't want to create an issue earlier because there was a number of dotnet watch issue on preview 5 or earlier. Looks like it's working now. Sorry for the confusion (part of the reason why I didn't want to create bugs on previews since you guys...
Thanks Jason for letting us know! Could you please create a GitHub issue for this with some additional details on how to reproduce the problem?: https://github.com/dotnet/aspnetcore/issues/new. That way we can get the right folks on the engineering team involved to investigate.
Will do! Thanks again
Can someone explain why compression cannot be used with sensitive data?
Hi Stilgar. The concern is that compressed data over encrypted connections is susceptible to CRIME/BREACH attacks. I’ve updated the blog text to clarify this.
How do we annotate MapGet calls for Open API swagger generation? Say I want to add a description, add request/response examples and so on.
Also, we can’t we use Activity.Current to get the activity for the current request, why do we need to call:
You can use the same attributes (though some don’t work in this preview) you would in MVC.
Somebody (e.g., another middleware) may have created an intermediate activity in the causal chain of activities. In that case, Activity.Current won't the Activity associated with the request, but Activity.Current.Parent (or somewhere in the that hierarchical chain) will be.
In practice, I expect user code to only use Activity.Current. I would only use the Activity from the feature to establish a contract with your listener. For example, if you wanted to implement the OpenTelemey HTTP semantic conventions,...