.NET 6 Preview 2 is now available and includes many great new improvements to ASP.NET Core.
Here’s what’s new in this preview release:
- Razor compiler updated to use source generators
- Support for custom event arguments in Blazor
- CSS isolation for MVC Views and Razor Pages
- Infer component generic types from ancestor components
- Preserve prerendered state in Blazor apps
- SignalR – Nullable annotations
Get started
To get started with ASP.NET Core in .NET 6 Preview 2, install the .NET 6 SDK.
If you’re on Windows using Visual Studio, we recommend installing the latest preview of Visual Studio 2019 16.10. If you’re on macOS, we recommend installing the latest preview of Visual Studio 2019 for Mac 8.10.
Upgrade an existing project
To upgrade an existing ASP.NET Core app from .NET 6 Preview 1 to .NET 6 Preview 2:
- Update all Microsoft.AspNetCore.* package references to
6.0.0-preview.2.*
. - Update all Microsoft.Extensions.* package references to
6.0.0-preview.2.*
.
See the full list of breaking changes in ASP.NET Core for .NET 6.
Razor compiler updated to use source generators
We’ve updated the Razor compiler in this preview to be implemented using C# source generators. Source generators run during compilation and can inspect what is being compiled to produce additional files that are compiled along with the rest of the project. Using source generators simplifies the Razor compiler and significantly speeds up build times.
The following graph shows the build time improvements when using the new Razor compiler to build the default Blazor Server and MVC templates:
Support for custom event arguments in Blazor
Blazor’s support for custom events is now expanded to also support custom event arguments. This allows passing arbitrary data to .NET event handlers with custom events.
For example, you may want to receive clipboard paste events along with the text that the user has pasted. To do so, first declare a custom name for your event, and a .NET class that will hold the event arguments for this event, by adding the following classes to your project:
[EventHandler("oncustompaste", typeof(CustomPasteEventArgs), enableStopPropagation: true, enablePreventDefault: true)]
public static class EventHandlers
{
// This static class doesn't need to contain any members. It's just a place where we can put
// [EventHandler] attributes to configure event types on the Razor compiler. This affects the
// compiler output as well as code completions in the editor.
}
public class CustomPasteEventArgs : EventArgs
{
// Data for these properties will be supplied by custom JavaScript logic
public DateTime EventTimestamp { get; set; }
public string PastedData { get; set; }
}
Once those are in place, you’ll get intellisense for a new event called @oncustompaste
in your Razor components. For example, in Index.razor
, you could use it as follows:
@page "/"
<p>Try pasting into the following text box:</p>
<input @oncustompaste="HandleCustomPaste" />
<p>@message</p>
@code {
string message;
void HandleCustomPaste(CustomPasteEventArgs eventArgs)
{
message = $"At {eventArgs.EventTimestamp.ToShortTimeString()}, you pasted: {eventArgs.PastedData}";
}
}
However, if you actually run the code now, the event will not fire. There’s one remaining step, which is adding some JavaScript code that actually supplies data for your new EventArgs
subclass. In your index.html
or _Host.cshtml
file, add the following:
<!-- You should add this directly after the <script> tag for blazor.server.js or blazor.webassembly.js -->
<script>
Blazor.registerCustomEventType('custompaste', {
browserEventName: 'paste',
createEventArgs: event => {
// This example only deals with pasting text, but you could use arbitrary JavaScript APIs
// to deal with users pasting other types of data, such as images
return {
eventTimestamp: new Date(),
pastedData: event.clipboardData.getData('text')
};
}
});
</script>
This tells the browser that, whenever a native paste
event occurs, it should also raise a custompaste
event and supply the event arguments data using your custom logic. Note that the conventions around event names differ between .NET (where the event names are prefixed with on
) and JavaScript (where they do not have any prefix).
CSS isolation for MVC Views and Razor Pages
CSS isolation is now supported with MVC views and Razor Pages just like it is with Blazor components. To add a view or page specific CSS file, simply add a .cshtml.css file matching the name of the .cshtml file.
Index.cshtml.css
h1 {
color: red;
}
In your layout add a link to {PROJECT NAME}.styles.css to reference the bundled styles.
<link rel="stylesheet" href="MyWebApp.styles.css" />
The styles will then only be applied to their respective views and pages:
Infer component generic types from ancestor components
When using a generic Blazor component, like a Grid<TItem>
or ListView<TItem>
, Blazor can typically infer the generic type parameters based on the parameters passed to the component so you don’t have to explicitly specify them. In more sophisticated components though, you might have multiple generic components that get used together where the type parameters are intended to match, like a Grid<TItem>
and Column<TItem>
. In these composite scenarios, generic type parameters would often need to be specified explicitly, like this:
<Grid Items="@people">
<Column TItem="Person" Name="Full name">@context.FirstName @context.LastName</Column>
<Column TItem="Person" Name="E-mail address">@context.Email</Column>
</Grid>
But what you really want to do is this:
<Grid Items="@people">
<Column Name="Full name">@context.FirstName @context.LastName</Column>
<Column Name="E-mail address">@context.Email</Column>
</Grid>
It was necessary to re-specify TItem
on each <Column>
, because each <Column>
was treated as an independent component that had no other way to know what type of data it should work with.
In .NET 6 Preview 2, Blazor can now infer generic type parameters from ancestor components. Ancestor components must opt in to this behavior. An ancestor component can cascade a type parameter by name to descendants using the [CascadingTypeParameter]
attribute. This attribute allows generic type inference to use the specified type parameter automatically with descendants that have a type parameter with the same name.
For example, you can define Grid
and Column
components that look like this:
Grid.razor
@typeparam TItem
@attribute [CascadingTypeParameter(nameof(TItem))]
...
@code {
[Parameter] public IEnumerable<TItem> Items { get; set; }
[Parameter] public RenderFragment ChildContent { get; set; }
}
Column.razor
@typeparam TItem
...
@code {
[Parameter] public string Title { get; set; }
}
You can then use the Grid
and Column
components like this:
<Grid Items="@GetItems()">
<Column Title="Product name" />
<Column Title="Num sales" />
</Grid>
@code {
IEnumerable<SaleRecord> GetItems() { ... }
}
Note: The Razor support in Visual Studio Code has not yet been updated to support this feature, so you may get incorrect errors even though the project correctly builds. This will be addressed in an upcoming tooling release.
Preserve prerendered state in Blazor apps
Blazor apps can be prerendered from the server to speed up the perceived load time of the app. The prerendered HTML can immediately be rendered while the app is setup for interactivity in the background. However, any state that was used during prerendering is lost and must be recreated when the app is fully loaded. If any state is setup asynchronously, then the UI may flicker as the the prenrendered UI is replaced with temporary placeholders and then fully rendered again.
To solve this problem, we’ve added support for persisting state into the prerendered page using the new <persist-component-state />
tag helper. In your app, you decide what state you want to persist using the new ComponentApplicationState
service. The ComponentApplicationState.OnPersisting
event is fired when state is about to be persisted into the prerendered page. You can then retrieve any persisted state when initializing your components.
The example below shows how the weather forecasts in the default FetchData
component can be persisted during prerendering and then retrieved to initialize the component in a Blazor Server app.
_Host.cshtml
<body>
<component type="typeof(App)" render-mode="ServerPrerendered" />
...
@* Persist the component state after all component invocations *@
<persist-component-state />
</body>
FetchData.razor
@page "/fetchdata"
@implements IDisposable
@inject ComponentApplicationState ApplicationState
...
@code {
protected override async Task OnInitializedAsync()
{
ApplicationState.OnPersisting += PersistForecasts;
if (!ApplicationState.TryRedeemPersistedState("fetchdata", out var data))
{
forecasts = await ForecastService.GetForecastAsync(DateTime.Now);
}
else
{
var options = new JsonSerializerOptions
{
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
PropertyNameCaseInsensitive = true,
};
forecasts = JsonSerializer.Deserialize<WeatherForecast[]>(data, options);
}
}
private Task PersistForecasts()
{
ApplicationState.PersistAsJson("fetchdata", forecasts);
return Task.CompletedTask;
}
void IDisposable.Dispose()
{
ApplicationState.OnPersisting -= PersistForecasts;
}
}
Note: A
TryRedeemFromJson<T>
helper method is available with this preview release, but has a known issue that will addressed in a future update. To work around the issue, useTryRedeemPersistedState
and manual JSON deserialization as show in the example above.
By initializing your components with the same state used during prerendering, any expensive initialization steps only needs to be executed once. The newly rendered UI also matches the prerendered UI, so no flicker occurs.
SignalR – Nullable annotations
The ASP.NET Core SignalR Client package has been annotated for nullability. This means that the C# compiler will provide appropriate feedback, when you enable nullability, based on your handling of nulls in SignalR APIs. The SignalR server has already been updated for nullability in .NET 5, but a few modifications were made in .NET 6. You can track ASP.NET Core support for nullable annotations at dotnet/aspnetcore #27389.
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!
I notice Blazor WebAssembly (.NET 5) has performance issues.
Animations such as menu open/close will stutters, typing on a textbox that is bound with an event will cause lag or characters appearing one by one in a slow manner.
I think Blazor in .NET 5 is not yet ready to be used for professional/serious businesses. One thing is probably because of interpreted WASM instead of a compiled WASM with shortcut of Mono WASM implementation.
Hi John,
It sounds like you are building a UI with a textbox inside it with an event handler on character change. This will trigger a UI refresh, and there are a couple of options for improving the performance. You can take control of the UI refresh loop by overriding ShouldRender, or Make a component for your text box that implements the logic locally that needs to occur on entry, that bubbles up an event when...
Hi John. Basic menus and text editing should work fine. If you’re having performance issues with these basic scenarios, could you please open a GitHub issue with details on how to reproduce the problems you’re seeing? Be sure to include details on the code you are testing with and the hardware and browser version that you are testing on. Thanks!
Daniel,
Nice to find your blog and information on Blazor's future. I'm using Blazor in WSD to create the portal for the new packaging system used for shipping our software updates. I've got 2 months experience under my belt and today was looking for internal sites and resources where to find out what components MS folks are building, issues and maybe a discussion alias to ask questions and listen to other's issues. ...
Hi Gary. There are a bunch of teams using Blazor internally at Microsoft, but I don’t think anything formal has been setup yet for knowledge share. Blazor operates in the open on GitHub, which is where we encourage public discussion and issue tracking to happen. Let’s chat offline about what would best meet your needs.
My pc burns at this update, can anyone tell why just like the reason told on this page: https://developercommunity.visualstudio.com/t/Constant-Oscillation-of-CPU/1352436/
Any chance you can put more resources into Razor tooling? I am working with a sizable Blazor (server-side) project and it's been nothing but grief over the past few months as I have added a good deal of .razor files. For instance, currently, the CPU will simply oscillate between 5-15% completely idle without any user interaction:
https://developercommunity.visualstudio.com/t/Constant-Oscillation-of-CPU/1352436
My rig feels like a cryptocurrency mining rig at the moment, but for Razor files. :P
EDIT: FWIW I...
Another performance issue:
https://developercommunity.visualstudio.com/t/razor-Development:-Basic-Development-Pe/1368587
It is not uncommon for my CPU to throttle for many seconds at a time at 50-75% and stay there after I stop typing. I am pretty sure it's due to the extensive nature of all the razor files that I have. Perhaps this scenario is not tested as much over there? Yet? :) I am in a "real world" scenario here and it simply feels like this is...
We have exactly the same issue. Nuking the .vs directory did help at some occasions, but still, the tooling is the biggest thing at the moment.
Hi Mike. The Visual Studio performance and reliability teams are looking into these issues, and should get back to you shortly. And yes, we are working to improve the experience with large projects and lots of Razor files. We also work with companies and users to share their real app code with us so that we can do performance testing with it. If that’s something you’d be interested in, let me know.
Ahhh awesome! Thank you so much, Daniel. I was actually diving back here to delete my comment as I felt my frustration got a bit too much of me. It's been a real churn this past month especially. Not just with Visual Studio but also with ReSharper, having reported dozens of issues there as well. A battle on two fronts as it were.
In any case, I am very glad to...
Hi Mike-E. Sorry, that bot comment is a bit confusing, and is really meant for issues marked for further investigation, not for known bugs. We are planning to address this issue in .NET 6. The VS folks already looked at it and concluded it was a Razor compiler issue that we need to address.
Hi Daniel,
Unfortunately, despite your assurances, it appears that the 20-30% razor file issue has been swept under the rug for a future sprint: https://github.com/dotnet/aspnetcore/issues/32118
It would be incredibly valuable and appreciated to have better support for larger projects, so that those of us who spend the 10-12 hours per day in Visual Studio don't have to deal with so much grief around the entire experience. :P It would seem that obvious performance issues such as...
Thank you for your reply and for your tremendous dedication to your product, Daniel. I will for sure keep the code offer in mind going forward, particularly if addressing these two outstanding issues does not solve the pain currently experienced. 👍
I have the feeling it is related to usings and ViewImports. Within the scope of a project we put all our usings inside ViewImports, so our Razor components for that library are nice and short. But somehow it triggers a recursive CPU thingy
Hey Dan, you and your team are doing amazing. But, regarding the “Support for custom event arguments in Blazor”, why do I need to write JavaScript?
Hi Saint4eva – although Blazor allows you to write C# in the browser, not all browser capabilities are available directly via WASM so there are scenarios where you have to revert to JavaScript. So interop is still going to be required as we wait for WASM to catch up and implement more browser APIs.
Hey Dan,
Why didn’t you guys fix…just kidding..
You and the team frickin’ rock 🤘💪. I’m grateful for every increment the team releases. The output and coordination coming out of .NET teams these past few years is outstanding.
Looking forward to full release 👍
Thanks Todd!. And if you ever do have some bugs you need us to fix you know where to find us on GitHub 😊.
Why did you go for this manual data persistence? It seems to me that a declarative way would be better like marking the state to be persisted with some attributes. Or maybe the reverse marking the component as one that requires data persistence and opting out with attributes on fields that are not to be persisted. Supporting direct control over the persisted state is great and all but for maximum usefulness it seems to me...
Hi Stilgar. Thanks for this suggestion! Please go ahead and open a GitHub issue for this so that we can discuss it more broadly with the community. We’re starting with what we think is a minimal yet flexible solution, but we’re open to discussing improvements that would simplify development.
I have already opened an issue about this (I even think it is the first one) and suggested using attributes – https://github.com/dotnet/aspnetcore/issues/26794
Perfect! I’ve updated the issue title to reflect the declarative nature of the ask.
I'm happy to see Blazor progressing so rapidly! But there's still serious shortcomings in the documentation.
When can we expect the syntax colorization of Razor code in the Blazor docs to be fixed? It's been completely broken everywhere in the docs for at least a year, and I think since the first production release in September 2019. I don't see any activity in the tickets below since October 2020:
https://github.com/dotnet/AspNetCore.Docs/issues/17296
(The one below is closed, but provides a...
Hi Michael. Yes, this has been a unfortunate long standing issue with Razor syntax coloring in the docs that we had hoped to get a resolution on sooner, but it’s taken longer than expected. We’re working on getting a short term resolution in place.