教學課程:建置 Blazor Server 聊天應用程式
本教學課程說明如何建置和修改 Blazor Server 應用程式。 您將學習如何:
- 使用 Blazor Server 應用程式範本建立簡單的聊天室。
- 運用 Razor 元件。
- 使用 Razor 元件中的事件處理和資料繫結。
- 快速部署至 Visual Studio 中的 Azure App Service。
- 從本機 SignalR 遷移至 Azure SignalR Service。
重要
原始 連接字串 只會針對示範目的出現在本文中。
連接字串 包含應用程式存取 Azure SignalR Service 所需的授權資訊。 連接字串內的存取金鑰類似於服務的根密碼。 在生產環境中,請一律保護您的存取金鑰。 使用 Azure 金鑰保存庫,使用 Microsoft Entra 識別元安全地管理和輪替密鑰,以及使用 Microsoft Entra 識別符授權存取權,並保護您的 連接字串。
避免將存取金鑰散發給其他使用者、寫入程式碼,或將其以純文字儲存在他人可以存取的位置。 如果您認為金鑰可能已遭盜用,請輪替金鑰。
準備開始了嗎?
必要條件
- 安裝 .NET Core 3.0 SDK (版本 >= 3.0.100)
- 安裝 Visual Studio 2019 (版本 >= 16.3)
在 Blazor Server 應用程式中建置本機聊天室
從 Visual Studio 2019 16.2.0 版開始,Azure SignalR Service 會內建於 Web 應用程式發佈流程中,協助您輕鬆管理 Web 應用程式和 SignalR Service 之間的相依性。 您可以同時在不進行任何程式碼變更的情況下工作:
- 在本機 SignalR 執行個體,在本機開發環境中。
- 在 Azure App Service 的 Azure SignalR Service 中。
建立 Blazor 聊天應用程式:
在 Visual Studio 中,選擇 [建立新專案]。
選取 [Blazor 應用程式]。
命名應用程式,然後選擇資料夾。
選取 Blazor Server 應用程式範本。
注意
請確定您已安裝 .NET Core SDK 3.0 +,以便 Visual Studio 能夠正確辨識目標 Framework。
您也可以在 .NET CLI 中執行
dotnet new
命令來建立專案:dotnet new blazorserver -o BlazorChat
新增名為
BlazorChatSampleHub.cs
的新 C# 檔案,並建立衍生自聊天應用程式Hub
類別的新類別BlazorChatSampleHub
。 如需建立中樞的詳細資訊,請參閱建立和使用中樞。using System; using System.Threading.Tasks; using Microsoft.AspNetCore.SignalR; namespace BlazorChat { public class BlazorChatSampleHub : Hub { public const string HubUrl = "/chat"; public async Task Broadcast(string username, string message) { await Clients.All.SendAsync("Broadcast", username, message); } public override Task OnConnectedAsync() { Console.WriteLine($"{Context.ConnectionId} connected"); return base.OnConnectedAsync(); } public override async Task OnDisconnectedAsync(Exception e) { Console.WriteLine($"Disconnected {e?.Message} {Context.ConnectionId}"); await base.OnDisconnectedAsync(e); } } }
在
Startup.Configure()
方法內新增中樞的端點。app.UseEndpoints(endpoints => { endpoints.MapBlazorHub(); endpoints.MapFallbackToPage("/_Host"); endpoints.MapHub<BlazorChatSampleHub>(BlazorChatSampleHub.HubUrl); });
安裝
Microsoft.AspNetCore.SignalR.Client
套件以使用 SignalR 用戶端。dotnet add package Microsoft.AspNetCore.SignalR.Client --version 3.1.7
若要實作 SignalR 用戶端,請在
Pages
資料夾下建立名為ChatRoom.razor
的新 Razor 元件。 使用 ChatRoom.razor 檔案,或執行下列步驟:新增
@page
指示詞和 using 陳述式。 使用@inject
指示詞插入NavigationManager
服務。@page "/chatroom" @inject NavigationManager navigationManager @using Microsoft.AspNetCore.SignalR.Client;
在
@code
區段中,將下列成員新增至新的 SignalR 用戶端,以用於傳送和接收訊息。@code { // flag to indicate chat status private bool _isChatting = false; // name of the user who will be chatting private string _username; // on-screen message private string _message; // new message input private string _newMessage; // list of messages in chat private List<Message> _messages = new List<Message>(); private string _hubUrl; private HubConnection _hubConnection; public async Task Chat() { // check username is valid if (string.IsNullOrWhiteSpace(_username)) { _message = "Please enter a name"; return; }; try { // Start chatting and force refresh UI. _isChatting = true; await Task.Delay(1); // remove old messages if any _messages.Clear(); // Create the chat client string baseUrl = navigationManager.BaseUri; _hubUrl = baseUrl.TrimEnd('/') + BlazorChatSampleHub.HubUrl; _hubConnection = new HubConnectionBuilder() .WithUrl(_hubUrl) .Build(); _hubConnection.On<string, string>("Broadcast", BroadcastMessage); await _hubConnection.StartAsync(); await SendAsync($"[Notice] {_username} joined chat room."); } catch (Exception e) { _message = $"ERROR: Failed to start chat client: {e.Message}"; _isChatting = false; } } private void BroadcastMessage(string name, string message) { bool isMine = name.Equals(_username, StringComparison.OrdinalIgnoreCase); _messages.Add(new Message(name, message, isMine)); // Inform blazor the UI needs updating InvokeAsync(StateHasChanged); } private async Task DisconnectAsync() { if (_isChatting) { await SendAsync($"[Notice] {_username} left chat room."); await _hubConnection.StopAsync(); await _hubConnection.DisposeAsync(); _hubConnection = null; _isChatting = false; } } private async Task SendAsync(string message) { if (_isChatting && !string.IsNullOrWhiteSpace(message)) { await _hubConnection.SendAsync("Broadcast", _username, message); _newMessage = string.Empty; } } private class Message { public Message(string username, string body, bool mine) { Username = username; Body = body; Mine = mine; } public string Username { get; set; } public string Body { get; set; } public bool Mine { get; set; } public bool IsNotice => Body.StartsWith("[Notice]"); public string CSS => Mine ? "sent" : "received"; } }
在
@code
區段之前新增 UI 標記,以與 SignalR 用戶端互動。<h1>Blazor SignalR Chat Sample</h1> <hr /> @if (!_isChatting) { <p> Enter your name to start chatting: </p> <input type="text" maxlength="32" @bind="@_username" /> <button type="button" @onclick="@Chat"><span class="oi oi-chat" aria-hidden="true"></span> Chat!</button> // Error messages @if (_message != null) { <div class="invalid-feedback">@_message</div> <small id="emailHelp" class="form-text text-muted">@_message</small> } } else { // banner to show current user <div class="alert alert-secondary mt-4" role="alert"> <span class="oi oi-person mr-2" aria-hidden="true"></span> <span>You are connected as <b>@_username</b></span> <button class="btn btn-sm btn-warning ml-md-auto" @onclick="@DisconnectAsync">Disconnect</button> </div> // display messages <div id="scrollbox"> @foreach (var item in _messages) { @if (item.IsNotice) { <div class="alert alert-info">@item.Body</div> } else { <div class="@item.CSS"> <div class="user">@item.Username</div> <div class="msg">@item.Body</div> </div> } } <hr /> <textarea class="input-lg" placeholder="enter your comment" @bind="@_newMessage"></textarea> <button class="btn btn-default" @onclick="@(() => SendAsync(_newMessage))">Send</button> </div> }
更新
NavMenu.razor
元件以插入新的NavLink
元件,以連結至NavMenuCssClass
下方的聊天室。<li class="nav-item px-3"> <NavLink class="nav-link" href="chatroom"> <span class="oi oi-chat" aria-hidden="true"></span> Chat room </NavLink> </li>
將幾個 CSS 類別新增至
site.css
檔案,以在聊天頁面中設定 UI 元素的樣式。/* improved for chat text box */ textarea { border: 1px dashed #888; border-radius: 5px; width: 80%; overflow: auto; background: #f7f7f7 } /* improved for speech bubbles */ .received, .sent { position: relative; font-family: arial; font-size: 1.1em; border-radius: 10px; padding: 20px; margin-bottom: 20px; } .received:after, .sent:after { content: ''; border: 20px solid transparent; position: absolute; margin-top: -30px; } .sent { background: #03a9f4; color: #fff; margin-left: 10%; top: 50%; text-align: right; } .received { background: #4CAF50; color: #fff; margin-left: 10px; margin-right: 10%; } .sent:after { border-left-color: #03a9f4; border-right: 0; right: -20px; } .received:after { border-right-color: #4CAF50; border-left: 0; left: -20px; } /* div within bubble for name */ .user { font-size: 0.8em; font-weight: bold; color: #000; } .msg { /*display: inline;*/ }
按 F5 以執行應用程式。 現在,您可以開始聊天:
發佈至 Azure
將 Blazor 應用程式部署至 Azure App Service 時,建議您使用 Azure SignalR Service。 Azure SignalR Service 允許將 Blazor Server 應用程式擴增為大量的並行 SignalR 連線。 此外,SignalR Service 的全球性和高效能資料中心可大幅縮短因地理位置而造成的延遲。
重要
在 Blazor Server 應用程式中,UI 狀態會保存於伺服器端,這表示需要黏性伺服器工作階段才能保留狀態。 如果只有單一應用程式伺服器,則依設計可確保黏性工作階段。 不過,如果有多個使用中的應用程式伺服器,用戶端交涉和連線可能會重新導向至不同的伺服器,這可能會導致 Blazor 應用程式中的 UI 狀態管理不一致。 因此,建議您啟用黏性伺服器工作階段,如下列 appsettings.json 所示:
"Azure:SignalR:ServerStickyMode": "Required"
以滑鼠右鍵按一下專案,然後移至 [發佈]。 使用下列設定:
- 目標:Azure
- 特定目標:支援所有類型的 Azure App Service。
- App Service:建立或選取 App Service 執行個體。
新增 Azure SignalR Service 相依項目。
建立發行設定檔之後,您會看到在 [服務相依性] 底下新增 Azure SignalR Service 的建議訊息。 選取 [設定] 以建立新的服務,或在面板中選取現有的 Azure SignalR Service。
服務相依性會執行下列活動,讓您的應用程式在 Azure 上執行下列作業時,自動切換至 Azure SignalR Service:
- 更新
HostingStartupAssembly
以使用 Azure SignalR Service。 - 新增 Azure SignalR Service NuGet 套件參考。
- 更新設定檔屬性以儲存相依性設定。
- 根據您的選擇設定秘密存放區。
- 在 appsettings.json 中新增組態,讓您的應用程式以 Azure SignalR Service 為目標。
- 更新
發行應用程式。
現在您的應用程式已準備好發佈。 發佈程序完成後,應用程式會自動在瀏覽器中啟動。
注意
由於 Azure App Service 部署啟動延遲,應用程式可能需要一些時間才能啟動。 您可以使用瀏覽器偵錯工具 (通常是按 F12),確認流量已重新導向至 Azure SignalR Service。
針對本機開發啟用 Azure SignalR Service
使用下列命令新增對 Azure SignalR SDK 的參考。
dotnet add package Microsoft.Azure.SignalR
在
Startup.ConfigureServices()
中新增AddAzureSignalR()
呼叫,如下列範例所示:public void ConfigureServices(IServiceCollection services) { ... services.AddSignalR().AddAzureSignalR(); ... }
在 appsettings.json 或使用秘密管理員工具設定 Azure SignalR Service 連接字串。
注意
步驟 2 可替換為設定裝載啟動組件以使用 SignalR SDK。
新增組態以在 appsettings.json 中開啟 Azure SignalR Service。
原始 連接字串 只針對示範目的出現在本文中。 在生產環境中,請一律保護您的存取金鑰。 使用 Azure 金鑰保存庫,使用 Microsoft Entra 識別元安全地管理及輪替您的 連接字串,並使用 Microsoft Entra 標識符來授權存取權。
"Azure": { "SignalR": { "Enabled": true, "ConnectionString": <your-connection-string> } }
設定裝載啟動組件以使用 Azure SignalR SDK。 編輯 launchSettings.json,並在
environmentVariables
中新增組態,如下列範例所示:"environmentVariables": { ..., "ASPNETCORE_HOSTINGSTARTUPASSEMBLIES": "Microsoft.Azure.SignalR" }
清除資源
若要清除在本教學課程中建立的資源,請使用 Azure 入口網站刪除資源群組。
其他資源
下一步
在本教學課程中,您已了解如何:
- 使用 Blazor Server 應用程式範本建立簡單的聊天室。
- 運用 Razor 元件。
- 使用 Razor 元件中的事件處理和資料繫結。
- 快速部署至 Visual Studio 中的 Azure App Service。
- 從本機 SignalR 遷移至 Azure SignalR Service。
深入了解高可用性: