Поделиться через


Руководство. Создание приложения чата Blazor Server

В этом учебнике показано, как создать и изменить приложение Blazor Server. Узнайте следующие темы:

  • создать простую комнату чата с помощью шаблона приложения Blazor Server;
  • работать с компонентами Razor;
  • использовать обработку событий и привязку данных в компонентах Razor;
  • выполнить быстрое развертывание в Службе приложений Azure с помощью Visual Studio;
  • перейти из локальной службы SignalR в Службу Azure SignalR.

Готовы?

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

Возникли проблемы? Сообщите нам об этом.

Создание локальной комнаты чата в приложении Blazor Server

Начиная с Visual Studio 2019 версии 16.2.0 служба Azure SignalR встроена в процесс публикации веб-приложения, что делает управление зависимостями между веб-приложением и службой SignalR гораздо удобнее. Вы можете работать без изменений кода одновременно:

  • в локальном экземпляре SignalR в локальной среде разработки.
  • в Служба Azure SignalR для службы приложение Azure.
  1. Создайте приложение чата Blazor.

    1. В Visual Studio выберите Создать проект.

    2. Выберите Приложение Blazor.

    3. Присвойте приложению имя и выберите папку.

    4. Выберите шаблон Серверное приложение Blazor.

      Примечание.

      Убедитесь, что вы уже установили пакет SDK для .NET Core 3.0 (или более новой версии), что позволит Visual Studio правильно распознавать требуемую версию .NET Framework.

      В разделе

    5. Вы также можете создать проект, выполнив dotnet new команду в CLI .Net:

      dotnet new blazorserver -o BlazorChat
      
  2. Добавьте новый файл C# с именем BlazorChatSampleHub.cs и создайте для приложения чата новый класс BlazorChatSampleHub, производный от класса Hub. Дополнительные сведения о создании концентраторов см. в статье Создание и использование концентраторов.

    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);
            }
        }
    }
    
  3. Добавьте конечную точку для концентратора в методе Startup.Configure().

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapBlazorHub();
        endpoints.MapFallbackToPage("/_Host");
        endpoints.MapHub<BlazorChatSampleHub>(BlazorChatSampleHub.HubUrl);
    });
    
  4. Установите пакет Microsoft.AspNetCore.SignalR.Client для использования клиента SignalR.

    dotnet add package Microsoft.AspNetCore.SignalR.Client --version 3.1.7
    
  5. Чтобы реализовать клиент SignalR, создайте новый компонент Razor, который вызывается ChatRoom.razor в папке Pages . Используйте файл ChatRoom.razor или выполните следующие действия:

    1. Добавьте директиву @page и операторы using. Используйте директиву @inject для внедрения службы NavigationManager.

      @page "/chatroom"
      @inject NavigationManager navigationManager
      @using Microsoft.AspNetCore.SignalR.Client;
      
    2. В разделе @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";
          }
      }
      
    3. Добавьте разметку пользовательского интерфейса перед разделом @code для взаимодействия с клиентом SignalR.

      <h1>Blazor SignalR Chat Sample</h1>
      <hr />
      
      @if (!_isChatting)
      {
          <p>
              Enter your name to start chatting:
          </p>
      
          <input type="text" maxlength="32" @bind="@_username" />
          <button type="button" @onclick="@Chat"><span class="oi oi-chat" aria-hidden="true"></span> Chat!</button>
      
          // Error messages
          @if (_message != null)
          {
              <div class="invalid-feedback">@_message</div>
              <small id="emailHelp" class="form-text text-muted">@_message</small>
          }
      }
      else
      {
          // banner to show current user
          <div class="alert alert-secondary mt-4" role="alert">
              <span class="oi oi-person mr-2" aria-hidden="true"></span>
              <span>You are connected as <b>@_username</b></span>
              <button class="btn btn-sm btn-warning ml-md-auto" @onclick="@DisconnectAsync">Disconnect</button>
          </div>
          // display messages
          <div id="scrollbox">
              @foreach (var item in _messages)
              {
                  @if (item.IsNotice)
                  {
                      <div class="alert alert-info">@item.Body</div>
                  }
                  else
                  {
                      <div class="@item.CSS">
                          <div class="user">@item.Username</div>
                          <div class="msg">@item.Body</div>
                      </div>
                  }
              }
              <hr />
              <textarea class="input-lg" placeholder="enter your comment" @bind="@_newMessage"></textarea>
              <button class="btn btn-default" @onclick="@(() => SendAsync(_newMessage))">Send</button>
          </div>
      }
      
  6. Обновите компонент NavMenu.razor и вставьте новый компонент NavLink для связи с комнатой чата в разделе NavMenuCssClass.

    <li class="nav-item px-3">
        <NavLink class="nav-link" href="chatroom">
            <span class="oi oi-chat" aria-hidden="true"></span> Chat room
        </NavLink>
    </li>
    
  7. Добавьте в файл site.css несколько классов CSS для стилизации элементов пользовательского интерфейса на странице чата.

    /* 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;*/
    }
    
  8. Чтобы запустить приложение, нажмите клавишу F5. Теперь можно начать чат:

    Показан анимированный чат между Бобом и Алиса. Алиса говорит Hello, Боб говорит Привет.

Возникли проблемы? Сообщите нам об этом.

Публикация в Azure

При развертывании приложения Blazor в Службе приложений Azure рекомендуется использовать Службу Azure SignalR. Служба Azure SignalR позволяет масштабировать приложение Blazor Server до большого количества одновременных подключений SignalR. Кроме того, глобальный охват службы SignalR и ее высокопроизводительные центры обработки данных обеспечивают низкую задержку благодаря доступности в разных регионах.

Внимание

В приложении Blazor Server состояния пользовательского интерфейса сохраняются на стороне сервера, то есть для сохранения состояния требуется "прикрепленный" серверный сеанс. Если у вас один сервер приложений, закрепление сеансов реализовано естественным образом. Однако если несколько серверов приложений используются, переговоры клиента и подключение могут быть перенаправлены на разные серверы, что может привести к несогласованному управлению состояниями пользовательского интерфейса в приложении Blazor. Поэтому рекомендуется включить липкие сеансы сервера, как показано в appsettings.json:

"Azure:SignalR:ServerStickyMode": "Required"
  1. Щелкните проект правой кнопкой мыши и выберите Опубликовать. Используйте следующие параметры:

    • Цель: Azure
    • Конкретизированный целевой объект: поддерживаются все типы Службы приложений Azure.
    • Служба приложений: создайте или выберите экземпляр Службы приложений.

    Анимация показывает выбор Azure в качестве целевого объекта, а затем приложение Azure Serice в качестве конкретного целевого объекта.

  2. Добавьте зависимости Службы Azure SignalR.

    После создания профиля публикации в разделе Зависимости службы появится сообщение с рекомендацией добавить службу Azure SignalR. Щелкните Настроить, чтобы создать новую или выбрать существующую Службу Azure SignalR на панели.

    При публикации выделена ссылка на configure.

    Зависимость службы выполняет следующие действия, чтобы приложение автоматически переключалось на Служба Azure SignalR, когда в Azure:

    • Обновите HostingStartupAssembly, чтобы использовать Службу Azure SignalR.
    • Добавьте ссылку на пакет NuGet для Службы Azure SignalR.
    • Обновите свойства профиля таким образом, чтобы сохранить параметры зависимости.
    • Выберите и настройте хранилище секретов.
    • Добавьте конфигурацию в файл appsettings.json, чтобы задать в качестве цели приложения Службу Azure SignalR.

    В сводке изменений флажки используются для выбора всех зависимостей.

  3. Публикация приложения.

    Теперь приложение готово к публикации. После завершения публикации приложение автоматически запускается в браузере.

    Примечание.

    Для запуска приложения может потребоваться некоторое время из-за задержки запуска развертывания Службы приложений Azure. Вы можете использовать средства отладчика браузера (как правило, они вызываются клавишей F12), чтобы убедиться, что трафик перенаправляется в Службу Azure SignalR.

    Пример чата Blazor SignalR содержит текстовое поле для вашего имени и чат! кнопка запуска чата.

Возникли проблемы? Сообщите нам об этом.

Включение Службы Azure SignalR в локальной среде разработки

  1. Добавьте ссылку на пакет SDK Azure SignalR с помощью команды ниже.

    dotnet add package Microsoft.Azure.SignalR
    
  2. Добавьте вызов AddAzureSignalR() , Startup.ConfigureServices() как показано в следующем примере:

    public void ConfigureServices(IServiceCollection services)
    {
        ...
        services.AddSignalR().AddAzureSignalR();
        ...
    }
    
  3. Настройте строку подключения Службы SignalR Azure в файле appsettings.js либо с помощью диспетчера секретов.

Примечание.

Шаг 2 можно заменить настройкой стартовых сборок размещения для использования пакета SDK SignalR.

  1. Добавьте конфигурацию для включения Службы Azure SignalR в файл appsettings.json:

    "Azure": {
      "SignalR": {
        "Enabled": true,
        "ConnectionString": <your-connection-string> 
      }
    }
    
    
  2. Настройте стартовую сборку размещения для использования пакета SDK для Azure SignalR. Отредактируйте файл launchSettings.json и добавьте в environmentVariables конфигурацию, как в примере ниже:

    "environmentVariables": {
        ...,
       "ASPNETCORE_HOSTINGSTARTUPASSEMBLIES": "Microsoft.Azure.SignalR"
     }
    
    

Возникли проблемы? Сообщите нам об этом.

Очистка ресурсов

Чтобы очистить ресурсы, созданные при работе с этим руководством, удалите группу ресурсов через портал Azure.

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

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

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

  • создать простую комнату чата с помощью шаблона приложения Blazor Server;
  • работать с компонентами Razor;
  • использовать обработку событий и привязку данных в компонентах Razor;
  • выполнить быстрое развертывание в Службе приложений Azure с помощью Visual Studio;
  • перейти из локальной службы SignalR в Службу Azure SignalR.

Подробнее о высоком уровне доступности: