Blazor WebAssembly 3.2.0 Preview 5 release now available

Daniel Roth

A new preview update of Blazor WebAssembly is now available! Here’s what’s new in this release:

  • Read configuration during startup
  • Configure HTTP fetch request options
  • Honor existing web.config when publishing
  • Attach tokens to outgoing requests
  • Support for time zones

Get started

To get started with Blazor WebAssembly 3.2.0 Preview 5 install the latest .NET Core 3.1 SDK.

NOTE: Version 3.1.201 or later of the .NET Core SDK is required to use this Blazor WebAssembly release! Make sure you have the correct .NET Core SDK version by running dotnet --version from a command prompt.

Once you have the appropriate .NET Core SDK installed, run the following command to install the updated Blazor WebAssembly template:

dotnet new -i Microsoft.AspNetCore.Components.WebAssembly.Templates::3.2.0-preview5.20216.8

If you’re on Windows using Visual Studio, we recommend installing the latest preview of Visual Studio 2019 16.6. For this preview, you should still install the template from the command-line as described above to ensure that the Blazor WebAssembly template shows up correctly in Visual Studio and on the command-line.

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.2.0 Preview 4 to 3.2.0 Preview 5:

  • Update all Microsoft.AspNetCore.Components.WebAssembly.* package references to version 3.2.0-preview5.20216.8.
  • Update any Microsoft.AspNetCore.Components.WebAssembly.Runtime package references to version 3.2.0-preview5.20216.1.
  • Remove any calls to set WebAssemblyHttpMessageHandlerOptions.DefaultCredentials and instead call SetBrowserRequestCredentials on individual requests (see “Configure HTTP fetch request options” section below).
  • Remove the redirect parameter from calls to TryGetToken on AccessTokenResult.

You’re all set!

Read configuration during startup

Configuration data is now available during app startup in Program.Main using the Configuration property on WebAssemblyHostBuilder. This property can now be used both to add configuration sources and to access the current configuration data.

You can see this feature in action in the project templates when you enable authentication with Azure AD, Azure AD B2C, or an OpenID Connect provider of your choice. The authentication settings are stored in appsettings.json and then read from configuration when the app starts up:

Program.cs

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

        builder.Services.AddTransient(sp => new HttpClient { BaseAddress = new Uri(builder.HostEnvironment.BaseAddress) });

        builder.Services.AddOidcAuthentication(options =>
        {
            // Configure your authentication provider options here.
            // For more information, see https://aka.ms/blazor-standalone-auth
            builder.Configuration.Bind("Local", options.ProviderOptions);
        });

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

appsettings.json

{
  "Local": {
    "Authority": "https:login.microsoftonline.com/",
    "ClientId": "33333333-3333-3333-33333333333333333"
  }
}

Configure HTTP fetch request options

HTTP requests issued from a Blazor WebAssembly app using HttpClient are handled using the browser fetch API. In this release, we’ve added a set of extension methods for HttpRequestMessage that configure various fetch related options. These extension methods live in the Microsoft.AspNetCore.Components.WebAssembly.Http namespace:

HttpRequestMessage extension method Fetch request property
SetBrowserRequestCredentials credentials
SetBrowserRequestCache cache
SetBrowserRequestMode mode
SetBrowserRequestIntegrity integrity

You can set additional options using the more generic SetBrowserRequestOption extension method.

The HTTP response is typically buffered in a Blazor WebAssembly app to enable support for sync reads on the response content. To enable support for response streaming, use the SetBrowserResponseStreamingEnabled extension method on the request.

Honor existing web.config when publishing

When publishing a standalone Blazor WebAssembly app, a web.config is automatically generated for the app that handles configuring IIS appropriately. You can now specify your own web.config in the project, which will get used instead of the generated one.

Attach tokens to outgoing requests

Configuring authentication now adds a BaseAddressAuthorizationMessageHandler as a service that can be used with HttpClient to attach access tokens to outgoing requests. The BaseAddressAuthorizationMessageHandler is preconfigured to make requests to the the app base address. Tokens are acquired using the existing IAccessTokenProvider service. If a token cannot be acquired, an AccessTokenNotAvailableException is thrown. This exception has a Redirect method that can be used to navigate the user to the identity provider to acquire a new token.

The authentication enabled Blazor WebAssembly templates now use IHttpClientFactory to set up an HttpClient with the BaseAddressAuthorizationMessageHandler:

builder.Services.AddHttpClient("BlazorWithIdentityApp1.ServerAPI", client => client.BaseAddress = new Uri(builder.HostEnvironment.BaseAddress))
    .AddHttpMessageHandler<BaseAddressAuthorizationMessageHandler>();

// Supply HttpClient instances that include access tokens when making requests to the server project
builder.Services.AddTransient(sp => sp.GetRequiredService<IHttpClientFactory>().CreateClient("BlazorWithIdentityApp1.ServerAPI"));

You can use the configured HttpClient to make authorized requests using a simple try-catch pattern. For example, here’s the updated code in the FetchData component for requesting the weather forecast data:

protected override async Task OnInitializedAsync()
{
    try
    {
        forecasts = await Http.GetFromJsonAsync<WeatherForecast[]>("WeatherForecast");
    }
    catch (AccessTokenNotAvailableException exception)
    {
        exception.Redirect();
    }
}

Alternatively, you can simplify things even further by defining a strongly-typed client that handles all of the HTTP and token acquisition concerns within a single class:

WeatherClient.cs

public class WeatherClient
{
    private readonly HttpClient httpClient;

    public WeatherClient(HttpClient httpClient)
    {
        this.httpClient = httpClient;
    }

    public async Task<IEnumerable<WeatherForecast>> GetWeatherForeacasts()
    {
        IEnumerable<WeatherForecast> forecasts = new WeatherForecast[0];
        try
        {
            forecasts = await httpClient.GetFromJsonAsync<WeatherForecast[]>("WeatherForecast");
        }
        catch (AccessTokenNotAvailableException exception)
        {
            exception.Redirect();
        }
        return forecasts;
    }
}

Program.cs

builder.Services.AddHttpClient<WeatherClient>(client => client.BaseAddress = new Uri(builder.HostEnvironment.BaseAddress))
    .AddHttpMessageHandler<BaseAddressAuthorizationMessageHandler>();

FetchData.razor

protected override async Task OnInitializedAsync()
{
    forecasts = await WeatherClient.GetWeatherForeacasts();
}

To make authorized requests to resources not hosted at the app base, use the AuthorizationMessageHandler. The AuthorizationMessageHandler can be configured with the authorized URLs, scopes, and return URL using the ConfigureHandler method.

For example, you can configure an HttpClient to use the AuthorizationMessageHandler like this:

builder.Services.AddSingleton(sp =>
{
    return new HttpClient(sp.GetRequiredService<AuthorizationMessageHandler>()
        .ConfigureHandler(
          new [] { "https://www.example.com/base" },
          scopes: new[] {"example.read", "example.write"}))
        {
           BaseAddress = new Uri("https://www.example.com/base")
        };
});

Alternatively, you can define a custom message handler that inherits from AuthorizationMessageHandler and preconfigures the handler as required.

Support for time zones

Blazor now infers the user’s time zone and uses it in date and time calculations. In addition, APIs on System.TimeZoneInfo that previously returned incomplete results now report correct results.

Help improve the Blazor docs!

Thank you everyone who has taken the time to give feedback on how we can best improve the Blazor docs!

If you haven’t already, please join in with helping us improve the docs by doing the following:

  • As you read the Blazor docs, let us know where we should focus our efforts by telling us if you find a topic helpful or not using the helpfulness widget at the top of each doc page:

    Doc helpfulness

  • Use the Feedback section at the bottom of each doc page to let us know when a particular topic is unclear, inaccurate, or incomplete.

    Doc feedback

  • Comment on our Improve the Blazor docs GitHub issue with your suggestions for new content and ways to improve the existing content.

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!

54 comments

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

  • Horacio Diez 0

    Hi Daniel!
    Thank you very much.
    I´ve upgraded the preview and everything is working ok.
    Just a question. Do i have to jump to System.Net.Http.Json version 5.0.0-preview.3.20214.6 or stay at the 3.2.0-preview5.20210.3 ?
    Thank you again!
    Horacio

    • Daniel RothMicrosoft employee 0

      Hi Horacio. For Blazor WebAssembly apps I recommend using the 3.2.0-preview5.20210.3 version of System.Net.Http.Json.

      • Horacio Diez 0

        Thank you Daniel!

  • fci01 dev 0

    Hi, do you plan to add a template to be able to run an application in dual mode (server-side or wasm) ?

    I have seen this
    https://github.com/Suchiman/BlazorDualMode

    but I think that is something would be great to be included by default and supported in the plataform so the same app can be run in one or the other.

    Thanks

    • Igor Nesterov 0

      For what?) How do you see this? Both models have some differences which makes impossible to work it in both sides without code rewriting in most cases

      • Howard Richards 0

        If you structure the Blazor client correctly it can be re-used in both hosting modes. The main thing is to ensure you separate out anything that won’t work on the WASM client, e.g. database access etc. using an abstraction or injected services.

    • Daniel RothMicrosoft employee 0

      We don’t have any immediate plans to change the templates to support dual mode execution, but it should be possible to setup yourself.

  • Christophe MOMMER 0

    Hi Daniel !

    Very nice to see Blazor WASM moving forward ! I might be using it for a project that will be start soon, as Blazor WASM will be stable before the project ends… Can’t wait 🙂

    A question though : will it be possible to use Blazor WASM components in a ASP.NET Core MVC app ? It’s possible with Blazor Server as of now

    Thanks!

    • Mark Gould 0

      Yes, it is possible. I’m working on a POC for embedding Blazor pages inside a Razor Pages site.

      I will put it up on GitHub soon and reply back.

        • Daniel RothMicrosoft employee 0

          Thanks for answering, Mark!

        • Christophe MOMMER 0

          Thank you for this sample !
          Will migrate my Blazor.Server components to Blazor.WASM to give it a try to my MVC project 😉

        • Rogier van der Hee 0

          Great! I added this case to the Github issue with feedback for documentation.

  • Igor Nesterov 0

    Thanks for great job! Hope release will be soon!)

    • Daniel RothMicrosoft employee 0

      Thanks Igor! The release is just weeks away at this point!

  • Igor Nesterov 0

    IntelliSense really slow in .razor pages(even in project with ~10 pages or so, Core i5 6200U and 12 gb RAM), it’s applicable for last preview (4) of vs and previous as well. I see that you closed a lot of reports like https://developercommunity.visualstudio.com/content/problem/873214/very-slow-intellisense-in-large-blazor-project.html
    but it still happens

    Additionally I am often facing with situation that debugger ignores my breakpoints in code and shows them only after restarting PC, not VS.
    When I installed preview 3 of vs I spent half day in trying’s to enter into my breakpoints in pages. When I already lost hope to fix it. It fixed itself.

    • Howard Richards 0

      On Twitter Dan did reply to my comment on similar issues – there are updates planned on the editor experience for Visual Studio. It’s probably the weakest part of the Blazor development experience at present I think. Not sure on the timeline but I expect they will be ready for Build next month. Perhaps Dan can comment but I don’t think the VS team is part of his responsibility.

      • Daniel RothMicrosoft employee 0

        Razor tooling improvements are in the works. They won’t be ready for BUILD, but they will start to show up in later Visual Studio previews.

        Igor, please file an issue for the Blazor WebAssembly debugging issue you are seeing if you can figure out a way to reproduce it and we’ll investigate.

  • Cristóvão Morgado 0

    Great update,
    When I try to scafold Identy to customize it I get this message:

    An unhandled exception occurred while processing the request.
    InvalidOperationException: The following sections have been defined but have not been rendered by the page at '/Pages/Shared/_Layout.cshtml': 'Scripts'. To ignore an unrendered section call IgnoreSection("sectionName").

    It’s an easy fix just adding @RenderSection(“Scripts”, required: false) to the _Layout.cshtml
    If I knew how to do a pull request I would helper further :'(

    But it’s an improvement on preview 3 I had a lot of C# alerts and missing things!

    Looking foward to have the release 1 to get my projects with it!

  • Mario Duarte 0

    Hi,

    I am struggling to create a strong-typed client.
    STATUS_ACCESS_VIOLATION

    Do you have a complete example so you can share?

    • Marlon Regenhardt 0

      Hi Mario,
      you can create the sample Blazor application with the following command:
      dotnet new blazorwasm -o WebApplication1
      There you will find a complete Blazor application.

    • Daniel RothMicrosoft employee 0

      Good point! I’ve updated the blog post to call this out. Thanks!

  • Duncan Jack 0

    Looking good, thanks folks.

    With Preview 4, a Blazor Web Assembly App with Individual User Accounts, ASP.NET Core hosted, deployed to an Azure App Service, worked with the .azurewebsites.net default domain and with a custom domain.

    With Preview 5, it still works with the .azurewebsites.net default domain. A custom domain gets a 401 when the app attempts to access the weather forecasts, because the custom domain is not a valid issuer for Identity Server. Setting the IssuerUrl in the call to AddIdentityServer resolves this for the custom domain. However, the default .azurewebsites.net then gets a 401. Fair enough. One or the other works, which makes sense. This may be the expected behavior.

    If this is the expected behavior, is this where you would expect AuthorizationMessageHandler to be used? That would make sense for cases where it’s not an ASP.NET Core hosted app. With an ASP.NET Core hosted app, it may be useful for it to work like Preview 4?

    This is probably the part when you tell me I’ve completely misunderstood something 😉

  • quang nguyen 0

    Hi Daniel,

    With the preview 5, how would you make an api request to an unprotected resources? It see that the token is required for every outgoing request. Thanks!

    • Daniel RothMicrosoft employee 0

      Hi Quang. If you create a project with authentication enabled, the registered HttpClient is setup to attach access tokens to all outbound requests. If you want to make requests to unprotected resources, you can use a different HttpClient instance that isn’t using an authorizing message handler. Instead of configuring a single HttpClient as a service, you’ll need to use the IHttpClientFactory to setup multiple different HttpClient instances: https://docs.microsoft.com/aspnet/core/fundamentals/http-requests.

    • Lochy 0

      Hi Quang,

      I think I managed to figure out the same thing by injecting IHttpClientFactory onto my page.
      Let me know if you need further help on this one.

      • Mason Channer 0

        Hi Lochy,

        Could you post some code on how you setup IHttpClientFactory?

Feedback usabilla icon