Использование SignalR для ASP.NET Core с Blazor

Примечание.

Это не последняя версия этой статьи. В текущем выпуске см . версию .NET 8 этой статьи.

Внимание

Эта информация относится к предварительному выпуску продукта, который может быть существенно изменен до его коммерческого выпуска. Майкрософт не предоставляет никаких гарантий, явных или подразумеваемых, относительно приведенных здесь сведений.

В текущем выпуске см . версию .NET 8 этой статьи.

В этом руководстве представлен базовый рабочий интерфейс для создания приложения в режиме реального времени с помощью SignalRBlazor. Эта статья полезна для разработчиков, которые уже знакомы SignalR и стремятся понять, как использовать SignalR в Blazor приложении. Подробные рекомендации по SignalR платформам Blazor см. в следующих справочных наборах документации и документации по API:

Вы узнаете, как выполнять следующие задачи:

  • Создание приложения Blazor
  • Добавление клиентской библиотеки SignalR
  • добавлять концентратор SignalR;
  • добавлять службы и конечную точку SignalR для концентратора SignalR;
  • Добавление кода компонента для чата Razor

Когда вы выполните задачи из этого руководства, у вас будет работающее приложение чата.

Необходимые компоненты

Visual Studio 2022 или более поздней версии с рабочей нагрузкой ASP.NET и разработка веб-приложений

Пример приложения

Для работы с этим руководством загружать пример приложения чата не обязательно. Пример приложения — это готовое рабочее приложение, созданное в результате выполнения действий, описанных в этом учебнике.

Просмотреть или скачать образец кода (описание загрузки)

Blazor Создание веб-приложения

Следуйте указаниям по выбору инструментов:

Примечание.

Требуются visual Studio 2022 или более поздней версии и пакет SDK для .NET Core 8.0.0 или более поздней версии.

Создание проекта

Blazor Выберите шаблон веб-приложения. Выберите Далее.

Введите BlazorSignalRApp в поле Имя проекта. Убедитесь, что для проекта правильно указано существующее расположение или укажите новое. Выберите Далее.

Убедитесь, что платформа — .NET 8 или более поздней версии. Нажмите кнопку создания.

Добавление клиентской библиотеки SignalR

В обозревателе решений щелкните проект BlazorSignalRApp правой кнопкой мыши и выберите пункт Управление пакетами NuGet.

Убедитесь, что в диалоговом окне Управление пакетами NuGet для параметра Источник пакета установлено значение nuget.org.

Нажав кнопку Обзор, введите Microsoft.AspNetCore.SignalR.Client в поле поиска.

В результатах поиска выберите последний выпуск Microsoft.AspNetCore.SignalR.Client пакета. Выберите Установить.

Если откроется диалоговое окно Просмотр изменений, нажмите кнопку ОК.

Если откроется диалоговое окно Принятие условий лицензионного соглашения, выберите Я принимаю, если принимаете условия.

добавлять концентратор SignalR;

Hubs Создайте папку (plural) и добавьте следующий 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.ResponseCompression и класс ChatHub в начало файла:

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 или более поздней версии и пакет SDK для .NET Core 6.0.0 или более поздней версии.

Создание проекта

Выберите шаблон приложения Blazor WebAssembly. Выберите Далее.

Введите BlazorWebAssemblySignalRApp в поле Имя проекта. Убедитесь, что для проекта правильно указано существующее расположение или укажите новое. Выберите Далее.

В диалоговом окне Дополнительные сведения установите флажок ASP.NET Core hosted (Размещено в ASP.NET Core).

Нажмите кнопку создания.

Убедитесь, что размещенное приложение Blazor WebAssembly создано: В Обозревателе решений проверьте наличие проекта Client и проекта Server. Если проекты отсутствуют, повторите процедуру заново, убедившись, что флажок ASP.NET Core Hosted (Размещено в ASP.NET Core) установлен, прежде чем нажимать Создать.

Добавление клиентской библиотеки SignalR

В обозревателе решений щелкните проект BlazorWebAssemblySignalRApp.Client правой кнопкой мыши и выберите пункт Управление пакетами NuGet.

Убедитесь, что в диалоговом окне Управление пакетами NuGet для параметра Источник пакета установлено значение nuget.org.

Нажав кнопку Обзор, введите Microsoft.AspNetCore.SignalR.Client в поле поиска.

В результатах поиска выберите пакет Microsoft.AspNetCore.SignalR.Client. Задайте версию в соответствии с общей платформой приложения. Выберите Установить.

Если откроется диалоговое окно Просмотр изменений, нажмите кнопку ОК.

Если откроется диалоговое окно Принятие условий лицензионного соглашения, выберите Я принимаю, если принимаете условия.

добавлять концентратор SignalR;

В проекте BlazorWebAssemblySignalRApp.Server создайте папку Hubs (plural) и добавьте следующий класс 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 или более поздней версии и пакет SDK для .NET Core 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.

Из-за проблемы с разрешением пакета при использовании System.Text.Json 5.x в приложении ASP.NET Core 3.x для проекта требуется ссылка на пакет System.Text.Encodings.Web. Основная проблема устранена в выпуске исправлений и была возвращена в ASP.NET Core 5.0. См. дополнительные сведения о том, как System.Text.Json определяет netcoreapp3.0 без зависимостей (dotnet/runtime #45560).

Чтобы добавить System.Text.Encodings.Web в проект, следуйте указаниям по выбору инструментов:

В обозревателе решений щелкните проект BlazorServerSignalRApp правой кнопкой мыши и выберите пункт Управление пакетами NuGet.

Убедитесь, что в диалоговом окне Управление пакетами NuGet для параметра Источник пакета установлено значение nuget.org.

Нажав кнопку Обзор, введите System.Text.Encodings.Web в поле поиска.

В результатах поиска выберите пакет System.Text.Encodings.Web. Выберите версию пакета, соответствующую используемой общей платформе. Выберите Установить.

Если откроется диалоговое окно Просмотр изменений, нажмите кнопку ОК.

Если откроется диалоговое окно Принятие условий лицензионного соглашения, выберите Я принимаю, если принимаете условия.

добавлять концентратор SignalR;

Создайте папку Hubs (plural) и добавьте следующий класс 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-адрес в адресную строку.

Выберите любой браузер, введите имя и сообщение и нажмите кнопку для отправки сообщения. Имя и сообщение отображаются на обеих страницах мгновенно:

SignalRBlazor Пример приложения открыт в двух окнах браузера с обменом сообщениями.

Цитаты: Звездный путь VI. Неоткрытая страна ©1991 Paramount

Следующие шаги

Из этого руководства вы узнали, как:

  • Создание приложения Blazor
  • Добавление клиентской библиотеки SignalR
  • добавлять концентратор SignalR;
  • добавлять службы и конечную точку SignalR для концентратора SignalR;
  • Добавление кода компонента для чата Razor

Подробные рекомендации по SignalR платформам Blazor см. в следующих справочных наборах документации:

Дополнительные ресурсы