本教程提供了使用 SignalR 和 Blazor 生成实时应用的基本工作经验。 本文适用于已经熟悉 SignalR 并正在寻求了解如何在 SignalR 应用中使用 Blazor 的开发人员。 有关 SignalR 和 Blazor 框架的详细指南,请参阅以下参考文档集和 API 文档:

  • <signalr/introduction>
  • ASP.NET Core
  • .NET API 浏览器
  • 了解如何:

  • 创建 Blazor 应用
  • 添加 SignalR 客户端库
  • 添加 SignalR 集线器
  • 添加 SignalR 服务和 SignalR 中心的终结点
  • 添加用于聊天的 Razor 组件代码
  • 在本教程结束时,你将拥有一个正常运行的聊天应用。

    Visual Studio Visual Studio Code Visual Studio for Mac .NET Core CLI

    创建新项目。

    选择“Blazor WebAssembly 应用”模板。 选择“下一步”。

    在“项目名称”字段中键入 BlazorWebAssemblySignalRApp 。 确认“位置”条目正确无误或为项目提供位置。 选择“ 下一步 ”。

    在“其他信息”对话框中,选中“ASP.NET Core 托管”复选框。

    选择“创建”。

    确认已创建托管 Blazor WebAssembly 应用:在解决方案资源管理器中,确认是否存在 Client 项目和 Server 项目。 如果两个项目不存在,请重新开始并在选择“创建”之前确认已选中“ASP.NET Core 托管”复选框。

    在命令行界面中执行以下命令:

    dotnet new blazorwasm -ho -o BlazorWebAssemblySignalRApp
    

    -ho|--hosted 选项将创建托管的 Blazor WebAssembly解决方案。 有关在 .vscode 文件夹中配置 VS Code 资产的信息,请参阅用于 ASP.NET Core Blazor 的工具中的 Linux 操作系统指南。

    -o|--output 选项为解决方案创建文件夹。 如果已为解决方案创建了文件夹,并在该文件夹中打开了命令行界面,那么请忽略用于创建解决方案的 -o|--output 选项和值。

    在 Visual Studio Code 中打开应用的项目文件夹。

    确认已创建托管 Blazor WebAssembly 应用:确认应用的解决方案文件夹中是否存在 Client 项目和 Server 项目。 如果两个项目不存在,请重新开始并确认在创建解决方案时将命令 -ho 或选项 --hosted 传递给 dotnet new 命令。

    若要在 .vscode 文件夹中配置 Visual Studio Code 资产以便进行调试,请参阅:

  • 用于 ASP.NET Core Blazor 的工具(使用 Linux 操作系统指南,无需考虑平台)
  • 调试 ASP.NET Core Blazor WebAssembly
  • 从“文件”菜单中选择“新建项目”命令,或从“启动窗口”创建新项目。

    在边栏中,选择“Web 和控制台”>“应用”。

    选择“Blazor WebAssembly 应用”模板。 选择“继续”。

    确认已将“身份验证”设置为“无身份验证”。 选中“托管的 ASP.NET Core”复选框。 选择“继续”。

    在“项目名称”字段中,将应用命名为 BlazorWebAssemblySignalRApp。 选择“创建”。

    如果出现信任开发证书的提示,请信任证书并继续操作。 信任证书需要使用用户密码和密钥链密码。

    通过导航到项目文件夹并打开项目的解决方案文件 (.sln) 打开项目。

    确认已创建托管 Blazor WebAssembly 应用:在解决方案资源管理器中,确认是否存在 Client 项目和 Server 项目。 如果两个项目不存在,请重新开始并在选择“创建”之前确认已选中“ASP.NET Core 托管”复选框。

    在命令行界面中执行以下命令:

    dotnet new blazorwasm -ho -o BlazorWebAssemblySignalRApp
    

    -ho|--hosted 选项将创建托管的 Blazor WebAssembly解决方案

    -o|--output 选项为解决方案创建文件夹。 如果已为解决方案创建了文件夹,并在该文件夹中打开了命令行界面,那么请忽略用于创建解决方案的 -o|--output 选项和值。

    确认已创建托管 Blazor WebAssembly 应用:确认应用的解决方案文件夹中是否存在 Client 项目和 Server 项目。 如果两个项目不存在,请重新开始并确认在创建解决方案时将命令 -ho 或选项 --hosted 传递给 dotnet new 命令。

    添加 SignalR 客户端库

    Visual Studio Visual Studio Code Visual Studio for Mac .NET Core CLI

    在“解决方案资源管理器”中,右键单击 BlazorWebAssemblySignalRApp.Client 项目,然后选择“管理 NuGet 包” 。

    在“管理 NuGet 包”对话框中,确认“包源”设置为“nuget.org” 。

    选择“浏览”后,在搜索框中键入“Microsoft.AspNetCore.SignalR.Client”。

    在搜索结果中,选择 Microsoft.AspNetCore.SignalR.Client 包。 将版本设置为与应用共享框架匹配的版本。 选择“安装” 。

    如果出现“预览更改”对话框,则选择“确定”。

    如果出现“许可证接受”对话框,如果你同意许可条款,请选择“我接受”。

    在“集成终端”(工具栏上的“视图”>“终端”)中,执行以下命令 :

    dotnet add Client package Microsoft.AspNetCore.SignalR.Client
    

    若要添加较早版本的包,请提供 --version {VERSION} 选项,其中 {VERSION} 占位符为要添加的包的版本。

    在“解决方案资源管理器”中,右键单击 BlazorWebAssemblySignalRApp.Client 项目,然后选择“管理 NuGet 包” 。

    在“管理 NuGet 包”对话框中,确认“包源”下拉列表设置为 nuget.org

    选择“浏览”后,在搜索框中键入“Microsoft.AspNetCore.SignalR.Client”。

    在搜索结果中,选择 Microsoft.AspNetCore.SignalR.Client 包旁边的复选框。 将版本设置为与应用共享框架匹配的版本。 选择“添加包”。

    出现“许可证接受”对话框时,如果你同意许可条款,请选择“接受”。

    解决方案文件夹的命令行界面中执行以下命令:

    dotnet add Client package Microsoft.AspNetCore.SignalR.Client
    

    若要添加较早版本的包,请提供 --version {VERSION} 选项,其中 {VERSION} 占位符为要添加的包的版本。

    添加 SignalR 集线器

    BlazorWebAssemblySignalRApp.Server 项目中,创建 Hubs(复数)文件夹,并添加以下 ChatHub 类 (Hubs/ChatHub.cs):

    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); public async Task SendMessage(string user, string message) await Clients.All.SendAsync("ReceiveMessage", user, message); public async Task SendMessage(string user, string message) await Clients.All.SendAsync("ReceiveMessage", user, message); public async Task SendMessage(string user, string message) await Clients.All.SendAsync("ReceiveMessage", user, message);

    为 SignalR 中心添加服务和终结点

    BlazorWebAssemblySignalRApp.Server 项目中打开 Program.cs 文件。

    ChatHub 类的命名空间添加到文件顶部:

    using BlazorWebAssemblySignalRApp.Server.Hubs;
    

    添加 SignalR 和响应压缩中间件服务:

    builder.Services.AddSignalR();
    builder.Services.AddResponseCompression(opts =>
          opts.MimeTypes = ResponseCompressionDefaults.MimeTypes.Concat(
             new[] { "application/octet-stream" });
    

    在处理管道的配置顶部,紧接在生成应用的行之后使用响应压缩中间件:

    app.UseResponseCompression();
    

    在控制器终结点和客户端回退之间,为中心添加一个终结点。 紧接行 app.MapControllers(); 之后,添加以下行:

    app.MapHub<ChatHub>("/chathub");
    

    BlazorWebAssemblySignalRApp.Server 项目中打开 Startup.cs 文件。

    ChatHub 类的命名空间添加到文件顶部:

    using BlazorWebAssemblySignalRApp.Server.Hubs;
    

    添加 SignalR 和响应压缩中间件服务:

    services.AddSignalR();
    services.AddResponseCompression(opts =>
          opts.MimeTypes = ResponseCompressionDefaults.MimeTypes.Concat(
             new[] { "application/octet-stream" });
    

    在处理管道的配置顶部使用响应压缩中间件:

    app.UseResponseCompression();
    

    在控制器的终结点和客户端回退之间,紧接在 endpoints.MapControllers(); 行之后为中心添加一个终结点:

    endpoints.MapHub<ChatHub>("/chathub");
    

    添加用于聊天的 Razor 组件代码

    BlazorWebAssemblySignalRApp.Client 项目中打开 Pages/Index.razor 文件。

    将标记替换为以下代码:

    @page "/" @using Microsoft.AspNetCore.SignalR.Client @inject NavigationManager Navigation @implements IAsyncDisposable <PageTitle>Index</PageTitle> <div class="form-group"> <label> User: <input @bind="userInput" /> </label> <div class="form-group"> <label> Message: <input @bind="messageInput" size="50" /> </label> <button @onclick="Send" disabled="@(!IsConnected)">Send</button> <ul id="messagesList"> @foreach (var message in messages) <li>@message</li> @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(Navigation.ToAbsoluteUri("/chathub")) .Build(); hubConnection.On<string, string>("ReceiveMessage", (user, message) => var encodedMsg = $"{user}: {message}"; messages.Add(encodedMsg); StateHasChanged(); await hubConnection.StartAsync(); private async Task Send() if (hubConnection is not null) await hubConnection.SendAsync("SendMessage", userInput, messageInput); public bool IsConnected => hubConnection?.State == HubConnectionState.Connected; public async ValueTask DisposeAsync() if (hubConnection is not null) await hubConnection.DisposeAsync(); @using Microsoft.AspNetCore.SignalR.Client @inject NavigationManager Navigation @implements IAsyncDisposable <PageTitle>Index</PageTitle> <div class="form-group"> <label> User: <input @bind="userInput" /> </label> <div class="form-group"> <label> Message: <input @bind="messageInput" size="50" /> </label> <button @onclick="Send" disabled="@(!IsConnected)">Send</button> <ul id="messagesList"> @foreach (var message in messages) <li>@message</li> @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(Navigation.ToAbsoluteUri("/chathub")) .Build(); hubConnection.On<string, string>("ReceiveMessage", (user, message) => var encodedMsg = $"{user}: {message}"; messages.Add(encodedMsg); StateHasChanged(); await hubConnection.StartAsync(); private async Task Send() if (hubConnection is not null) await hubConnection.SendAsync("SendMessage", userInput, messageInput); public bool IsConnected => hubConnection?.State == HubConnectionState.Connected; public async ValueTask DisposeAsync() if (hubConnection is not null) await hubConnection.DisposeAsync(); @page "/" @using Microsoft.AspNetCore.SignalR.Client @inject NavigationManager NavigationManager @implements IAsyncDisposable <div class="form-group"> <label> User: <input @bind="userInput" /> </label> <div class="form-group"> <label> Message: <input @bind="messageInput" size="50" /> </label> <button @onclick="Send" disabled="@(!IsConnected)">Send</button> <ul id="messagesList"> @foreach (var message in messages) <li>@message</li> @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(); async Task Send() => await hubConnection.SendAsync("SendMessage", userInput, messageInput); public bool IsConnected => hubConnection.State == HubConnectionState.Connected; public async ValueTask DisposeAsync() if (hubConnection is not null) await hubConnection.DisposeAsync(); @page "/" @using Microsoft.AspNetCore.SignalR.Client @inject NavigationManager NavigationManager @implements IDisposable <div class="form-group"> <label> User: <input @bind="userInput" /> </label> <div class="form-group"> <label> Message: <input @bind="messageInput" size="50" /> </label> <button @onclick="Send" disabled="@(!IsConnected)">Send</button> <ul id="messagesList"> @foreach (var message in messages) <li>@message</li> @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(); async Task Send() => await hubConnection.SendAsync("SendMessage", userInput, messageInput); public bool IsConnected => hubConnection.State == HubConnectionState.Connected; public void Dispose() _ = hubConnection?.DisposeAsync();

    在“解决方案资源管理器”中,选择 BlazorWebAssemblySignalRApp.Server 项目。 按 F5 来运行应用并进行调试,或者按 Ctrl+F5 (Windows)/+F5 (macOS) 来运行应用但不调试。

    执行托管的 Blazor WebAssembly 应用时,请从解决方案的 Server 项目运行应用。

    Google Chrome 或 Microsoft Edge 必须是调试会话的选定浏览器。

    如果应用无法在浏览器中启动:

  • 在 .NET 控制台中,确认解决方案是否从“Server”项目运行。
  • 使用浏览器的重新加载按钮刷新浏览器。
  • 有关在 .vscode 文件夹中配置 VS Code 资产的信息,请参阅用于 ASP.NET Core Blazor 的工具中的 Linux 操作系统指南。

    F5 来运行应用并进行调试,或者按 Ctrl+F5 (Windows)/+F5 (macOS) 来运行应用但不调试。

    执行托管的 Blazor WebAssembly 应用时,请从解决方案的 Server 项目运行应用。

    Google Chrome 或 Microsoft Edge 必须是调试会话的选定浏览器。

    如果应用无法在浏览器中启动:

  • 在 .NET 控制台中,确认解决方案是否从“Server”项目运行。
  • 使用浏览器的重新加载按钮刷新浏览器。
  • 在“解决方案”边栏中,选择 BlazorWebAssemblySignalRApp.Server 项目。 按 + 来运行应用并进行调试,或者按 ++ 来运行应用但不调试。

    执行托管的 Blazor WebAssembly 应用时,请从解决方案的 Server 项目运行应用。

    Google Chrome 或 Microsoft Edge 必须是调试会话的选定浏览器。

    如果应用无法在浏览器中启动:

  • 在 .NET 控制台中,确认解决方案是否从“Server”项目运行。
  • 使用浏览器的重新加载按钮刷新浏览器。
  • 选择任一浏览器,输入名称和消息,然后选择按钮发送消息。 两个页面上立即显示名称和消息:

    引文:Star Trek VI: The Undiscovered Country ©1991 Paramount

    创建 Blazor Server 应用

    按照所选工具的指南进行操作:

    Visual Studio Visual Studio Code Visual Studio for Mac .NET Core CLI

    创建新项目。

    选择“Blazor Server 应用”模板。 选择“下一步”。

    在“项目名称”字段中键入 BlazorServerSignalRApp。 确认“位置”条目正确无误或为项目提供位置。 选择“下一步”。

    选择“创建”。

    在命令行界面中执行以下命令:

    dotnet new blazorserver -o BlazorServerSignalRApp
    

    -o|--output 选项为项目创建文件夹。 如果已为项目创建了文件夹,并在该文件夹中打开了命令行界面,那么请忽略用于创建项目的 -o|--output 选项和值。

    在 Visual Studio Code 中打开应用的项目文件夹。

    当显示添加资产以生成和调试应用的对话框时,选择“是”。 Visual Studio Code 会自动将生成的 launch.jsontasks.json 文件添加到 .vscode 文件夹中。 有关在 .vscode 文件夹中配置 VS Code 资产的信息(包括如何手动将文件添加到解决方案),请参阅用于 ASP.NET Core Blazor 的工具中的 Linux 操作系统指南。

    安装最新版本的 Visual Studio for Mac。 当安装程序请求要安装的工作负载时,请选择“.NET”。

    从“文件”菜单中选择“新建项目”命令,或从“启动窗口”创建新项目。

    在边栏中,选择“Web 和控制台”>“应用”。

    选择“Blazor Server 应用”模板。 选择“继续”。

    确认已将“身份验证”设置为“无身份验证”。 选择“继续”。

    在“项目名称”字段中,将应用命名为 BlazorServerSignalRApp。 选择“创建”。

    如果出现信任开发证书的提示,请信任证书并继续操作。 信任证书需要使用用户密码和密钥链密码。

    通过导航到项目文件夹并打开项目的解决方案文件 (.sln) 打开项目。

    在命令行界面中执行以下命令:

    dotnet new blazorserver -o BlazorServerSignalRApp
    

    -o|--output 选项为项目创建文件夹。 如果已为项目创建了文件夹,并在该文件夹中打开了命令行界面,那么请忽略用于创建项目的 -o|--output 选项和值。

    添加 SignalR 客户端库

    Visual Studio Visual Studio Code Visual Studio for Mac .NET Core CLI

    在“解决方案资源管理器”中,右键单击 BlazorServerSignalRApp 项目,然后选择“管理 NuGet 包” 。

    在“管理 NuGet 包”对话框中,确认“包源”设置为“nuget.org” 。

    选择“浏览”后,在搜索框中键入“Microsoft.AspNetCore.SignalR.Client”。

    在搜索结果中,选择 Microsoft.AspNetCore.SignalR.Client 包。 将版本设置为与应用共享框架匹配的版本。 选择“安装” 。

    如果出现“预览更改”对话框,则选择“确定”。

    如果出现“许可证接受”对话框,如果你同意许可条款,请选择“我接受”。

    在“集成终端”(工具栏上的“视图”>“终端”)中,执行以下命令 :

    dotnet add package Microsoft.AspNetCore.SignalR.Client
    

    若要添加较早版本的包,请提供 --version {VERSION} 选项,其中 {VERSION} 占位符为要添加的包的版本。

    在“解决方案资源管理器”中,右键单击 BlazorServerSignalRApp 项目,然后选择“管理 NuGet 包” 。

    在“管理 NuGet 包”对话框中,确认“包源”下拉列表设置为 nuget.org

    选择“浏览”后,在搜索框中键入“Microsoft.AspNetCore.SignalR.Client”。

    在搜索结果中,选择 Microsoft.AspNetCore.SignalR.Client 包旁边的复选框。 将版本设置为与应用共享框架匹配的版本。 选择“添加包”。

    出现“许可证接受”对话框时,如果你同意许可条款,请选择“接受”。

    在项目文件夹的命令行界面中执行以下命令:

    dotnet add package Microsoft.AspNetCore.SignalR.Client
    

    若要添加较早版本的包,请提供 --version {VERSION} 选项,其中 {VERSION} 占位符为要添加的包的版本。

    添加 System.Text.Encodings.Web 包

    本部分仅适用于 ASP.NET Core 版本 3.x 的应用。

    由于在 ASP.NET Core 3.x 应用中使用 System.Text.Json 5.x 时出现包解析问题,项目需要 System.Text.Encodings.Web 的包引用。 基础问题已在修补程序版本中解决并向后移植到 ASP.NET Core 5.0。 有关详细信息,请参阅 System.Text.Json 定义无依赖项的 netcoreapp3.0(dotnet/运行时 #45560)

    若要将 System.Text.Encodings.Web 添加到项目,请按照所选工具的指南进行操作:

    Visual Studio Visual Studio Code Visual Studio for Mac .NET Core CLI

    在“解决方案资源管理器”中,右键单击 BlazorServerSignalRApp 项目,然后选择“管理 NuGet 包” 。

    在“管理 NuGet 包”对话框中,确认“包源”设置为“nuget.org” 。

    选择“浏览”后,在搜索框中键入“System.Text.Encodings.Web”。

    在搜索结果中,选择 System.Text.Encodings.Web 包。 选择与正在使用的共享框架相匹配的包版本。 选择“安装” 。

    如果出现“预览更改”对话框,则选择“确定”。

    如果出现“许可证接受”对话框,如果你同意许可条款,请选择“我接受”。

    在“集成终端”(工具栏上的“视图”>“终端”)中,执行以下命令:

    dotnet add package System.Text.Encodings.Web
    

    若要添加较早版本的包,请提供 --version {VERSION} 选项,其中 {VERSION} 占位符为要添加的包的版本。

    在“解决方案资源管理器”中,右键单击 BlazorServerSignalRApp 项目,然后选择“管理 NuGet 包” 。

    在“管理 NuGet 包”对话框中,确认“包源”下拉列表设置为 nuget.org

    选择“浏览”后,在搜索框中键入“System.Text.Encodings.Web”。

    在搜索结果中,选中 System.Text.Encodings.Web 包旁边的复选框,选择与正在使用的共享框架相匹配的包的正确版本,然后选择“添加包”。

    出现“许可证接受”对话框时,如果你同意许可条款,请选择“接受”。

    在项目文件夹的命令行界面中执行以下命令:

    dotnet add package System.Text.Encodings.Web
    

    若要添加较早版本的包,请提供 --version {VERSION} 选项,其中 {VERSION} 占位符为要添加的包的版本。

    添加 SignalR 集线器

    创建 Hubs(复数)文件夹,并添加以下 ChatHub 类 (Hubs/ChatHub.cs):

    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); public async Task SendMessage(string user, string message) await Clients.All.SendAsync("ReceiveMessage", user, message); public async Task SendMessage(string user, string message) await Clients.All.SendAsync("ReceiveMessage", user, message); public async Task SendMessage(string user, string message) await Clients.All.SendAsync("ReceiveMessage", user, message);

    为 SignalR 中心添加服务和终结点

    打开 Program.cs 文件。

    Microsoft.AspNetCore.ResponseCompressionChatHub 类的命名空间添加到文件的顶部:

    using Microsoft.AspNetCore.ResponseCompression;
    using BlazorServerSignalRApp.Server.Hubs;
    

    添加响应压缩中间件服务:

    builder.Services.AddResponseCompression(opts =>
       opts.MimeTypes = ResponseCompressionDefaults.MimeTypes.Concat(
             new[] { "application/octet-stream" });
    

    在处理管道的配置顶部使用响应压缩中间件:

    app.UseResponseCompression();
    

    在映射 Blazor 中心的终结点和客户端回退之间,紧接在 app.MapBlazorHub(); 行之后为中心添加一个终结点:

    app.MapHub<ChatHub>("/chathub");
    

    打开 Startup.cs 文件。

    Microsoft.AspNetCore.ResponseCompressionChatHub 类的命名空间添加到文件的顶部:

    using Microsoft.AspNetCore.ResponseCompression;
    using BlazorServerSignalRApp.Server.Hubs;
    

    添加响应压缩中间件服务:

    services.AddResponseCompression(opts =>
       opts.MimeTypes = ResponseCompressionDefaults.MimeTypes.Concat(
             new[] { "application/octet-stream" });
    

    在处理管道的配置顶部使用响应压缩中间件:

    app.UseResponseCompression();
    

    在映射 Blazor 中心的终结点和客户端回退之间,紧接在 endpoints.MapBlazorHub(); 行之后为中心添加一个终结点:

    endpoints.MapHub<ChatHub>("/chathub");
    

    添加用于聊天的 Razor 组件代码

    打开 Pages/Index.razor 文件。

    将标记替换为以下代码:

    @page "/" @using Microsoft.AspNetCore.SignalR.Client @inject NavigationManager Navigation @implements IAsyncDisposable <PageTitle>Index</PageTitle> <div class="form-group"> <label> User: <input @bind="userInput" /> </label> <div class="form-group"> <label> Message: <input @bind="messageInput" size="50" /> </label> <button @onclick="Send" disabled="@(!IsConnected)">Send</button> <ul id="messagesList"> @foreach (var message in messages) <li>@message</li> @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(Navigation.ToAbsoluteUri("/chathub")) .Build(); hubConnection.On<string, string>("ReceiveMessage", (user, message) => var encodedMsg = $"{user}: {message}"; messages.Add(encodedMsg); InvokeAsync(StateHasChanged); await hubConnection.StartAsync(); private async Task Send() if (hubConnection is not null) await hubConnection.SendAsync("SendMessage", userInput, messageInput); public bool IsConnected => hubConnection?.State == HubConnectionState.Connected; public async ValueTask DisposeAsync() if (hubConnection is not null) await hubConnection.DisposeAsync(); @using Microsoft.AspNetCore.SignalR.Client @inject NavigationManager Navigation @implements IAsyncDisposable <PageTitle>Index</PageTitle> <div class="form-group"> <label> User: <input @bind="userInput" /> </label> <div class="form-group"> <label> Message: <input @bind="messageInput" size="50" /> </label> <button @onclick="Send" disabled="@(!IsConnected)">Send</button> <ul id="messagesList"> @foreach (var message in messages) <li>@message</li> @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(Navigation.ToAbsoluteUri("/chathub")) .Build(); hubConnection.On<string, string>("ReceiveMessage", (user, message) => var encodedMsg = $"{user}: {message}"; messages.Add(encodedMsg); InvokeAsync(StateHasChanged); await hubConnection.StartAsync(); private async Task Send() if (hubConnection is not null) await hubConnection.SendAsync("SendMessage", userInput, messageInput); public bool IsConnected => hubConnection?.State == HubConnectionState.Connected; public async ValueTask DisposeAsync() if (hubConnection is not null) await hubConnection.DisposeAsync(); @page "/" @using Microsoft.AspNetCore.SignalR.Client @inject NavigationManager NavigationManager @implements IAsyncDisposable <div class="form-group"> <label> User: <input @bind="userInput" /> </label> <div class="form-group"> <label> Message: <input @bind="messageInput" size="50" /> </label> <button @onclick="Send" disabled="@(!IsConnected)">Send</button> <ul id="messagesList"> @foreach (var message in messages) <li>@message</li> @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); InvokeAsync(StateHasChanged); await hubConnection.StartAsync(); async Task Send() => await hubConnection.SendAsync("SendMessage", userInput, messageInput); public bool IsConnected => hubConnection.State == HubConnectionState.Connected; public async ValueTask DisposeAsync() if (hubConnection is not null) await hubConnection.DisposeAsync(); @page "/" @using Microsoft.AspNetCore.SignalR.Client @inject NavigationManager NavigationManager @implements IAsyncDisposable <div class="form-group"> <label> User: <input @bind="userInput" /> </label> <div class="form-group"> <label> Message: <input @bind="messageInput" size="50" /> </label> <button @onclick="Send" disabled="@(!IsConnected)">Send</button> <ul id="messagesList"> @foreach (var message in messages) <li>@message</li> @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); InvokeAsync(StateHasChanged); await hubConnection.StartAsync(); async Task Send() => await hubConnection.SendAsync("SendMessage", userInput, messageInput); public bool IsConnected => hubConnection.State == HubConnectionState.Connected; public async ValueTask DisposeAsync() await hubConnection?.DisposeAsync();

    选择任一浏览器,输入名称和消息,然后选择按钮发送消息。 两个页面上立即显示名称和消息:

    引文:Star Trek VI: The Undiscovered Country ©1991 Paramount

    在本教程中,你了解了如何执行以下操作:

  • 创建 Blazor 应用
  • 添加 SignalR 客户端库
  • 添加 SignalR 集线器
  • 添加 SignalR 服务和 SignalR 中心的终结点
  • 添加用于聊天的 Razor 组件代码
  • 有关 SignalR 和 Blazor 框架的详细指南,请参阅以下参考文档集:

    ASP.NET Core 概述SignalRASP.NET CoreBlazor

  • 具有 Identity 服务器、WebSocket 和服务器发送事件的持有者令牌身份验证
  • 在托管的 Blazor WebAssembly 应用中保护 SignalR 中心
  • ASP.NET Core SignalR 概述
  • SignalR 用于身份验证的跨源协商
  • SignalR 配置
  • 调试 ASP.NET Core Blazor WebAssembly
  • ASP.NET Core 的威胁缓解指南Blazor Server
  • Blazor 示例 GitHub 存储库 (dotnet/blazor-samples)
  •