Blazor Server support

PREREQUISITES: This feature is available only for projects provisioned on the unified Sitefinity Cloud infrastructure. If your project was provisioned before May 2025, contact the Sitefinity Cloud team to verify eligibility.

Overview

Sitefinity Cloud supports Blazor Server components in ASP.NET Core Renderer applications running on multi-pod Azure Kubernetes Service (AKS) deployments.

NOTE: A multi-pod AKS deployment means your Renderer application is scaled out to run as multiple parallel instances on Azure Kubernetes (for redundancy and load distribution).

In multi-pod AKS deployments, Blazor Server requires shared SignalR state and consistent Data Protection keys across all pods.
Sitefinity Cloud manages the required Azure infrastructure automatically, so your ASP.NET Core Renderer runs reliably once you have configured and updated it as described below.

How it works

When Blazor Server support is enabled for your project, the following Azure infrastructure is provisioned automatically:

ResourcePurpose
Azure SignalR ServiceManaged SignalR hub that routes connections to the correct pod
User-assigned managed identityAuthenticates the Renderer pods to Azure Blob Storage and Azure Key Vault through Microsoft Entra Workload ID
Azure Key Vault encryption keyEncrypts Data Protection keys at rest
Blob containerStores the shared Data Protection keys.xml file

All pods in your Renderer deployment connect to the Azure SignalR Service, which ensures that Blazor circuits maintain their state regardless of which pod handles the reconnection. Data Protection keys are stored centrally in Azure Blob Storage and encrypted with a Key Vault key, so all pods can encrypt and decrypt antiforgery tokens and authentication cookies consistently.

Authentication from the pod to Azure resources happens through Workload ID for Blob Storage and Key Vault access. The CI/CD pipeline injects the Azure SignalR connection string as an environment variable during deployment. The pod obtains an Azure token automatically through a projected Kubernetes service account token.

Request the feature

To request Blazor Server support for your project:

  1. Log a support case.
  2. Describe the desired goal.

The Sitefinity Cloud team will set up the required Azure infrastructure and update your CI/CD pipeline.

You must configure and update your ASP.NET Core Renderer to use the provisioned infrastructure, as described in the following sections.

Configure your ASP.NET Core Renderer

Add NuGet packages

Add the following package references to the .csproj file of your Renderer:

xml
<PackageReference Include="Microsoft.AspNetCore.SignalR.Client" />
<PackageReference Include="Microsoft.Azure.SignalR" />
<PackageReference Include="Azure.Extensions.AspNetCore.DataProtection.Blobs" />
<PackageReference Include="Azure.Extensions.AspNetCore.DataProtection.Keys" />
<PackageReference Include="Azure.Identity" />

If you use Central Package Management, add the versions to your Directory.Packages.props file:

xml
<PackageVersion Include="Microsoft.AspNetCore.SignalR.Client" Version="9.0.14" />
<PackageVersion Include="Microsoft.Azure.SignalR" Version="1.33.0" />
<PackageVersion Include="Azure.Extensions.AspNetCore.DataProtection.Blobs" Version="1.3.4" />
<PackageVersion Include="Azure.Extensions.AspNetCore.DataProtection.Keys" Version="1.2.4" />
<PackageVersion Include="Azure.Identity" Version="1.13.2" />

NOTE: Use the latest stable versions available at the time of implementation. The versions mentioned above are the minimum verified versions.

Configure Data Protection with Workload ID

Add the following code to your Program.cs file before AddServerSideBlazor():

C#
using System;
using Microsoft.AspNetCore.DataProtection;
using Azure.Identity;

// After builder.Services.AddSitefinity() and other service registrations

var dpBlobUri = builder.Configuration["Sitefinity:DataProtection:Azure:BlobUri"];
var dpKeyUri = builder.Configuration["Sitefinity:DataProtection:Azure:KeyUri"];
if (!string.IsNullOrEmpty(dpBlobUri) && !string.IsNullOrEmpty(dpKeyUri))
{
    var credential = new DefaultAzureCredential();
    builder.Services.AddDataProtection()
        .PersistKeysToAzureBlobStorage(new Uri(dpBlobUri), credential)
        .ProtectKeysWithAzureKeyVault(new Uri(dpKeyUri), credential);
}

This code reads the blob URI and Key Vault key URI from environment variables that the CI/CD pipeline injects automatically. It uses DefaultAzureCredential, which automatically picks up Workload ID in AKS.
When the environment variables are not set, as in a local development environment, the Data Protection configuration is skipped.

Configure Azure SignalR Service

Add SignalR and Blazor Services to your Program.cs file. The Content Security Policy (CSP) delegate is required so that the browser can establish WebSocket connections to the SignalR endpoint:

C#
var signalREndpoint = builder.Configuration["Azure:SignalR:Endpoint"] ?? string.Empty;

builder.Services.AddSitefinity(x =>
{
    x.CspOptions.CspDelegate = (csp, context) =>
    {
        if (!string.IsNullOrEmpty(signalREndpoint))
        {
            var wsEndpoint = signalREndpoint.Replace("https://", "wss://");
            csp.ConnectSrc = $"{signalREndpoint} {wsEndpoint} " + csp.ConnectSrc;
        }
    };
});

builder.Services.AddServerSideBlazor();
builder.Services.AddSignalR()
    .AddAzureSignalR(options =>
    {
        options.ServerStickyMode = Microsoft.Azure.SignalR.ServerStickyMode.Required;
        options.ConnectionString = builder.Configuration["Azure:SignalR:ConnectionString"];
    });

NOTE: The ServerStickyMode.Required setting ensures that Blazor circuits are always routed back to the same application server, which is essential for maintaining circuit state.

Map the Blazor hub

At the end of the middleware pipeline, after app.UseSitefinity(), add the following:

C#
app.MapBlazorHub();

Deploy the Renderer

After you update your Renderer code, run the DotNetCoreRenderer.CI.CD pipeline. The pipeline automatically reads the SignalR and Data Protection settings from Key Vault and injects them as environment variables during deployment. No manual configuration of connection strings or keys is required.

Verify the setup

After deployment, you can verify that Blazor Server is working correctly by:

  1. Opening a page that contains Blazor components.
  2. Verifying that the Blazor components render and respond to user interactions.
  3. Checking the browser developer tools network tab for WebSocket connections to the Azure SignalR Service endpoint.

If Blazor components fail intermittently, verify the following:

  • The Azure:SignalR:ConnectionString environment variable is set on the pod.
  • The Data Protection keys.xml file exists in the blob storage container.
  • The ServerStickyMode is set to Required in your code.

Troubleshooting

Blazor components show "The list of component records is not valid"

This error occurs when a SignalR reconnection reaches a different pod that does not have the circuit state. Verify that:

  • Azure SignalR Service is properly configured for your project
  • The Azure:SignalR:ConnectionString environment variable is present in the pod
  • ServerStickyMode is set to Required in your Program.cs code

Antiforgery token validation fails across pods

This issue occurs when Data Protection keys are not shared between pods. Verify that:

  • The Sitefinity:DataProtection:Azure:BlobUri environment variable is set
  • The Sitefinity:DataProtection:Azure:KeyUri environment variable is set
  • The Data Protection keys.xml file exists and is encrypted (contains AzureKeyVaultXmlDecryptor in its content)

If the keys.xml file contains an unencrypted key, it means the pod started before the Key Vault encryption key was provisioned. Contact the Sitefinity Cloud team to resolve this issue.

Pod cannot authenticate to Azure resources

If pod logs show Azure.Identity.CredentialUnavailableException, this indicates that Workload Identity is not configured correctly. Contact the Sitefinity Cloud team to verify the service account annotations and federated identity credentials.