Use ASP.NET Core SignalR with Blazor
This tutorial teaches the basics of building a real-time app using SignalR with Blazor. You learn how to:
- Create a Blazor project
- Add the SignalR client library
- Add a SignalR hub
- Add SignalR services and an endpoint for the SignalR hub
- Add Razor component code for chat
At the end of this tutorial, you'll have a working chat app.
View or download sample code (how to download)
Prerequisites
- Visual Studio 2019 16.8 or later with the ASP.NET and web development workload
- .NET 5.0 SDK or later
- Visual Studio 2019 16.6 or later with the ASP.NET and web development workload
- .NET Core 3.1 SDK or later
Create a hosted Blazor WebAssembly app
Follow the guidance for your choice of tooling:
Note
Visual Studio 16.8 or later and .NET Core SDK 5.0.0 or later are required.
Note
Visual Studio 16.6 or later and .NET Core SDK 3.1.300 or later are required.
Create a new project.
Select Blazor App and select Next.
Type
BlazorWebAssemblySignalRApp
in the Project name field. Confirm the Location entry is correct or provide a location for the project. Select Create.Choose the Blazor WebAssembly App template.
Under Advanced, select the ASP.NET Core hosted check box.
Select Create.
Add the SignalR client library
In Solution Explorer, right-click the
BlazorWebAssemblySignalRApp.Client
project and select Manage NuGet Packages.In the Manage NuGet Packages dialog, confirm that the Package source is set to
nuget.org
.With Browse selected, type
Microsoft.AspNetCore.SignalR.Client
in the search box.In the search results, select the
Microsoft.AspNetCore.SignalR.Client
package. Set the version to match the shared framework of the app. Select Install.If the Preview Changes dialog appears, select OK.
If the License Acceptance dialog appears, select I Accept if you agree with the license terms.
Add the System.Text.Encodings.Web package
This section only applies to apps for ASP.NET Core version 3.x.
Due to a package resolution issue when using System.Text.Json
5.x in an ASP.NET Core 3.x app, the BlazorWebAssemblySignalRApp.Server
project requires a package reference for System.Text.Encodings.Web
. The underlying issue will be resolved in a future patch release of .NET 5. For more information, see System.Text.Json defines netcoreapp3.0 with no dependencies (dotnet/runtime #45560).
To add System.Text.Encodings.Web
to the BlazorWebAssemblySignalRApp.Server
project of the ASP.NET Core 3.1 hosted Blazor solution, follow the guidance for your choice of tooling:
In Solution Explorer, right-click the
BlazorWebAssemblySignalRApp.Server
project and select Manage NuGet Packages.In the Manage NuGet Packages dialog, confirm that the Package source is set to
nuget.org
.With Browse selected, type
System.Text.Encodings.Web
in the search box.In the search results, select the
System.Text.Encodings.Web
package. Select the version of the package that matches the shared framework in use. Select Install.If the Preview Changes dialog appears, select OK.
If the License Acceptance dialog appears, select I Accept if you agree with the license terms.
Add a SignalR hub
In the BlazorWebAssemblySignalRApp.Server
project, create a Hubs
(plural) folder and add the following ChatHub
class (Hubs/ChatHub.cs
):
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.SignalR;
namespace BlazorWebAssemblySignalRApp.Server.Hubs
{
public class ChatHub : Hub
{
public async Task SendMessage(string user, string message)
{
await Clients.All.SendAsync("ReceiveMessage", user, message);
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.SignalR;
namespace BlazorWebAssemblySignalRApp.Server.Hubs
{
public class ChatHub : Hub
{
public async Task SendMessage(string user, string message)
{
await Clients.All.SendAsync("ReceiveMessage", user, message);
}
}
}
Add services and an endpoint for the SignalR hub
In the
BlazorWebAssemblySignalRApp.Server
project, open theStartup.cs
file.Add the namespace for the
ChatHub
class to the top of the file:using BlazorWebAssemblySignalRApp.Server.Hubs;
Add SignalR and Response Compression Middleware services to
Startup.ConfigureServices
:public void ConfigureServices(IServiceCollection services) { services.AddSignalR(); services.AddControllersWithViews(); services.AddRazorPages(); services.AddResponseCompression(opts => { opts.MimeTypes = ResponseCompressionDefaults.MimeTypes.Concat( new[] { "application/octet-stream" }); }); }
In
Startup.Configure
:- Use Response Compression Middleware at the top of the processing pipeline's configuration.
- Between the endpoints for controllers and the client-side fallback, add an endpoint for the hub.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { app.UseResponseCompression(); if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); app.UseWebAssemblyDebugging(); } else { app.UseExceptionHandler("/Error"); app.UseHsts(); } app.UseHttpsRedirection(); app.UseBlazorFrameworkFiles(); app.UseStaticFiles(); app.UseRouting(); app.UseEndpoints(endpoints => { endpoints.MapRazorPages(); endpoints.MapControllers(); endpoints.MapHub<ChatHub>("/chathub"); endpoints.MapFallbackToFile("index.html"); }); }
Add SignalR and Response Compression Middleware services to
Startup.ConfigureServices
:public void ConfigureServices(IServiceCollection services) { services.AddSignalR(); services.AddControllersWithViews(); services.AddResponseCompression(opts => { opts.MimeTypes = ResponseCompressionDefaults.MimeTypes.Concat( new[] { "application/octet-stream" }); }); }
In
Startup.Configure
:- Use Response Compression Middleware at the top of the processing pipeline's configuration.
- Between the endpoints for controllers and the client-side fallback, add an endpoint for the hub.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { app.UseResponseCompression(); if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); app.UseWebAssemblyDebugging(); } else { app.UseExceptionHandler("/Error"); app.UseHsts(); } app.UseHttpsRedirection(); app.UseBlazorFrameworkFiles(); app.UseStaticFiles(); app.UseRouting(); app.UseEndpoints(endpoints => { endpoints.MapControllers(); endpoints.MapHub<ChatHub>("/chathub"); endpoints.MapFallbackToFile("index.html"); }); }
Add Razor component code for chat
- In the
BlazorWebAssemblySignalRApp.Client
project, open thePages/Index.razor
file.
Replace the markup with the following code:
@page "/" @using Microsoft.AspNetCore.SignalR.Client @inject NavigationManager NavigationManager @implements IAsyncDisposable <div class="form-group"> <label> User: <input @bind="userInput" /> </label> </div> <div class="form-group"> <label> Message: <input @bind="messageInput" size="50" /> </label> </div> <button @onclick="Send" disabled="@(!IsConnected)">Send</button> <hr> <ul id="messagesList"> @foreach (var message in messages) { <li>@message</li> } </ul> @code { private HubConnection hubConnection; private List<string> messages = new List<string>(); private string userInput; private 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}: {message}"; messages.Add(encodedMsg); StateHasChanged(); }); await hubConnection.StartAsync(); } Task Send() => hubConnection.SendAsync("SendMessage", userInput, messageInput); public bool IsConnected => hubConnection.State == HubConnectionState.Connected; public async ValueTask DisposeAsync() { await hubConnection.DisposeAsync(); } }
Replace the markup with the following code:
@page "/" @using Microsoft.AspNetCore.SignalR.Client @inject NavigationManager NavigationManager @implements IDisposable <div class="form-group"> <label> User: <input @bind="userInput" /> </label> </div> <div class="form-group"> <label> Message: <input @bind="messageInput" size="50" /> </label> </div> <button @onclick="Send" disabled="@(!IsConnected)">Send</button> <hr> <ul id="messagesList"> @foreach (var message in messages) { <li>@message</li> } </ul> @code { private HubConnection hubConnection; private List<string> messages = new List<string>(); private string userInput; private 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}: {message}"; messages.Add(encodedMsg); StateHasChanged(); }); await hubConnection.StartAsync(); } Task Send() => hubConnection.SendAsync("SendMessage", userInput, messageInput); public bool IsConnected => hubConnection.State == HubConnectionState.Connected; public void Dispose() { _ = hubConnection.DisposeAsync(); } }
Run the app
Follow the guidance for your tooling:
In Solution Explorer, select the
BlazorWebAssemblySignalRApp.Server
project. Press F5 to run the app with debugging or Ctrl+F5 to run the app without debugging.Copy the URL from the address bar, open another browser instance or tab, and paste the URL in the address bar.
Choose either browser, enter a name and message, and select the button to send the message. The name and message are displayed on both pages instantly:
Quotes: Star Trek VI: The Undiscovered Country ©1991 Paramount
Create a Blazor Server app
Follow the guidance for your choice of tooling:
Note
Visual Studio 16.8 or later and .NET Core SDK 5.0.0 or later are required.
Note
Visual Studio 16.6 or later and .NET Core SDK 3.1.300 or later are required.
Create a new project.
Select Blazor App and select Next.
Type
BlazorServerSignalRApp
in the Project name field. Confirm the Location entry is correct or provide a location for the project. Select Create.Choose the Blazor Server App template.
Select Create.
Add the SignalR client library
In Solution Explorer, right-click the
BlazorServerSignalRApp
project and select Manage NuGet Packages.In the Manage NuGet Packages dialog, confirm that the Package source is set to
nuget.org
.With Browse selected, type
Microsoft.AspNetCore.SignalR.Client
in the search box.In the search results, select the
Microsoft.AspNetCore.SignalR.Client
package. Set the version to match the shared framework of the app. Select Install.If the Preview Changes dialog appears, select OK.
If the License Acceptance dialog appears, select I Accept if you agree with the license terms.
Add the System.Text.Encodings.Web package
This section only applies to apps for ASP.NET Core version 3.x.
Due to a package resolution issue when using System.Text.Json
5.x in an ASP.NET Core 3.x app, the project requires a package reference for System.Text.Encodings.Web
. The underlying issue will be resolved in a future patch release of .NET 5. For more information, see System.Text.Json defines netcoreapp3.0 with no dependencies (dotnet/runtime #45560).
To add System.Text.Encodings.Web
to the project, follow the guidance for your choice of tooling:
In Solution Explorer, right-click the
BlazorServerSignalRApp
project and select Manage NuGet Packages.In the Manage NuGet Packages dialog, confirm that the Package source is set to
nuget.org
.With Browse selected, type
System.Text.Encodings.Web
in the search box.In the search results, select the
System.Text.Encodings.Web
package. Select the version of the package that matches the shared framework in use. Select Install.If the Preview Changes dialog appears, select OK.
If the License Acceptance dialog appears, select I Accept if you agree with the license terms.
Add a SignalR hub
Create a Hubs
(plural) folder and add the following ChatHub
class (Hubs/ChatHub.cs
):
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.SignalR;
namespace BlazorServerSignalRApp.Server.Hubs
{
public class ChatHub : Hub
{
public async Task SendMessage(string user, string message)
{
await Clients.All.SendAsync("ReceiveMessage", user, message);
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.SignalR;
namespace BlazorServerSignalRApp.Server.Hubs
{
public class ChatHub : Hub
{
public async Task SendMessage(string user, string message)
{
await Clients.All.SendAsync("ReceiveMessage", user, message);
}
}
}
Add services and an endpoint for the SignalR hub
Open the
Startup.cs
file.Add the namespaces for Microsoft.AspNetCore.ResponseCompression and the
ChatHub
class to the top of the file:using Microsoft.AspNetCore.ResponseCompression; using BlazorServerSignalRApp.Server.Hubs;
Add Response Compression Middleware services to
Startup.ConfigureServices
:public void ConfigureServices(IServiceCollection services) { services.AddRazorPages(); services.AddServerSideBlazor(); services.AddSingleton<WeatherForecastService>(); services.AddResponseCompression(opts => { opts.MimeTypes = ResponseCompressionDefaults.MimeTypes.Concat( new[] { "application/octet-stream" }); }); }
In
Startup.Configure
:- Use Response Compression Middleware at the top of the processing pipeline's configuration.
- Between the endpoints for mapping the Blazor hub and the client-side fallback, add an endpoint for the hub.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { app.UseResponseCompression(); if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } else { app.UseExceptionHandler("/Error"); app.UseHsts(); } app.UseHttpsRedirection(); app.UseStaticFiles(); app.UseRouting(); app.UseEndpoints(endpoints => { endpoints.MapBlazorHub(); endpoints.MapHub<ChatHub>("/chathub"); endpoints.MapFallbackToPage("/_Host"); }); }
Add Response Compression Middleware services to
Startup.ConfigureServices
:public void ConfigureServices(IServiceCollection services) { services.AddRazorPages(); services.AddServerSideBlazor(); services.AddSingleton<WeatherForecastService>(); services.AddResponseCompression(opts => { opts.MimeTypes = ResponseCompressionDefaults.MimeTypes.Concat( new[] { "application/octet-stream" }); }); }
In
Startup.Configure
:- Use Response Compression Middleware at the top of the processing pipeline's configuration.
- Between the endpoints for mapping the Blazor hub and the client-side fallback, add an endpoint for the hub.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { app.UseResponseCompression(); if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } else { app.UseExceptionHandler("/Error"); app.UseHsts(); } app.UseHttpsRedirection(); app.UseStaticFiles(); app.UseRouting(); app.UseEndpoints(endpoints => { endpoints.MapBlazorHub(); endpoints.MapHub<ChatHub>("/chathub"); endpoints.MapFallbackToPage("/_Host"); }); }
Add Razor component code for chat
- Open the
Pages/Index.razor
file.
Replace the markup with the following code:
@page "/" @using Microsoft.AspNetCore.SignalR.Client @inject NavigationManager NavigationManager @implements IAsyncDisposable <div class="form-group"> <label> User: <input @bind="userInput" /> </label> </div> <div class="form-group"> <label> Message: <input @bind="messageInput" size="50" /> </label> </div> <button @onclick="Send" disabled="@(!IsConnected)">Send</button> <hr> <ul id="messagesList"> @foreach (var message in messages) { <li>@message</li> } </ul> @code { private HubConnection hubConnection; private List<string> messages = new List<string>(); private string userInput; private 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}: {message}"; messages.Add(encodedMsg); StateHasChanged(); }); await hubConnection.StartAsync(); } Task Send() => hubConnection.SendAsync("SendMessage", userInput, messageInput); public bool IsConnected => hubConnection.State == HubConnectionState.Connected; public async ValueTask DisposeAsync() { await hubConnection.DisposeAsync(); } }
Replace the markup with the following code:
@page "/" @using Microsoft.AspNetCore.SignalR.Client @inject NavigationManager NavigationManager @implements IAsyncDisposable <div class="form-group"> <label> User: <input @bind="userInput" /> </label> </div> <div class="form-group"> <label> Message: <input @bind="messageInput" size="50" /> </label> </div> <button @onclick="Send" disabled="@(!IsConnected)">Send</button> <hr> <ul id="messagesList"> @foreach (var message in messages) { <li>@message</li> } </ul> @code { private HubConnection hubConnection; private List<string> messages = new List<string>(); private string userInput; private 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}: {message}"; messages.Add(encodedMsg); StateHasChanged(); }); await hubConnection.StartAsync(); } Task Send() => hubConnection.SendAsync("SendMessage", userInput, messageInput); public bool IsConnected => hubConnection.State == HubConnectionState.Connected; public async ValueTask DisposeAsync() { await hubConnection.DisposeAsync(); } }
Run the app
Follow the guidance for your tooling:
Press F5 to run the app with debugging or Ctrl+F5 to run the app without debugging.
Copy the URL from the address bar, open another browser instance or tab, and paste the URL in the address bar.
Choose either browser, enter a name and message, and select the button to send the message. The name and message are displayed on both pages instantly:
Quotes: Star Trek VI: The Undiscovered Country ©1991 Paramount
Next steps
In this tutorial, you learned how to:
- Create a Blazor project
- Add the SignalR client library
- Add a SignalR hub
- Add SignalR services and an endpoint for the SignalR hub
- Add Razor component code for chat
To learn more about building Blazor apps, see the Blazor documentation:
Introduction to ASP.NET Core Blazor Bearer token authentication with Identity Server, WebSockets, and Server-Sent Events