使用 ASP.NET Core SignalR 搭配 Blazor

注意

這不是這篇文章的最新版本。 如需目前版本,請參閱本文的 .NET 8 版本

重要

這些發行前產品的相關資訊在產品正式發行前可能會有大幅修改。 Microsoft 對此處提供的資訊,不做任何明確或隱含的瑕疵擔保。

如需目前版本,請參閱本文的 .NET 8 版本

本教學課程提供建置使用 SignalR 搭配 Blazor 即時應用程式的基本工作體驗。 本文適用於已經熟悉 SignalR 並想要了解如何在 Blazor 應用程式中使用 SignalR 的開發人員。 如需 SignalR 和 Blazor 架構的詳細指引,請參閱下列參考文件集和 API 文件:

了解如何:

  • 建立 Blazor 應用程式
  • 新增 SignalR 用戶端程式庫
  • 新增 SignalR 中樞
  • 新增 SignalR 服務和 SignalR 中樞的端點
  • 新增聊天的 Razor 元件程式碼

在本教學課程結束時,您將有一個可運作的聊天應用程式。

必要條件

Visual Studio 2022 或更新版本,其中包含 ASP.NET 和網頁程式開發工作負載

範例應用程式

本教學課程不需要下載教學課程的範例聊天應用程式。 範例應用程式是遵循本教學課程步驟所產生的最終的正常運作應用程式。

檢視或下載範例程式碼 \(英文\) (如何下載)

建立 Blazor Web 應用程式

請遵循您所選擇工具的指引:

注意

需要 Visual Studio 2022 或更新版本和 .NET Core SDK 8.0.0 或更新版本。

建立新專案。

選取 Blazor Web 應用程式範本。 選取 [下一步] 。

在 [專案名稱] 欄位中輸入 BlazorSignalRApp。 確認 [位置] 項目正確或提供專案的位置。 選取 [下一步]。

確認 Framework 為 .NET 8 或更新版本。 選取 建立

新增 SignalR 用戶端程式庫

在 [方案總管] 中,以滑鼠右鍵按一下 BlazorSignalRApp 專案,然後選取 [管理 NuGet 套件]

在 [管理 NuGet 套件] 對話方塊中,確認 [套件來源] 已設定為 nuget.org

選取 [瀏覽] 後,在搜尋方塊中輸入 Microsoft.AspNetCore.SignalR.Client

在搜尋結果中,選取 Microsoft.AspNetCore.SignalR.Client 套件的最新版本。 選取 [安裝]。

如果出現 [預覽變更] 對話方塊,請選取 [確定]

在出現 [接受授權] 對話方塊時,如果您同意授權條款,請選取 [我接受]

新增 SignalR 中樞

建立 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 檔案。

Microsoft.AspNetCore.ResponseCompressionChatHub 類別的命名空間新增至檔案頂端:

using Microsoft.AspNetCore.ResponseCompression;
using BlazorSignalRApp.Hubs;

新增回應壓縮中介軟體服務:

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

使用處理管線組態頂端的回應壓縮中介軟體:

app.UseResponseCompression();

緊接在對應 Razor 元件 (app.MapRazorComponents<T>()) 的那一行之後為中樞新增端點:

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

新增聊天的 Razor 元件程式碼

開啟 Components/Pages/Home.razor 檔案。

以下列程式碼取代標記:

@page "/"
@rendermode InteractiveServer
@using Microsoft.AspNetCore.SignalR.Client
@inject NavigationManager Navigation
@implements IAsyncDisposable

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

注意

使用熱重新載入時,請在 Development 環境中停用回應壓縮中介軟體。 如需詳細資訊,請參閱 ASP.NET Core BlazorSignalR 指引

執行應用程式

請遵循工具的指引:

F5 以偵錯或 Ctrl+F5 (Windows)/+F5 (macOS) 執行應用程式,而不進行偵錯。

從網址列複製 URL,開啟另一個瀏覽器執行個體或索引標籤,然後將 URL 貼入網址列。

選擇任一個瀏覽器,輸入名稱和訊息,然後選取傳送訊息的按鈕。 名稱和訊息會立即顯示在兩個頁面上:

SignalRBlazor 範例應用程式會在兩個瀏覽器視窗中開啟,其中顯示交換的訊息。

引述:星艦迷航記 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 (Windows)/+F5 (macOS) 執行應用程式,而不進行偵錯。

重要

執行裝載的 Blazor WebAssembly 應用程式時,請從解決方案的Server專案執行應用程式。

Google Chrome 或 Microsoft Edge 必須是偵錯工作階段的選取瀏覽器。

如果應用程式無法在瀏覽器中啟動:

  • 在 .NET 主控台中,確認解決方案正在從「Server」專案執行。
  • 使用瀏覽器的重新載入按鈕來重新整理瀏覽器。

從網址列複製 URL,開啟另一個瀏覽器執行個體或索引標籤,然後將 URL 貼入網址列。

選擇任一個瀏覽器,輸入名稱和訊息,然後選取傳送訊息的按鈕。 名稱和訊息會立即顯示在兩個頁面上:

SignalRBlazor 範例應用程式會在兩個瀏覽器視窗中開啟,其中顯示交換的訊息。

引述:星艦迷航記 VI:邁入未來 ©1991 Paramount

Blazor Server 體驗

建立應用程式

請遵循您選擇的工具指引來建立 Blazor Server 應用程式:

注意

需要 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 套件。 設定版本以符合應用程式的共用架構。 選取安裝

如果出現 [預覽變更] 對話方塊,請選取 [確定]

在出現 [接受授權] 對話方塊時,如果您同意授權條款,請選取 [我接受]

新增 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 (dotnet/runtime #45560)。

若要將 System.Text.Encodings.Web 新增至專案,請遵循您所選擇工具的指引:

在 [方案總管] 中,以滑鼠右鍵按一下 BlazorServerSignalRApp 專案,然後選取 [管理 NuGet 套件]

在 [管理 NuGet 套件] 對話方塊中,確認 [套件來源] 已設定為 nuget.org

選取 [瀏覽] 後,在搜尋方塊中輸入 System.Text.Encodings.Web

在搜尋結果中,選取 System.Text.Encodings.Web 套件。 選取符合使用中共用架構的套件版本。 選取安裝

如果出現 [預覽變更] 對話方塊,請選取 [確定]

在出現 [接受授權] 對話方塊時,如果您同意授權條款,請選取 [我接受]

新增 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.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>
<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 貼入網址列。

選擇任一個瀏覽器,輸入名稱和訊息,然後選取傳送訊息的按鈕。 名稱和訊息會立即顯示在兩個頁面上:

SignalRBlazor 範例應用程式會在兩個瀏覽器視窗中開啟,其中顯示交換的訊息。

引述:星艦迷航記 VI:邁入未來 ©1991 Paramount

下一步

在本教學課程中,您已了解如何:

  • 建立 Blazor 應用程式
  • 新增 SignalR 用戶端程式庫
  • 新增 SignalR 中樞
  • 新增 SignalR 服務和 SignalR 中樞的端點
  • 新增聊天的 Razor 元件程式碼

如需 SignalR 和 Blazor 架構的詳細指引,請參閱下列參考文件集:

其他資源