注意
這不是這篇文章的最新版本。 如需目前的版本,請參閱 本文的 .NET 9 版本。
警告
不再支援此版本的 ASP.NET Core。 如需詳細資訊,請參閱 .NET 和 .NET Core 支持原則。 如需目前的版本,請參閱 本文的 .NET 9 版本。
本教學課程提供建置使用 SignalR 搭配 Blazor 即時應用程式的基本工作體驗。 本文適用於已經熟悉 SignalR 並想要了解如何在 SignalR 應用程式中使用 Blazor 的開發人員。 如需 SignalR 和 Blazor 架構的詳細指引,請參閱下列參考文件集和 API 文件:
了解如何:
- 建立 Blazor 應用程式
- 新增 SignalR 用戶端程式庫
- 新增 SignalR 中樞
- 新增 SignalR 服務和 SignalR 中樞的端點
- 新增聊天的 Razor 元件程式碼
在本教學課程結束時,您將有一個可運作的聊天應用程式。
必要條件
具有 ASP.NET 和 Web 開發工作負載的 Visual Studio (最新版本)
範例應用程式
本教學課程不需要下載教學課程的範例聊天應用程式。 範例應用程式是遵循本教學課程步驟所產生的最終的正常運作應用程式。 當您開啟範例存放庫時,請開啟您打算設為目標的版本資料夾,並尋找名為 BlazorSignalRApp
的範例。
本教學課程不需要下載教學課程的範例聊天應用程式。 範例應用程式是遵循本教學課程步驟所產生的最終的正常運作應用程式。 當您開啟範例存放庫時,請開啟您打算設為目標的版本資料夾,並尋找名為 BlazorWebAssemblySignalRApp
的範例。
檢視或下載範例程式碼 \(英文\) (如何下載)
建立 Blazor Web App
請遵循您所選擇工具的指引:
注意
需要 Visual Studio 2022 或更新版本和 .NET Core SDK 8.0.0 或更新版本。
在 Visual Studio 中:
- 從 [開始] 視窗選取 [建立新專案] ,或從功能表欄選取 [檔案][新]>>[專案]。
- 在 建立新專案 對話方塊中,從專案範本清單中選取 Blazor Web App 。 選取下一步按鈕。
- 在 [設定新專案] 對話方塊中,在 [專案名稱]
BlazorSignalRApp
欄位中,將專案命名為 ,包括符合大小寫。 使用此確切的專案名稱很重要,以確保命名空間符合您從教學課程複製到您要建置的應用程式的程式碼。 - 請確認應用程式的 位置 適合。 繼續選取 [將解決方案與專案放置在同一個目錄] 核取方塊。 選取下一步按鈕。
- 在 [其他資訊] 對話方塊中,使用下列設定:
- 架構:確認已選取 最新的架構。 如果 Visual Studio 的 架構 下拉式清單不包含最新的可用 .NET Framework,更新 Visual Studio 並重新啟動教學課程。
- 驗證類型:無
- 針對 HTTPS 進行設定:已選取
- 互動式轉譯模式:WebAssembly
- 互動位置:每頁/元件
- 包含範例頁面:已選取
- 不要使用最上層陳述式:未選取
- 選取 建立。
本文中的指導會針對 SignalR 用戶端使用 WebAssembly 元件,因為使用 SignalR 從相同應用程式中的互動式伺服器元件連線到中樞並無意義,這是因為可能會導致伺服器連接埠耗盡。
新增 SignalR 用戶端程式庫
在 [方案總管] 中,以滑鼠右鍵按一下 BlazorSignalRApp.Client
專案,然後選取 [管理 NuGet 套件]。
在 [管理 NuGet 套件] 對話方塊中,確認 [套件來源] 已設定為 nuget.org
。
選取 [瀏覽] 後,在搜尋方塊中輸入 Microsoft.AspNetCore.SignalR.Client
。
在搜尋結果中,選取 Microsoft.AspNetCore.SignalR.Client
套件的最新版本。 選取 [安裝]。
如果出現 [預覽變更] 對話方塊,請選取 [確定]。
在出現 [接受授權] 對話方塊時,如果您同意授權條款,請選取 [我接受]。
新增 SignalR 中樞
在伺服器 BlazorSignalRApp
專案中,建立 Hubs
(複數) 資料夾,並新增下列 ChatHub
類別 (Hubs/ChatHub.cs
):
using Microsoft.AspNetCore.SignalR;
namespace BlazorSignalRApp.Hubs;
public class ChatHub : Hub
{
public async Task SendMessage(string user, string message)
{
await Clients.All.SendAsync("ReceiveMessage", user, message);
}
}
新增 SignalR 中樞的服務和端點
開啟伺服器 Program
專案的 BlazorSignalRApp
檔案。
將 Microsoft.AspNetCore.ResponseCompression 和 ChatHub
類別的命名空間新增至檔案頂端:
using Microsoft.AspNetCore.ResponseCompression;
using BlazorSignalRApp.Hubs;
新增 SignalR 和回應壓縮中介軟體服務:
builder.Services.AddSignalR();
builder.Services.AddResponseCompression(opts =>
{
opts.MimeTypes = ResponseCompressionDefaults.MimeTypes.Concat(
[ "application/octet-stream" ]);
});
使用處理管線設定頂端的回應壓縮中介軟體: 將下列程式碼行緊接在建置應用程式的行後面 (var app = builder.Build();
):
app.UseResponseCompression();
在執行應用程式的行之前,新增中樞的端點 (app.Run();
):
app.MapHub<ChatHub>("/chathub");
新增聊天的 Razor 元件程式碼
將下列 Pages/Chat.razor
檔案新增至 BlazorSignalRApp.Client
專案:
@page "/chat"
@rendermode InteractiveWebAssembly
@using Microsoft.AspNetCore.SignalR.Client
@inject NavigationManager Navigation
@implements IAsyncDisposable
<PageTitle>Chat</PageTitle>
<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 = [];
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();
}
}
}
將專案新增至 NavMenu
元件,以觸達聊天頁面。 在 Components/Layout/NavMenu.razor
元件 <div>
區塊之後的 Weather
中,新增下列 <div>
區塊:
<div class="nav-item px-3">
<NavLink class="nav-link" href="chat">
<span class="bi bi-list-nested-nav-menu" aria-hidden="true"></span> Chat
</NavLink>
</div>
注意
使用Development
時,請在 環境中停用回應壓縮中介軟體。 如需詳細資訊,請參閱 ASP.NET Core BlazorSignalR 指引。
執行應用程式
請遵循工具的指引:
在 [方案總管] 中選取伺服器 BlazorSignalRApp
專案後,按 F5 來執行應用程式並進行除錯,或按 Ctrl+F5 來執行應用程式而不進行除錯。
從網址列複製 URL,開啟另一個瀏覽器執行個體或索引標籤,然後將 URL 貼入網址列。
選擇任一個瀏覽器,輸入名稱和訊息,然後選取傳送訊息的按鈕。 名稱和訊息會立即顯示在兩個頁面上:
引述:星艦迷航記 VI:邁入未來 ©1991 Paramount
託管 Blazor WebAssembly 體驗
建立應用程式
請遵循您選擇的工具指引來建立託管的 Blazor WebAssembly 應用程式:
注意
需要 Visual Studio 2022 或更新版本和 .NET Core SDK 6.0.0 或更新版本。
建立新專案。
選擇 Blazor WebAssembly 應用程式範本。 選取 [下一步] 。
在 [專案名稱]BlazorWebAssemblySignalRApp
欄位中輸入 。 確認 [位置] 項目正確或提供專案的位置。 選取 [下一步] 。
在 [其他資訊] 對話方塊中,選取 [已託管 ASP.NET Core] 核取方塊。
選取 建立。
確認已建立託管的 Blazor WebAssembly 應用程式:在 [方案總管] 中,確認 Client 專案和 Server 專案是否存在。 如果兩個專案不存在,請重新開始並確認選取 [已託管 ASP.NET Core] 核取方塊,然後再選取 [建立]。
新增 SignalR 用戶端程式庫
在 [方案總管] 中,以滑鼠右鍵按一下 BlazorWebAssemblySignalRApp.Client
專案,然後選取 [管理 NuGet 套件]。
在 [管理 NuGet 套件] 對話方塊中,確認 [套件來源] 已設定為 nuget.org
。
選取 [瀏覽] 後,在搜尋方塊中輸入 Microsoft.AspNetCore.SignalR.Client
。
在搜尋結果中,選取 Microsoft.AspNetCore.SignalR.Client
套件。 設定版本以符合應用程式的共用架構。 選取 [安裝]。
如果出現 [預覽變更] 對話方塊,請選取 [確定]。
在出現 [接受授權] 對話方塊時,如果您同意授權條款,請選取 [我接受]。
新增 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);
}
}
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.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.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);
}
}
}
新增 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>
<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(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 Navigation
@implements IAsyncDisposable
<PageTitle>Index</PageTitle>
<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(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>
<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();
}
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>
<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();
}
async Task Send() =>
await hubConnection.SendAsync("SendMessage", userInput, messageInput);
public bool IsConnected =>
hubConnection.State == HubConnectionState.Connected;
public void Dispose()
{
_ = hubConnection?.DisposeAsync();
}
}
注意
使用Development
時,請在 環境中停用回應壓縮中介軟體。 如需詳細資訊,請參閱 ASP.NET Core BlazorSignalR 指引。
執行應用程式
請遵循工具的指引:
在 [方案總管] 中,選取 BlazorWebAssemblySignalRApp.Server
專案。 按 F5 執行應用程式以偵錯,或按 Ctrl+F5 執行應用程式而不偵錯。
重要
執行裝載的 Blazor WebAssembly 應用程式時,請從解決方案的Server專案執行應用程式。
Google Chrome 或 Microsoft Edge 必須是偵錯工作階段的選取瀏覽器。
如果應用程式無法在瀏覽器中啟動:
- 在 .NET 主控台中,確認解決方案正在從「Server」專案執行。
- 使用瀏覽器的重新載入按鈕來重新整理瀏覽器。
從網址列複製 URL,開啟另一個瀏覽器執行個體或索引標籤,然後將 URL 貼入網址列。
選擇任一個瀏覽器,輸入名稱和訊息,然後選取傳送訊息的按鈕。 名稱和訊息會立即顯示在兩個頁面上:
引述:星艦迷航記 VI:邁入未來 ©1991 Paramount
下一步
在本教學課程中,您已了解如何:
- 建立 Blazor 應用程式
- 新增 SignalR 用戶端程式庫
- 新增 SignalR 中樞
- 新增 SignalR 服務和 SignalR 中樞的端點
- 新增聊天的 Razor 元件程式碼
如需 SignalR 和 Blazor 架構的詳細指引,請參閱下列參考文件集: