ASP.NET Core Blazor hosting model configuration

By Daniel Roth and Luke Latham

This article covers hosting model configuration.

Blazor WebAssembly

Environment

When running an app locally, the environment defaults to Development. When the app is published, the environment defaults to Production.

A hosted Blazor WebAssembly app picks up the environment from the server via a middleware that communicates the environment to the browser by adding the blazor-environment header. The value of the header is the environment. The hosted Blazor app and the server app share the same environment. For more information, including how to configure the environment, see Use multiple environments in ASP.NET Core.

For a standalone app running locally, the development server adds the blazor-environment header to specify the Development environment. To specify the environment for other hosting environments, add the blazor-environment header.

In the following example for IIS, add the custom header to the published web.config file. The web.config file is located in the bin/Release/{TARGET FRAMEWORK}/publish folder:

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
  <system.webServer>

    ...

    <httpProtocol>
      <customHeaders>
        <add name="blazor-environment" value="Staging" />
      </customHeaders>
    </httpProtocol>
  </system.webServer>
</configuration>

Note

To use a custom web.config file for IIS that isn't overwritten when the app is published to the publish folder, see Host and deploy ASP.NET Core Blazor WebAssembly.

Obtain the app's environment in a component by injecting IWebAssemblyHostEnvironment and reading the Environment property:

@page "/"
@using Microsoft.AspNetCore.Components.WebAssembly.Hosting
@inject IWebAssemblyHostEnvironment HostEnvironment

<h1>Environment example</h1>

<p>Environment: @HostEnvironment.Environment</p>

During startup, the WebAssemblyHostBuilder exposes the IWebAssemblyHostEnvironment through the HostEnvironment property, which enables developers to have environment-specific logic in their code:

if (builder.HostEnvironment.Environment == "Custom")
{
    ...
};

The following convenience extension methods permit checking the current environment for Development, Production, Staging, and custom environment names:

  • IsDevelopment()
  • IsProduction()
  • IsStaging()
  • IsEnvironment("{ENVIRONMENT NAME}")
if (builder.HostEnvironment.IsStaging())
{
    ...
};

if (builder.HostEnvironment.IsEnvironment("Custom"))
{
    ...
};

The IWebAssemblyHostEnvironment.BaseAddress property can be used during startup when the NavigationManager service isn't available.

Configuration

Blazor WebAssembly loads configuration from:

Warning

Configuration in a Blazor WebAssembly app is visible to users. Don't store app secrets or credentials in configuration.

For more information on configuration providers, see Configuration in ASP.NET Core.

App settings configuration

wwwroot/appsettings.json:

{
  "message": "Hello from config!"
}

Inject an IConfiguration instance into a component to access the configuration data:

@page "/"
@using Microsoft.Extensions.Configuration
@inject IConfiguration Configuration

<h1>Configuration example</h1>

<p>Message: @Configuration["message"]</p>

Provider configuration

The following example uses a MemoryConfigurationSource to supply additional configuration:

Program.Main:

using Microsoft.Extensions.Configuration.Memory;

...

var vehicleData = new Dictionary<string, string>()
{
    { "color", "blue" },
    { "type", "car" },
    { "wheels:count", "3" },
    { "wheels:brand", "Blazin" },
    { "wheels:brand:type", "rally" },
    { "wheels:year", "2008" },
};

var memoryConfig = new MemoryConfigurationSource { InitialData = vehicleData };

...

builder.Configuration.Add(memoryConfig);

Inject an IConfiguration instance into a component to access the configuration data:

@page "/"
@using Microsoft.Extensions.Configuration
@inject IConfiguration Configuration

<h1>Configuration example</h1>

<h2>Wheels</h2>

<ul>
    <li>Count: @Configuration["wheels:count"]</li>
    <li>Brand: @Configuration["wheels:brand"]</li>
    <li>Type: @Configuration["wheels:brand:type"]</li>
    <li>Year: @Configuration["wheels:year"]</li>
</ul>

@code {
    var wheelsSection = Configuration.GetSection("wheels");
    
    ...
}

To read other configuration files from the wwwroot folder into configuration, use an HttpClient to obtain the file's content. When using this approach, the existing HttpClient service registration can use the local client created to read the file, as the following example shows:

wwwroot/cars.json:

{
    "size": "tiny"
}

Program.Main:

using Microsoft.Extensions.Configuration;

...

var client = new HttpClient()
{
    BaseAddress = new Uri(builder.HostEnvironment.BaseAddress)
};

builder.Services.AddTransient(sp => client);

using var response = await client.GetAsync("cars.json");
using var stream = await response.Content.ReadAsStreamAsync();

builder.Configuration.AddJsonStream(stream);

Authentication configuration

wwwroot/appsettings.json:

{
  "Local": {
    "Authority": "{AUTHORITY}",
    "ClientId": "{CLIENT ID}"
  }
}

Program.Main:

builder.Services.AddOidcAuthentication(options =>
    builder.Configuration.Bind("Local", options.ProviderOptions);

Logging configuration

wwwroot/appsettings.json:

{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft": "Warning",
      "Microsoft.Hosting.Lifetime": "Information"
    }
  }
}

Program.Main:

builder.Logging.AddConfiguration(
    builder.Configuration.GetSection("Logging"));

Host builder configuration

Program.Main:

var hostname = builder.Configuration["HostName"];

Cached configuration

Configuration files are cached for offline use. With Progressive Web Applications (PWAs), you can only update configuration files when creating a new deployment. Editing configuration files between deployments has no effect because:

  • Users have cached versions of the files that they continue to use.
  • The PWA's service-worker.js and service-worker-assets.js files must be rebuilt on compilation, which signal to the app on the user's next online visit that the app has been redeployed.

For more information on how background updates are handled by PWAs, see Build Progressive Web Applications with ASP.NET Core Blazor WebAssembly.

Logging

For information on Blazor WebAssembly logging support, see Logging in .NET Core and ASP.NET Core.

Blazor Server

Reflect the connection state in the UI

When the client detects that the connection has been lost, a default UI is displayed to the user while the client attempts to reconnect. If reconnection fails, the user is provided the option to retry.

To customize the UI, define an element with an id of components-reconnect-modal in the <body> of the _Host.cshtml Razor page:

<div id="components-reconnect-modal">
    ...
</div>

The following table describes the CSS classes applied to the components-reconnect-modal element.

CSS class Indicates…
components-reconnect-show A lost connection. The client is attempting to reconnect. Show the modal.
components-reconnect-hide An active connection is re-established to the server. Hide the modal.
components-reconnect-failed Reconnection failed, probably due to a network failure. To attempt reconnection, call window.Blazor.reconnect().
components-reconnect-rejected Reconnection rejected. The server was reached but refused the connection, and the user's state on the server is lost. To reload the app, call location.reload(). This connection state may result when:
  • A crash in the server-side circuit occurs.
  • The client is disconnected long enough for the server to drop the user's state. Instances of the components that the user is interacting with are disposed.
  • The server is restarted, or the app's worker process is recycled.

Render mode

Blazor Server apps are set up by default to prerender the UI on the server before the client connection to the server is established. This is set up in the _Host.cshtml Razor page:

<body>
    <app>
      <component type="typeof(App)" render-mode="ServerPrerendered" />
    </app>

    <script src="_framework/blazor.server.js"></script>
</body>

RenderMode configures whether the component:

  • Is prerendered into the page.
  • Is rendered as static HTML on the page or if it includes the necessary information to bootstrap a Blazor app from the user agent.
RenderMode Description
ServerPrerendered Renders the component into static HTML and includes a marker for a Blazor Server app. When the user-agent starts, this marker is used to bootstrap a Blazor app.
Server Renders a marker for a Blazor Server app. Output from the component isn't included. When the user-agent starts, this marker is used to bootstrap a Blazor app.
Static Renders the component into static HTML.

Rendering server components from a static HTML page isn't supported.

Configure the SignalR client for Blazor Server apps

Sometimes, you need to configure the SignalR client used by Blazor Server apps. For example, you might want to configure logging on the SignalR client to diagnose a connection issue.

To configure the SignalR client in the Pages/_Host.cshtml file:

  • Add an autostart="false" attribute to the <script> tag for the blazor.server.js script.
  • Call Blazor.start and pass in a configuration object that specifies the SignalR builder.
<script src="_framework/blazor.server.js" autostart="false"></script>
<script>
  Blazor.start({
    configureSignalR: function (builder) {
      builder.configureLogging("information"); // LogLevel.Information
    }
  });
</script>

Logging

For information on Blazor Server logging support, see Logging in .NET Core and ASP.NET Core.