次の方法で共有


ASP.NET Core SignalR を Blazor と共に使用する

注意

これは、この記事の最新バージョンではありません。 現在のリリースについては、この記事の .NET 8 バージョンを参照してください。

重要

この情報はリリース前の製品に関する事項であり、正式版がリリースされるまでに大幅に変更される可能性があります。 Microsoft はここに示されている情報について、明示か黙示かを問わず、一切保証しません。

現在のリリースについては、この記事の .NET 8 バージョンを参照してください。

このチュートリアルでは、Blazor で SignalR を使ってリアルタイム アプリを構築するための基本的な作業エクスペリエンスを提供します。 この記事は、開発者で既に SignalR を良く知っている人や、Blazor アプリでの SignalR の使用方法を理解しようとしている人に役立ちます。 SignalR および Blazor フレームワークの詳細なガイダンスについては、次のリファレンス ドキュメント セットと API ドキュメントを参照してください:

具体的には、次の方法を学習します。

  • Blazor アプリを作成する
  • SignalR クライアント ライブラリを追加する
  • SignalR ハブを追加する
  • SignalR サービスと SignalR ハブのエンドポイントを追加する
  • チャットのための Razor コンポーネント コードを追加する

このチュートリアルの最後には、動作するチャット アプリが完成します。

前提条件

ASP.NET および Web 開発ワークロードを含む Visual Studio 2022 以降

サンプル アプリ

このチュートリアルでは、チュートリアルのサンプル チャット アプリをダウンロードする必要はありません。 このサンプル アプリは、このチュートリアルの手順に従って作成した、最終的な動作するアプリです。

サンプル コードを表示またはダウンロードします (ダウンロード方法)。

Blazor Web アプリを作成する

使用するツールに向けたガイダンスに従ってください。

Note

Visual Studio 2022 以降と .NET Core SDK 8.0.0 以降が必要です。

Visual Studio:

  • [スタート] ウィンドウから [新しいプロジェクトの作成] を選択するか、メニュー バーから [ファイル]>[新規]>[プロジェクト] を選択します。
  • [新しいプロジェクトの作成] ダイアログで、プロジェクト テンプレートのリストから [Blazor Web アプリ] を選択します。 [次へ] ボタンを選択します。
  • [新しいプロジェクトの構成] ダイアログで、[プロジェクト名] フィールでプロジェクトに「BlazorSignalRApp」という名前を付けます (大文字化は一致させます)。 この正確なプロジェクト名を使用することは、名前空間が、チュートリアルからビルドするアプリにコピーするコードと一致するようにするために重要です。
  • アプリの [場所] が適切であることを確認します。 [ソリューションとプロジェクトを同じディレクトリに配置する] チェック ボックスはオンのままにします。 [次へ] ボタンを選択します。
  • [追加情報] ダイアログで、次の設定を使用します。
    • フレームワーク: 最新のフレームワークが選択されていることを確認します。 Visual Studio の [フレームワーク] ドロップダウン リストに使用可能な最新の .NET Framework が含まれていない場合は、Visual Studio を更新して、チュートリアルを再起動します。
    • 認証の種類: なし
    • HTTPS 用の構成: 選択されている (有効)
    • 対話型レンダリング モード: WebAssembly
    • 対話機能の場所: ページ/コンポーネントごと
    • サンプル ページを含める: 選択されている (有効)
    • 最上位レベルのステートメントを使用しない: 選択しない
    • [作成] を選択します

SignalR クライアント ライブラリを追加する

ソリューション エクスプローラーで、BlazorSignalRApp.Client プロジェクトを右クリックし、 [NuGet パッケージの管理] を選択します。

[NuGet パッケージの管理] ダイアログで、 [パッケージ ソース]nuget.org に設定されていることを確認します。

[参照] が選択されている状態で、検索ボックスに「Microsoft.AspNetCore.SignalR.Client」と入力します。

検索結果で、Microsoft.AspNetCore.SignalR.Client パッケージの最新リリースを選択します。 [インストール] を選択します。

[変更のプレビュー] ダイアログ ボックスが表示されたら、 [OK] を選択します。

[ライセンスの同意] ダイアログが表示されたら、ライセンス条項に同意する場合は [同意する] を選択します。

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 ハブのエンドポイントを追加する

サーバー BlazorSignalRApp プロジェクトの Program ファイルを開きます。

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 = 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();
        }
    }
}

NavMenu コンポーネントに、チャット ページに到達するためのエントリを追加します。 Weather コンポーネントの <div> ブロックの直後の Components/Layout/NavMenu.razor に、次の <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>

Note

ホット リロードを使用する場合は、Development 環境の応答圧縮ミドルウェアを無効にします。 詳しくは、ASP.NET Core BlazorSignalR ガイダンスを参照してください。

アプリを実行する

お使いのツール用のガイダンスに従ってください。

ソリューション エクスプローラー で サーバー BlazorSignalRApp プロジェクトが選択された状態で、F5 キーを押して、デバッグしてアプリを実行するか、Ctrl+F5 キー (Windows) または +F5 キーを押して (macOS)、デバッグなしでアプリを実行します。

アドレス バーから URL をコピーし、別のブラウザー インスタンスまたはタブを開き、アドレス バーに URL を貼り付けます。

いずれかのブラウザーを選択し、名前とメッセージを入力し、メッセージを送信するボタンを選択します。 両方のページに、その名前とメッセージが瞬時に表示されます。

交換されたメッセージが表示されている、2 つのブラウザー ウィンドウで開かれた SignalRBlazor サンプル アプリ。

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

ホステッド Blazor WebAssembly エクスペリエンス

アプリを作成する

ホストされている Blazor WebAssembly アプリを作成するには、選択したツールのガイダンスに従ってください。

Note

Visual Studio 2022 以降と .NET Core SDK 6.0.0 以降が必要です。

新しいプロジェクトを作成します。

Blazor WebAssembly アプリ テンプレートを選択します。 [次へ] を選択します。

[プロジェクト名] フィールドに「BlazorWebAssemblySignalRApp」と入力します。 [場所] エントリが正しいことを確認します。または、プロジェクトの場所を指定します。 [次へ] を選択します。

[追加情報] ダイアログで、[ASP.NET Core Hosted] (ホストされている ASP.NET Core) チェックボックスをオンにします。

[作成] を選択します。

ホストされる Blazor WebAssembly アプリが作成されたことを確認します。そのためには、ソリューション エクスプローラーで、Client プロジェクトと Server プロジェクトが存在することを確認します。 2 つのプロジェクトが存在しない場合は、最初からやり直して、[作成] を選択する前に、[ASP.NET Core hosted](ホストされている ASP.NET Core) チェック ボックスをオンにしておきます。

SignalR クライアント ライブラリを追加する

ソリューション エクスプローラーで、BlazorWebAssemblySignalRApp.Client プロジェクトを右クリックし、 [NuGet パッケージの管理] を選択します。

[NuGet パッケージの管理] ダイアログで、 [パッケージ ソース]nuget.org に設定されていることを確認します。

[参照] が選択されている状態で、検索ボックスに「Microsoft.AspNetCore.SignalR.Client」と入力します。

検索結果から Microsoft.AspNetCore.SignalR.Client パッケージを選択します。 アプリの共有フレームワークに合わせてバージョンを設定します。 [インストール] を選択します。

[変更のプレビュー] ダイアログ ボックスが表示されたら、 [OK] を選択します。

[ライセンスの同意] ダイアログが表示されたら、ライセンス条項に同意する場合は [同意する] を選択します。

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 キー (Windows) または +F5 (macOS) キーを押して、デバッグなしでアプリを実行します。

重要

ホスト型 Blazor WebAssembly アプリを実行する場合は、ソリューションのServer プロジェクトから、そのアプリを実行します。

デバッグ セッション用のブラウザーとしては、Google Chrome または Microsoft Edge を選択する必要があります。

ブラウザーでアプリを起動できない場合:

  • .NET コンソールで、ソリューションが "Server" プロジェクトから実行されていることを確認します。
  • ブラウザーの再読み込みボタンを使ってブラウザーを更新します。

アドレス バーから URL をコピーし、別のブラウザー インスタンスまたはタブを開き、アドレス バーに URL を貼り付けます。

いずれかのブラウザーを選択し、名前とメッセージを入力し、メッセージを送信するボタンを選択します。 両方のページに、その名前とメッセージが瞬時に表示されます。

交換されたメッセージが表示されている、2 つのブラウザー ウィンドウで開かれた SignalRBlazor サンプル アプリ。

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

Blazor Server エクスペリエンス

アプリを作成する

Blazor Server アプリを作成するには、選択したツールのガイダンスに従ってください。

Note

Visual Studio 2022 以降と .NET Core SDK 6.0.0 以降が必要です。

新しいプロジェクトを作成します。

[Blazor Server アプリ] テンプレートを選択します。 [次へ] を選択します。

[プロジェクト名] フィールドに「BlazorServerSignalRApp」と入力します。 [場所] エントリが正しいことを確認します。または、プロジェクトの場所を指定します。 [次へ] を選択します。

[作成] を選択します。

SignalR クライアント ライブラリを追加する

ソリューション エクスプローラーで、BlazorServerSignalRApp プロジェクトを右クリックし、 [NuGet パッケージの管理] を選択します。

[NuGet パッケージの管理] ダイアログで、 [パッケージ ソース]nuget.org に設定されていることを確認します。

[参照] が選択されている状態で、検索ボックスに「Microsoft.AspNetCore.SignalR.Client」と入力します。

検索結果から Microsoft.AspNetCore.SignalR.Client パッケージを選択します。 アプリの共有フレームワークに合わせてバージョンを設定します。 [インストール] を選択します。

[変更のプレビュー] ダイアログ ボックスが表示されたら、 [OK] を選択します。

[ライセンスの同意] ダイアログが表示されたら、ライセンス条項に同意する場合は [同意する] を選択します。

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 defines netcoreapp3.0 with no dependencies (dotnet/runtime #45560)」を参照してください。

System.Text.Encodings.Web をプロジェクトに追加するには、使用するツールのガイダンスに従ってください。

ソリューション エクスプローラーで、BlazorServerSignalRApp プロジェクトを右クリックし、 [NuGet パッケージの管理] を選択します。

[NuGet パッケージの管理] ダイアログで、 [パッケージ ソース]nuget.org に設定されていることを確認します。

[参照] が選択されている状態で、検索ボックスに「System.Text.Encodings.Web」と入力します。

検索結果から System.Text.Encodings.Web パッケージを選択します。 使用している共有フレームワークに一致するパッケージのバージョンを選択します。 [インストール] を選択します。

[変更のプレビュー] ダイアログ ボックスが表示されたら、 [OK] を選択します。

[ライセンスの同意] ダイアログが表示されたら、ライセンス条項に同意する場合は [同意する] を選択します。

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);
    }
}
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.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.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);
        }
    }
}

サービスと SignalR ハブのエンドポイントを追加する

Program.cs ファイルを開きます。

Microsoft.AspNetCore.ResponseCompression の名前空間と ChatHub クラスをファイルの先頭に追加します。

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.ResponseCompression の名前空間と ChatHub クラスをファイルの先頭に追加します。

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>
<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);
            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 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);
            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>
<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);
            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>
<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);
            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();
    }
}

注意

ホット リロードを使用する場合は、Development 環境の応答圧縮ミドルウェアを無効にします。 詳しくは、ASP.NET Core BlazorSignalR ガイダンスを参照してください。

アプリを実行する

お使いのツール用のガイダンスに従ってください。

F5 キーを押して、デバッグしてアプリを実行するか、Ctrl+F5 キー (Windows) または +F5 (macOS) キーを押して、デバッグなしでアプリを実行します。

アドレス バーから URL をコピーし、別のブラウザー インスタンスまたはタブを開き、アドレス バーに URL を貼り付けます。

いずれかのブラウザーを選択し、名前とメッセージを入力し、メッセージを送信するボタンを選択します。 両方のページに、その名前とメッセージが瞬時に表示されます。

交換されたメッセージが表示されている、2 つのブラウザー ウィンドウで開かれた SignalRBlazor サンプル アプリ。

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

次の手順

このチュートリアルでは、以下の内容を学習しました。

  • Blazor アプリを作成する
  • SignalR クライアント ライブラリを追加する
  • SignalR ハブを追加する
  • SignalR サービスと SignalR ハブのエンドポイントを追加する
  • チャットのための Razor コンポーネント コードを追加する

SignalR および Blazor フレームワークの詳細なガイダンスについては、次のリファレンス ドキュメント セットを参照してください:

その他のリソース