--- title: ASP.NET Core Blazor SignalR guidance author: guardrex description: Learn how to configure and manage Blazor SignalR connections. monikerRange: '>= aspnetcore-3.1' ms.author: riande ms.custom: mvc ms.date: 03/12/2021 no-loc: [Home, Privacy, Kestrel, appsettings.json, "ASP.NET Core Identity", cookie, Cookie, Blazor, "Blazor Server", "Blazor WebAssembly", "Identity", "Let's Encrypt", Razor, SignalR] uid: blazor/fundamentals/signalr zone_pivot_groups: blazor-hosting-models --- # ASP.NET Core Blazor SignalR guidance ::: zone pivot="webassembly" This article explains how to configure and manage SignalR connections in Blazor apps. For general guidance on ASP.NET Core SignalR configuration, see the topics in the area of the documentation. To configure SignalR [added to a hosted Blazor WebAssembly solution](xref:tutorials/signalr-blazor), see . ## SignalR cross-origin negotiation for authentication To configure SignalR's underlying client to send credentials, such as cookies or HTTP authentication headers: * Use to set on cross-origin [`fetch`](https://developer.mozilla.org/docs/Web/API/Fetch_API/Using_Fetch) requests. `IncludeRequestCredentialsMessageHandler.cs`: ```csharp using System.Net.Http; using System.Threading; using System.Threading.Tasks; using Microsoft.AspNetCore.Components.WebAssembly.Http; public class IncludeRequestCredentialsMessageHandler : DelegatingHandler { protected override Task SendAsync( HttpRequestMessage request, CancellationToken cancellationToken) { request.SetBrowserRequestCredentials(BrowserRequestCredentials.Include); return base.SendAsync(request, cancellationToken); } } ``` * Where a hub connection is built, assign the to the option: ```csharp HubConnectionBuilder hubConnecton; ... hubConnecton = new HubConnectionBuilder() .WithUrl(new Uri(NavigationManager.ToAbsoluteUri("/chathub")), options => { options.HttpMessageHandlerFactory = innerHandler => new IncludeRequestCredentialsMessageHandler { InnerHandler = innerHandler }; }).Build(); ``` The preceding example configures the hub connection URL to the absolute URI address at `/chathub`, which is the URL used in the [SignalR with Blazor tutorial](xref:tutorials/signalr-blazor) in the `Index` component (`Pages/Index.razor`). The URI can also be set via a string, for example `https://signalr.example.com`, or via [configuration](xref:blazor/fundamentals/configuration). For more information, see . ::: moniker range=">= aspnetcore-5.0" ## Render mode If a Blazor WebAssembly app that uses SignalR is configured to prerender on the server, prerendering occurs before the client connection to the server is established. For more information, see the following articles: * * ::: moniker-end ## Additional resources * * ::: zone-end ::: zone pivot="server" This article explains how to configure and manage SignalR connections in Blazor apps. For general guidance on ASP.NET Core SignalR configuration, see the topics in the area of the documentation. To configure SignalR [added to a hosted Blazor WebAssembly solution](xref:tutorials/signalr-blazor), see . ## Circuit handler options Configure the Blazor Server circuit with the shown in the following table. | Option | Default | Description | | --- | --- | --- | | | `false` | Send detailed exception messages to JavaScript when an unhandled exception occurs on the circuit or when a .NET method invocation through JS interop results in an exception. | | | 100 | Maximum number of disconnected circuits that the server holds in memory at a time. | | | 3 minutes | Maximum amount of time a disconnected circuit is held in memory before being torn down. | | | 1 minute | Maximum amount of time the server waits before timing out an asynchronous JavaScript function invocation. | | | 10 | Maximum number of unacknowledged render batches the server keeps in memory per circuit at a given time to support robust reconnection. After reaching the limit, the server stops producing new render batches until one or more batches are acknowledged by the client. | Configure the options in `Startup.ConfigureServices` with an options delegate to . The following example assigns the default option values shown in the preceding table. Confirm that `Startup.cs` uses the namespace (`using System;`). `Startup.ConfigureServices`: ```csharp services.AddServerSideBlazor(options => { options.DetailedErrors = false; options.DisconnectedCircuitMaxRetained = 100; options.DisconnectedCircuitRetentionPeriod = TimeSpan.FromMinutes(3); options.JSInteropDefaultCallTimeout = TimeSpan.FromMinutes(1); options.MaxBufferedUnacknowledgedRenderBatches = 10; }); ``` To configure the , use with . For option descriptions, see . The following example assigns the default option values. Confirm that `Startup.cs` uses the namespace (`using System;`). `Startup.ConfigureServices`: ```csharp services.AddServerSideBlazor() .AddHubOptions(options => { options.ClientTimeoutInterval = TimeSpan.FromSeconds(30); options.EnableDetailedErrors = false; options.HandshakeTimeout = TimeSpan.FromSeconds(15); options.KeepAliveInterval = TimeSpan.FromSeconds(15); options.MaximumParallelInvocationsPerClient = 1; options.MaximumReceiveMessageSize = 32 * 1024; options.StreamBufferCapacity = 10; }); ``` ## 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 `` of the `_Host.cshtml` Razor page. `Pages/_Host.cshtml`: ```cshtml
...
``` Add the following CSS styles to the site's stylesheet. `wwwroot/css/site.css`: ```css #components-reconnect-modal { display: none; } #components-reconnect-modal.components-reconnect-show { display: block; } ``` The following table describes the CSS classes applied to the `components-reconnect-modal` element by the Blazor framework. | 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()` in JavaScript. | | `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()` in JavaScript. 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 user's components are disposed.
  • The server is restarted, or the app's worker process is recycled.
| ## Render mode By default, Blazor Server apps prerender the UI on the server before the client connection to the server is established. For more information, see . ## Initialize the Blazor circuit Configure the manual start of a Blazor Server app's [SignalR circuit](xref:blazor/hosting-models#circuits) in the `Pages/_Host.cshtml` file: * Add an `autostart="false"` attribute to the ` ``` ### Chain to the `Promise` that results from a manual start To perform additional tasks, such as JS interop initialization, use [`then`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise/then) to chain to the [`Promise`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise) that results from a manual Blazor app start. `Pages/_Host.cshtml`: ```cshtml ... ``` ### Configure SignalR client logging On the client builder, pass in the `configureSignalR` configuration object that calls `configureLogging` with the log level. `Pages/_Host.cshtml`: ```cshtml ... ``` In the preceding example, `information` is equivalent to a log level of . ### Modify the reconnection handler The reconnection handler's circuit connection events can be modified for custom behaviors, such as: * To notify the user if the connection is dropped. * To perform logging (from the client) when a circuit is connected. To modify the connection events, register callbacks for the following connection changes: * Dropped connections use `onConnectionDown`. * Established/re-established connections use `onConnectionUp`. **Both `onConnectionDown` and `onConnectionUp` must be specified.** `Pages/_Host.cshtml`: ```cshtml ... ``` ### Adjust the reconnection retry count and interval To adjust the reconnection retry count and interval, set the number of retries (`maxRetries`) and period in milliseconds permitted for each retry attempt (`retryIntervalMilliseconds`). `Pages/_Host.cshtml`: ```cshtml ... ``` ## Hide or replace the reconnection display To hide the reconnection display, set the reconnection handler's `_reconnectionDisplay` to an empty object (`{}` or `new Object()`). `Pages/_Host.cshtml`: ```cshtml ... ``` To replace the reconnection display, set `_reconnectionDisplay` in the preceding example to the element for display: ```javascript Blazor.defaultReconnectionHandler._reconnectionDisplay = document.getElementById("{ELEMENT ID}"); ``` The placeholder `{ELEMENT ID}` is the ID of the HTML element to display. ::: moniker range=">= aspnetcore-5.0" Customize the delay before the reconnection display appears by setting the `transition-delay` property in the site's CSS for the modal element. The following example sets the transition delay from 500 ms (default) to 1,000 ms (1 second). `wwwroot/css/site.css`: ```css #components-reconnect-modal { transition: visibility 0s linear 1000ms; } ``` ## Disconnect the Blazor circuit from the client By default, a Blazor circuit is disconnected when the [`unload` page event](https://developer.mozilla.org/docs/Web/API/Window/unload_event) is triggered. To disconnect the circuit for other scenarios on the client, invoke `Blazor.disconnect` in the appropriate event handler. In the following example, the circuit is disconnected when the page is hidden ([`pagehide` event](https://developer.mozilla.org/docs/Web/API/Window/pagehide_event)): ```javascript window.addEventListener('pagehide', () => { Blazor.disconnect(); }); ``` ::: moniker-end ## Blazor Server circuit handler Blazor Server allows code to define a *circuit handler*, which allows running code on changes to the state of a user's circuit. A circuit handler is implemented by deriving from and registering the class in the app's service container. The following example of a circuit handler tracks open SignalR connections. `TrackingCircuitHandler.cs`: ::: moniker range=">= aspnetcore-5.0" [!code-csharp[](~/blazor/common/samples/5.x/BlazorSample_Server/TrackingCircuitHandler.cs)] ::: moniker-end ::: moniker range="< aspnetcore-5.0" [!code-csharp[](~/blazor/common/samples/3.x/BlazorSample_Server/TrackingCircuitHandler.cs)] ::: moniker-end Circuit handlers are registered using DI. Scoped instances are created per instance of a circuit. Using the `TrackingCircuitHandler` in the preceding example, a singleton service is created because the state of all circuits must be tracked. `Startup.cs`: ```csharp public void ConfigureServices(IServiceCollection services) { ... services.AddSingleton(); } ``` If a custom circuit handler's methods throw an unhandled exception, the exception is fatal to the Blazor Server circuit. To tolerate exceptions in a handler's code or called methods, wrap the code in one or more [`try-catch`](/dotnet/csharp/language-reference/keywords/try-catch) statements with error handling and logging. When a circuit ends because a user has disconnected and the framework is cleaning up the circuit state, the framework disposes of the circuit's DI scope. Disposing the scope disposes any circuit-scoped DI services that implement . If any DI service throws an unhandled exception during disposal, the framework logs the exception. ## Azure SignalR Service We recommend using the [Azure SignalR Service](xref:signalr/scale#azure-signalr-service) for Blazor Server apps hosted in Microsoft Azure. The service allows for scaling up a Blazor Server app to a large number of concurrent SignalR connections. In addition, the SignalR Service's global reach and high-performance data centers significantly aid in reducing latency due to geography. For prerendering support with the Azure SignalR Service, configure the app to use *sticky sessions*. For more information, see . ## Additional resources * * * * [Blazor Server reconnection events and component lifecycle events](xref:blazor/components/lifecycle#blazor-server-reconnection-events) ::: zone-end