チュートリアル:Blazor Server チャット アプリを構築する
このチュートリアルでは、Blazor Server アプリの構築と変更を行う方法について説明します。 学習内容は次のとおりです。
- Blazor Server アプリ テンプレートを使用して簡単なチャット ルームを作成する。
- Razor コンポーネントを操作する。
- Razor コンポーネントのイベント処理とデータ バインディングを使用する。
- Visual Studio で Azure App Service にすばやくデプロイする。
- ローカルの SignalR から Azure SignalR Service に移行する。
開始の準備はできていますか?
前提条件
- .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 App] (Blazor Server アプリ) テンプレートを選択します。
Note
Visual Studio でターゲット フレームワークが正しく認識されるよう、あらかじめ .NET Core SDK 3.0 以上をインストールしておいてください。
.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); });
SignalR クライアントを使用するための
Microsoft.AspNetCore.SignalR.Client
パッケージをインストールします。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"; } }
SignalR クライアントと対話するために、
@code
セクションの前に UI マークアップを追加します。<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
コンポーネントを更新して、NavMenuCssClass
の下のチャット ルームにリンクする新しいNavLink
コンポーネントを挿入します。<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>
site.css
ファイルにいくつかの 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 に発行する
Azure App Service に Blazor アプリをデプロイする場合は、Azure SignalR Service を使用することをお勧めします。 Azure SignalR Service を使うと、Blazor Server アプリを多数の同時 SignalR 接続にスケールアップできます。 さらに、SignalR Service のグローバル リーチとハイパフォーマンスのデータセンターは、地理的条件による待ち時間の短縮に大きく役立ちます。
重要
Blazor Server アプリでは、UI の状態はサーバー側で保持されます。つまり、状態を保持するには、スティッキー サーバー セッションが必要です。 アプリ サーバーが 1 台の場合は、設計によってスティッキー セッションが保証されます。 これに対し、複数のアプリ サーバーがある場合は、クライアントのネゴシエーションと接続に異なるサーバーが使用された結果、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 SignalR Service が Azure 上にあればアプリがそれに自動的に切り替わるよう、サービス依存関係によって以下のアクティビティが実行されます。
- Azure SignalR Service を使用するように
HostingStartupAssembly
を更新する。 - Azure SignalR Service NuGet パッケージの参照を追加する。
- プロファイル プロパティを更新して、依存関係の設定を保存する。
- 選択内容に従ってシークレット ストアを構成する。
- Azure SignalR Service がアプリのターゲットとなるように appsettings.json に構成を追加する。
- Azure SignalR Service を使用するように
アプリの発行
これで、アプリを発行する準備が整いました。 発行プロセスが完了すると、ブラウザー内でアプリが自動的に起動されます。
Note
Azure App Service のデプロイが開始されるまでの待ち時間が原因で、アプリの起動に時間がかかる場合があります。 (通常は F12 キーを押して) ブラウザーのデバッガー ツールを使用すると、トラフィックが Azure SignalR Service にリダイレクトされていることを確認できます。
ローカル開発用に Azure SignalR Service を有効にする
次のコマンドを使用して、Azure SignalR SDK への参照を追加します。
dotnet add package Microsoft.Azure.SignalR
次に示すように、
AddAzureSignalR()
の呼び出しをStartup.ConfigureServices()
に追加します。public void ConfigureServices(IServiceCollection services) { ... services.AddSignalR().AddAzureSignalR(); ... }
appsettings.json 内で、またはシークレット マネージャー ツールを使用して、Azure SignalR Service の接続文字列を構成します。
Note
手順 2 の代わりに、SignalR SDK を使用するようにホスティング スタートアップ アセンブリを構成することができます。
Azure SignalR Service を有効にするための構成を appsettings.json に追加します。
"Azure": { "SignalR": { "Enabled": true, "ConnectionString": <your-connection-string> } }
Azure SignalR SDK を使用するようにホスティング スタートアップ アセンブリを構成します。 launchSettings.json を編集して、
environmentVariables
内に次の例のような構成を追加します。"environmentVariables": { ..., "ASPNETCORE_HOSTINGSTARTUPASSEMBLIES": "Microsoft.Azure.SignalR" }
リソースをクリーンアップする
このチュートリアルで作成したリソースをクリーンアップするには、Azure portal を使用してリソース グループを削除します。
その他のリソース
次のステップ
このチュートリアルでは、以下の内容を学習しました。
- Blazor Server アプリ テンプレートを使用して簡単なチャット ルームを作成する。
- Razor コンポーネントを操作する。
- Razor コンポーネントのイベント処理とデータ バインディングを使用する。
- Visual Studio で Azure App Service にすばやくデプロイする。
- ローカルの SignalR から Azure SignalR Service に移行する。
高可用性についての詳細を参照してください。
フィードバック
https://aka.ms/ContentUserFeedback」を参照してください。
以下は間もなく提供いたします。2024 年を通じて、コンテンツのフィードバック メカニズムとして GitHub の issue を段階的に廃止し、新しいフィードバック システムに置き換えます。 詳細については、「フィードバックの送信と表示