Telerik blogs

Another year, another .NET release to look forward to.

It’s a few months until .NET 10 launches, but the preview releases are already landing. Here are some highlights of what we’ve seen so far, the problems solved and clues as to what we can expect as we edge closer to the RTM release in November.

Blazor Script Served as a Static Asset

One of the notable changes in .NET 9 was overhauled middleware for handling static assets in your Blazor apps. This change meant your static assets (CSS, JS files) are automatically compressed and fingerprinted, so they play nicely with caching and minimize how much your users have to download before your site springs into life.

But the Blazor script itself was served outside of this middleware.

In .NET 10, the Blazor Script now benefits from the same automatic precompression and fingerprinting to reduce the download size and improve caching of the file. With this change, blazor.web.js drops from 183 KB to 43 KB (76% size reduction).

Easier Customization of Rows in QuickGrid

If you’re after a quick and easy way to show tabular data, Microsoft QuickGrid is a solid option. But it was difficult in previous releases to alter the style of a row based on the item being rendered.

The new RowClass parameter addresses this. Now you can change the style of a row conditionally, like this:

<QuickGrid ... RowClass="GetRowClass">
	...
</QuickGrid>
@code {
    private record OrderLine(int Id, string Item, int Quantity, bool Shipped);
    
    private string GetRowClass(OrderLine line) =>
        line.Shipped ? "highlight" : null;
}

No More Jumping Around with NavigateTo

In previous versions of .NET, when you used NavigateTo to navigate to the same page in a Blazor app with an interactive router (so running with one of Blazor’s interactive render modes), the browser would scroll to the top of the page. This was a pain if you used NavigateTo to change the query string, or fragment for the current page.

Now, the scroll position will be preserved. (This also works for forward and backward navigation to the same page.)

NavLink is a handy component in Blazor that automatically applies a CSS class to a link when the link and the current URL of the page match. This is useful when you want to show, on a Nav Menu, which page is currently selected.

With .NET 10, NavLink will now ignore the query string and fragment when you use the NavLinkMatch.All value for the Match parameter. In effect, this means the link will remain active (have the active class) if the URL matches, regardless of the query string and fragment.

You can revert to the original behavior using the snappily named Microsoft.AspNetCore.Components.Routing.NavLink.DisableMatchAllIgnoresLeftUriPart AppContext switch.

You can also create your own version of NavLink and override the logic for determining whether a URL matches or not.

public class FancyNavLink : NavLink
{
    protected override bool ShouldMatch(string currentUriAbsolute)
    {
        bool shouldMatch = false;     
        
        var href = this.AdditionalAttributes?["href"];
        
        // conditional logic here, to compare href with currentUriAbsolute

        return shouldMatch;
    }
}

Easily Customized Reconnection UI

The Blazor Web App template now includes the markup, CSS and JS for the standard Reconnection UI component.

.NET 10 reconnection dialog

This is the UI that will be shown when your client loses the WebSocket connection to the server.

Should you choose not to use this component, a default reconnection UI will be used as a fallback.

There’s also now a components-reconnect-state-changed event that’s dispatched when reconnection state changes. And there’s a new reconnection state of retrying, which you can handle in your reconnection UI.

Declarative Model for Persisting State

By default, your Blazor components are prerendered—meaning they’re rendered once on the server, at which point the rendered HTML is returned and displayed in the browser.

Then the component is rendered again, either on the server or client (depending on whether you’re using Blazor Server or WebAssembly).

The upshot of this is you can get a visible effect where you see data appear (after the preload) then “flash” as the data is fetched, and rendered, again in one of Blazor’s interactive modes.

You can avoid this second load by persisting state from the prerender, so your component uses that persisted state when it renders in interactive mode. But today it takes quite a bit of boilerplate code to make that happen, creating a PersistingComponentStateSubscription, using ApplicationState to look for persisted state and disposing of everything properly.

In .NET 10, you can do it with one attribute.

@code {
    
    [SupplyParameterFromPersistentComponentState]
    public List<User>? Users { get; set; }

    protected override async Task OnInitializedAsync()
    {
        Users ??= await UserService.GetUsersAsync();
    }
    
}

With this, when the component prerenders the user list will be stored in persisted state. It will be serialized and sent “over the wire” to the Blazor app running in Interactive Server or Interactive WebAssembly mode.

Blazor WASM Apps Can Reference Fingerprinted Versions of Static Web Assets

Standalone Blazor WASM apps (those not hosted via ASP.NET Core) can reference framework static web assets.

It requires this setting in your CSProj file:

<Project Sdk="Microsoft.NET.Sdk.BlazorWebAssembly">
  <PropertyGroup>
    <TargetFramework>net10.0</TargetFramework>    
+   <WriteImportMapToHtml>true</WriteImportMapToHtml>
  </PropertyGroup>
</Project>

Then you’ll need to include an empty <script type="importmap"></script> element in your index.html file:

<head>    
    ....
+   <script type="importmap"></script>
</head>

With that in place, you can then reference the fingerprinted version of the blazor.webassembly.js script like this:

<body>
    ...
    
    <script src="_framework/blazor.webassembly#[.{fingerprint}].js"></script>
</body>

In effect, this will allow you to always get the latest version of blazor.webassembly.js with a unique filename that’s generated based on the contents of the file, meaning you should never end up with a stale version from the cache when you deploy upgraded Blazor standalone apps.

In terms of how this actually works, if you look at the source code for your app when it’s running in the browser, you’ll see something like this:

    <script type="importmap">{
  "imports": {
    "./_framework/blazor.webassembly.js": "./_framework/blazor.webassembly.7ksmg6ui0q.js",
	...
  },
  "scopes": {},
  "integrity": {
    "./_framework/blazor.webassembly.7ksmg6ui0q.js": "sha256-6X2pDdgzF4O/SgWURawQ2TGvk7fRgPqWOrHkEpM1vJk=",
    "./_framework/blazor.webassembly.js": "sha256-6X2pDdgzF4O/SgWURawQ2TGvk7fRgPqWOrHkEpM1vJk=",
    ...

  }
}</script>

There will be a lot more entries, but I’ve omitted most of them for brevity!

Here you can see how Blazor has generated an import map. This means any JS in your app that imports ./_framework/blazor.webassembly.js will be redirected to the correctly fingerprinted filename.

You’ll also see that this line:

<script src="_framework/blazor.webassembly#[.{fingerprint}].js"></script>

Has been replaced with something like this:

<script src="_framework/blazor.webassembly.7ksmg6ui0q.js"></script>

Blazor WASM Standalone Apps Can Now Set the Environment at Build Time

If you wish to control the environment for your Blazor WebAssembly app, you can now set it at build time using this property in your .csproj file:

<WasmApplicationEnvironmentName>Staging</WasmApplicationEnvironmentName>

Previously, .NET would use the Blazor-Environment header to set the environment.

This new approach means you can set this during CI/CD environments and/or when publishing via other means so that you’re using the correct configuration for your chosen environment.

In Summary

This article touches on the main changes that have emerged in the first three preview releases for .NET 10.

Still to come (from the roadmap) are:

  • Metrics for Blazor
  • Support for persisting component state across enhanced page navigations (when using Blazor SSR)
  • Microsoft Identity Platform auth option for the Blazor Web App template

Plus lots and lots of bug fixes.


Jon Hilton
About the Author

Jon Hilton

Jon spends his days building applications using Microsoft technologies (plus, whisper it quietly, a little bit of JavaScript) and his spare time helping developers level up their skills and knowledge via his blog, courses and books. He's especially passionate about enabling developers to build better web applications by mastering the tools available to them. Follow him on Twitter here.

Related Posts

Comments

Comments are disabled in preview mode.