Blazor WebAssembly 3.2.0 Preview 1 release now available

Daniel Roth

Today we released a new preview update for Blazor WebAssembly with a bunch of great new features and improvements.

Here’s what’s new in this release:

  • Version updated to 3.2
  • Simplified startup
  • Download size improvements
  • Support for .NET SignalR client

Get started

To get started with Blazor WebAssembly 3.2.0 Preview 1 install the .NET Core 3.1 SDK and then run the following command:

dotnet new -i Microsoft.AspNetCore.Blazor.Templates::3.2.0-preview1.20073.1

That’s it! You can find additional docs and samples on https://blazor.net.

Upgrade an existing project

To upgrade an existing Blazor WebAssembly app from 3.1.0 Preview 4 to 3.2.0 Preview 1:

  • Update all Microsoft.AspNetCore.Blazor.* package references to 3.2.0-preview1.20073.1.
  • In Program.cs in the Blazor WebAssembly client project replace BlazorWebAssemblyHost.CreateDefaultBuilder() with WebAssemblyHostBuilder.CreateDefault().
  • Replace IWebAssemblyHost with WebAssemblyHost.
  • Replace IWebAssemblyHostBuilder with WebAssemblyHostBuilder.
  • Move the root component registrations in the Blazor WebAssembly client project from Startup.Configure to Program.cs by calling builder.RootComponents.Add<TComponent>(string selector).
  • Move the configured services in the Blazor WebAssembly client project from Startup.ConfigureServices to Program.cs by adding services to the builder.Services collection.
  • Remove Startup.cs from the Blazor WebAssembly client project.
  • If you’re hosting Blazor WebAssembly with ASP.NET Core, in your Server project replace the call to app.UseClientSideBlazorFiles<Client.Startup>(...) with app.UseClientSideBlazorFiles<Client.Program>(...).

Version updated to 3.2

In this release we updated the versions of the Blazor WebAssembly packages to 3.2 to distinguish them from the recent .NET Core 3.1 Long Term Support (LTS) release. There is no corresponding .NET Core 3.2 release – the new 3.2 version applies only to Blazor WebAssembly. Blazor WebAssembly is currently based on .NET Core 3.1, but it doesn’t inherit the .NET Core 3.1 LTS status. Instead, the initial release of Blazor WebAssembly scheduled for May of this year will be a Current release, which “are supported for three months after a subsequent Current or LTS release” as described in the .NET Core support policy. The next planned release for Blazor WebAssembly after the 3.2 release in May will be with .NET 5. This means that once .NET 5 ships you’ll need to update your Blazor WebAssembly apps to .NET 5 to stay in support.

Simplified startup

We’ve simplified the startup and hosting APIs for Blazor WebAssembly in this release. Originally the startup and hosting APIs for Blazor WebAssembly were designed to mirror the patterns used by ASP.NET Core, but not all of the concepts were relevant. The updated APIs also enable some new scenarios.

Here’s what the new startup code in Program.cs looks like:

public class Program
{
    public static async Task Main(string[] args)
    {
        var builder = WebAssemblyHostBuilder.CreateDefault(args);
        builder.RootComponents.Add<App>("app");

        await builder.Build().RunAsync();
    }
}

Blazor WebAssembly apps now support async Main methods for the app entry point.

To a create a default host builder, call WebAssemblyHostBuilder.CreateDefault(). Root components and services are configured using the builder; a separate Startup class is no longer needed.

The following example adds a WeatherService so it’s available through dependency injection (DI):

public class Program
{
    public static async Task Main(string[] args)
    {
        var builder = WebAssemblyHostBuilder.CreateDefault(args);
        builder.Services.AddSingleton<WeatherService>();
        builder.RootComponents.Add<App>("app");

        await builder.Build().RunAsync();
    }
}

Once the host is built, you can access services from the root DI scope before any components have been rendered. This can be useful if you need to run some initialization logic before anything is rendered:

public class Program
{
    public static async Task Main(string[] args)
    {
        var builder = WebAssemblyHostBuilder.CreateDefault(args);
        builder.Services.AddSingleton<WeatherService>();
        builder.RootComponents.Add<App>("app");

        var host = builder.Build();

        var weatherService = host.Services.GetRequiredService<WeatherService>();
        await weatherService.InitializeWeatherAsync();

        await host.RunAsync();
    }
}

The host also now provides a central configuration instance for the app. The configuration isn’t populated with any data by default, but you can populate it as required in your app.

public class Program
{
    public static async Task Main(string[] args)
    {
        var builder = WebAssemblyHostBuilder.CreateDefault(args);
        builder.Services.AddSingleton<WeatherService>();
        builder.RootComponents.Add<App>("app");

        var host = builder.Build();

        var weatherService = host.Services.GetRequiredService<WeatherService>();
        await weatherService.InitializeWeatherAsync(host.Configuration["WeatherServiceUrl"]);

        await host.RunAsync();
    }
}

Download size improvements

Blazor WebAssembly apps run the .NET IL linker on every build to trim unused code from the app. In previous releases only the core framework libraries were trimmed. Starting with this release the Blazor framework assemblies are trimmed as well resulting in a modest size reduction of about 100 KB transferred. As before, if you ever need to turn off linking, add the <BlazorLinkOnBuild>false</BlazorLinkOnBuild> property to your project file.

Support for the .NET SignalR client

You can now use SignalR from your Blazor WebAssembly apps using the .NET SignalR client.

To give SignalR a try from your Blazor WebAssembly app:

  1. Create an ASP.NET Core hosted Blazor WebAssembly app.

    dotnet new blazorwasm -ho -o BlazorSignalRApp
    
  2. Add the ASP.NET Core SignalR Client package to the Client project.

    cd BlazorSignalRApp
    dotnet add Client package Microsoft.AspNetCore.SignalR.Client
    
  3. In the Server project, add the following Hub/ChatHub.cs class.

    using System.Threading.Tasks;
    using Microsoft.AspNetCore.SignalR;
    
    namespace BlazorSignalRApp.Server.Hubs
    {
        public class ChatHub : Hub
        {
            public async Task SendMessage(string user, string message)
            {
                await Clients.All.SendAsync("ReceiveMessage", user, message);
            }
        }
    }
    
  4. In the Server project, add the SignalR services in the Startup.ConfigureServices method.

    services.AddSignalR();
    
  5. Also add an endpoint for the ChatHub in Startup.Configure.

    .UseEndpoints(endpoints =>
    {
        endpoints.MapDefaultControllerRoute();
        endpoints.MapHub<ChatHub>("/chatHub");
        endpoints.MapFallbackToClientSideBlazor<Client.Program>("index.html");
    });
    
  6. Update Pages/Index.razor in the Client project with the following markup.

    @using Microsoft.AspNetCore.SignalR.Client
    @page "/"
    @inject NavigationManager NavigationManager
    
    <div>
        <label for="userInput">User:</label>
        <input id="userInput" @bind="userInput" />
    </div>
    <div class="form-group">
        <label for="messageInput">Message:</label>
        <input id="messageInput" @bind="messageInput" />
    </div>
    <button @onclick="Send" disabled="@(!IsConnected)">Send Message</button>
    
    <hr />
    
    <ul id="messagesList">
        @foreach (var message in messages)
        {
            <li>@message</li>
        }
    </ul>
    
    @code {
        HubConnection hubConnection;
        List<string> messages = new List<string>();
        string userInput;
        string messageInput;
    
        protected override async Task OnInitializedAsync()
        {
            hubConnection = new HubConnectionBuilder()
                .WithUrl(NavigationManager.ToAbsoluteUri("/chatHub"))
                .Build();
    
            hubConnection.On<string, string>("ReceiveMessage", (user, message) =>
            {
                var encodedMsg = user + " says " + message;
                messages.Add(encodedMsg);
                StateHasChanged();
            });
    
            await hubConnection.StartAsync();
        }
    
        Task Send() => hubConnection.SendAsync("SendMessage", userInput, messageInput);
    
        public bool IsConnected => hubConnection.State == HubConnectionState.Connected;
    }
    
  7. Build and run the Server project

    cd Server
    dotnet run
    
  8. Open the app in two separate browser tabs to chat in real time over SignalR.

Known issues

Below is the list of known issues with this release that will get addressed in a future update.

  • Running a new ASP.NET Core hosted Blazor WebAssembly app from the command-line results in the warning: CSC : warning CS8034: Unable to load Analyzer assembly C:\Users\user\.nuget\packages\microsoft.aspnetcore.components.analyzers\3.1.0\analyzers\dotnet\cs\Microsoft.AspNetCore.Components.Analyzers.dll : Assembly with same name is already loaded.

    • Workaround: This warning can be ignored or suppressed using the <DisableImplicitComponentsAnalyzers>true</DisableImplicitComponentsAnalyzers> MSBuild property.

Feedback

We hope you enjoy the new features in this preview release of Blazor WebAssembly! Please let us know what you think by filing issues on GitHub.

Thanks for trying out Blazor!

108 comments

Discussion is closed. Login to edit/delete existing comments.

  • Baran Ozdemir 0

    Hi Dan,

    Thanks for the update. First thing I noticed with my client-side app, I get these errors below. However the application works fine. Not sure why it is complaining about pdb files.

    Failed to load resource: the server responded with a status of 404 (Not Found) XXXX.Business.Web.pdb:1
    Failed to load resource: the server responded with a status of 404 (Not Found) XXXX.Models.pdb:1
    Failed to load resource: the server responded with a status of 404 (Not Found) XXXX.Business.SharedServices.pdb:1
    Failed to load resource: the server responded with a status of 404 (Not Found) XXXX.Models.pdb:1 
    Failed to load resource: the server responded with a status of 404 (Not Found) /_framework/_bin/Microsoft.WindowsAzure.Storage.pdb:1
  • Laxman Nagtilak 0

    Unable to find the _content folder in WebAssembly 3.2.0 Preview 1.
    I am using Blazored.Toast in my webassembly Project.
    I have referenced the css in index.html as below.

    <link href=”_content/Blazored.Toast/blazored-toast.css” rel=”stylesheet” />

    Before updating to WebAssembly 3.2.0 Preview 1 it was working but after updating the blazor to WebAssembly 3.2.0 Preview 1 it is not working .
    issue is Css file not found at the path.

  • JAHANGIR HUMMAYUN 0

    Hi Daniel,
    I have updated my existing project and changed Main method as you advised and given below. But i am getting an error that WebAssemblyHostBuilder is inaccessible due to its protection level.
    Can you please advise.

    Thanks

    • JAHANGIR HUMMAYUN 0

      Problem is resolved.

      • mohamed charif 0

        Could you tell me how you have resolved it?

        • Wil Wilder Apaza Bustamante 0

          this comment has been deleted.

  • Chris Simeone 0

    Great post Dan, thanks!

    Can I create a Blazor WebAssembly app using Visual Studio for Mac (v8.4.6 build 36)?

    I installed .NET Core 3.1 SDK and the latest Blazor WebAssembly 3.2.0 Preview 1, but Blazor WebAssembly App template does not show up in Visual Studio for Mac.

    I also tried a CLI build, but get errors as well.

    For more detail about the problems I am having, here’s my StackOverflow question:
    https://stackoverflow.com/questions/60324442/missing-blazor-webassembly-app-template-for-visual-studio-for-mac

    • Daniel RothMicrosoft employee 0

      Hi Chris. Visual Studio for Mac currently doesn’t support creating Blazor WebAssembly projects. You can, however, use Visual Studio for Mac to create and develop Blazor Server projects. Support in Visual Studio for Mac for Blazor WebAssembly is planned for their upcoming 8.6 release.

  • Ismel Martínez Díaz 0

    Hello. Sorry if I don’t understand well this web stack and what is the final goal of this new browser client technology. But I was expecting something different. I will write some questions, please give me some answers.

    Why is needed all the .net libraries (.dll)? I was expecting only one or two .wasm files. I think the C# code will be compiled to .wasm.

    Why is needed a server ? I think that I will do (dotnet build) like (webpack build – for Angular or React -) and I will obtain one or two, or several, .wasm files, and an index.html file, and then I will put those files in some public path on any server that I would running, and the browser will load those files and the page will work like an SPA.

    Thanks.

    Thanks.

    • Daniel RothMicrosoft employee 0

      Hi Ismel,

      Blazor WebAssembly apps work by including with the app a small .NET runtime implemented in WebAssembly. The .NET runtime is then used to execute normal .NET assemblies (.dlls) directly in the browser. This enables keeps build times fast and enables you to use existing .NET libraries in your app. We don’t currently compile the entire app to WebAssembly. However, enabling support for compiling more of the app to WebAssembly is something we are working on for the upcoming .NET 5 release later this year.

      The only server component you need for a Blazor WebAssembly app is a web server that can serve static files. You can host Blazor WebAssembly apps on existing static site hosts like GitHub Pages or Azure Static Sites just like you can with an Angular or React app. .NET isn’t needed on the server at all. But many web apps have both a client and server component, so if you pair Blazor WebAssembly with .NET Core you now have a full stack solution for building your entire web app.

      I hope this helps!

      • Ismel Martínez Díaz 0

        Hi Daniel,

        Thanks for the answers, they are helpful.

        For the second answer, how I can generate the static files (which is the dist folder?), so I could take those files an put them under some other server?, for example, Python Flask lightweight web server.

        Best Regards, Ismel.

        • Daniel RothMicrosoft employee 0

          After doing a dotnet publish on your Blazor WebAssembly project the dist folder is located at /bin/Release/{TARGET FRAMEWORK}/publish/{ASSEMBLY NAME}/dist.

          • Ismel Martínez Díaz 0

            I will try it. Thanks a lot.

  • Nemo 0

    Daniel, does the DOM diffing algorithm in StateHasChanged() take into account elements which are not visible and ignore them? E.g. if there is a table with 100 rows and columns, but if only the first 50 rows and 30 columns are visible, will DOM updates be pushed for the bottom 50 rows and 70 columns which are invisible? If the DOM diffing algorithm can track the visibility of elements and render accordingly, it would be really efficient and would let us build high frequency real-time user interfaces. Thank you.

    • Daniel RothMicrosoft employee 0

      Hi Srihari,

      If by “visible” they mean “within the current scroll viewport” and “not hidden by CSS rules” then no, Blazor’s diffing algorithm doesn’t know about either of those. It wouldn’t be viable to create a diffing system that was somehow sensitive to those, since they can both change over time and then the prior diffing results would become incorrect. Blazor is concerned only with building the correct DOM contents, and then it’s a separate matter for the browser to know how to present that to the user.

      The way we intend scenarios like “giant grid” to perform well is the same as used by other UI stacks, i.e., virtualization. A developer building a grid component can take care of only rendering the rows/columns that will be seen within the current scroll viewport using application-specific knowledge such as “my rows are always 20px high and the viewport is always 600px high, so there won’t be more than 31 rows visible at once”. It’s the same in React, Flutter, and others.

      I hope this helps!

  • Douglas Simao 0

    Just to understand… I created a Blazor client-side then I published it.
    it created a folder publish: Web App was published successfully file:///C:/BlazorApp1/bin/Release/netstandard2.1/publish/
    in there I got a lot of ddls: Microsoft.AspNetCore.Authorization.dll, Microsoft.Extensions.Configuration.Abstractions.dll etc also a file web.config and a folder BlazorApp1/dist with my files

    When I copied only the files from dist folder it didnt work, then when I copied everything from C:/BlazorApp1/bin/Release/netstandard2.1/publish/, ddls, web.config etc then it worked, also I did another test and deleted all dlls and it still worked

    my question is, what is the right way to publish a client side blazor app? what files I need to copy over iis?

    • Daniel RothMicrosoft employee 0

      Hi Douglas,

      The dist folder should have everything you need to run a standalone Blazor WebAssembly app. If you have an ASP.NET Core hosted Blazor WebAssembly app, then you’ll need everything in the publish folder. You can read all about how to publish Blazor WebAssembly apps here: https://docs.microsoft.com/aspnet/core/host-and-deploy/blazor/

  • Fabian 0

    Hi Daniel,
    When it comes to sending a list of vehicles (car1, car2, train2, motocycle1) from the .net server to f.ex. Angular Client I used the capability of Newtonsoft.Json to add TypeNameHandling in order to indicate the type as a metadata to each Json object. Now as Newtonsoft.Json is not supported on Blazor Webassembly I wonder how to solve this?

    • Daniel RothMicrosoft employee 0

      Newtonsoft.Json should still work with Blazor WebAssembly. If you’re finding that’s not the case for your scenario, please let us know! Just file an issue on GitHub.

      • Fabian 0

        Pardon – you’re right of course.

        Let me seize the occasion to give you a feedback about my gratitude. Two things are very special in my opinion:

        First the fact that Microsoft being the world’s biggest software developer achieved (despite its orientation for profitability) the change of ideology to turn its software development tools to open source. To me this is another revolution that Microsoft brought to the world and I am amazed how you manage to take this path by joining the two ends: open source and profitability.

        My second thankful thought is about Blazor. Without my first point, this second wouldn’t have been possible. And the impact of Blazor on the world of software is yet indescribable for me. Thank you so much for this fascinating idea with such incredible possibilities and power.

        Thanks to all those at Microsoft who made it possible to turn the framework into open source involving the courage and the hard work. And thanks to all those who brought Blazor into life. Every day in the world of Blazor is like programmers heaven. Thanks.

  • Hoffman, Scott M 0

    Is or will there be a migration document to migrate Blazor Server apps to Web Assembly?

      • Hoffman, Scott M 0

        Thank you!

        BTW, I really appreciate all the work that has been done to bring Blazor (both server side and web assembly) up to production support quality.

  • Piercarlo Schiavo - BIsolution 0

    Hi Daniel,

    I have a problem that “WebAssemblyHostBuilder” doesn´t load the appsettings.json configuration.

    I have the file “appsettings.json” in main directory of client side but the host.Configuration is every time empty.

    It would load “appsettings.json” as default like “IConfiguration” on server side or I need to do some other else ?

    Thank you for help

    var host = builder.Build();
    var configEmail = host.Services.GetRequiredService<ConfigEmailVerfificationUrl>();
    configEmail.EmailVerificationUrl = host.Configuration["GlobalSettings:GeneralSettings:EmailVerificationUrl"];
    await host.RunAsync();

Feedback usabilla icon