Tutorial: Criar um aplicativo de chat do Blazor Server

Este tutorial mostra como criar e modificar um aplicativo Blazor Server. Você aprenderá a:

  • Criar uma sala de chat simples com o modelo de aplicativo Blazor Server.
  • Trabalhar com os componentes do Razor.
  • Usar a manipulação de eventos e a associação de dados em componentes do Razor.
  • Implantar rapidamente o Serviço de Aplicativo do Azure no Visual Studio.
  • Fazer a migração do SignalR local para o Serviço do Azure SignalR.

Pronto para começar?

Pré-requisitos

Está enfrentando problemas? Queremos saber.

Criar uma sala de chat local no aplicativo Blazor Server

No Visual Studio 2019 versão 16.2.0 em diante, o Serviço do Azure SignalR é incorporado ao processo de publicação do aplicativo Web para tornar o gerenciamento das dependências entre o aplicativo Web e o Serviço do SignalR muito mais conveniente. Você pode trabalhar na instância local do SignalR no ambiente de desenvolvimento local e, ao mesmo tempo, no Serviço do Azure SignalR para o Serviço de Aplicativo do Azure sem nenhuma alteração de código.

  1. Crie um aplicativo de chat Blazor:

    1. No Visual Studio, escolha Criar um projeto.

    2. Selecione Aplicativo Blazor.

    3. Dê um nome ao aplicativo e escolha uma pasta.

    4. Selecione o modelo Aplicativo Blazor Server.

      Observação

      Verifique se você já instalou o SDK do .NET Core 3.0 ou posterior a fim de permitir que o Visual Studio reconheça corretamente a estrutura de destino.

      In Create a new project, select the Blazor app template.

    5. Crie também um projeto executando o comando dotnet new na CLI do .NET:

      dotnet new blazorserver -o BlazorChat
      
  2. Adicione um novo arquivo C# chamado BlazorChatSampleHub.cs e crie uma classe BlazorChatSampleHub derivada da classe Hub para o aplicativo de chat. Para obter mais informações sobre como criar hubs, confira Criar e usar hubs.

    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. Adicione um ponto de extremidade para o hub o método Startup.Configure().

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapBlazorHub();
        endpoints.MapFallbackToPage("/_Host");
        endpoints.MapHub<BlazorChatSampleHub>(BlazorChatSampleHub.HubUrl);
    });
    
  4. Instale o pacote Microsoft.AspNetCore.SignalR.Client para usar o cliente do SignalR.

    dotnet add package Microsoft.AspNetCore.SignalR.Client --version 3.1.7
    
  5. Crie um componente do Razor chamado ChatRoom.razor na pasta Pages para implementar o cliente do SignalR. Siga as etapas abaixo ou use o arquivo ChatRoom.razor.

    1. Adicione a diretiva @page e as instruções using. Use a diretiva @inject para injetar o serviço NavigationManager.

      @page "/chatroom"
      @inject NavigationManager navigationManager
      @using Microsoft.AspNetCore.SignalR.Client;
      
    2. Na seção @code, adicione os membros a seguir ao novo cliente do SignalR para enviar e receber mensagens.

      @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. Adicione a marcação de interface do usuário antes da seção @code para interagir com o cliente do 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. Atualize o componente NavMenu.razor para inserir um novo componente NavLink a ser vinculado à sala de chat em 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. Adicione algumas classes CSS ao arquivo site.css para definir o estilo dos elementos de interface do usuário na página de chat.

    /* 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. Pressione F5 para executar o aplicativo. Agora, você poderá iniciar o chat:

    An animated chat between Bob and Alice is shown. Alice says Hello, Bob says Hi.

Está enfrentando problemas? Queremos saber.

Publicar no Azure

Quando você implantar o aplicativo Blazor no Serviço de Aplicativo do Azure, recomendaremos usar o Serviço do Azure SignalR. O Serviço do Azure SignalR permite dimensionar um aplicativo Blazor Server para um grande número de conexões simultâneas do SignalR. Além disso, o alcance global do Serviço do SignalR e os datacenters de alto desempenho ajudam significativamente a reduzir a latência devido à geografia.

Importante

Em um aplicativo Blazor Server, os estados de interface do usuário são mantidos no lado do servidor, o que significa que uma sessão de servidor temporária é necessária para preservar o estado. Se houver um só servidor de aplicativos, as sessões temporárias serão garantidas por design. No entanto, se houver vários servidores de aplicativos, haverá a possibilidade de que a negociação e a conexão do cliente sejam encaminhadas para diferentes servidores, o que poderá levar a um gerenciamento de estado de interface do usuário inconsistente em um aplicativo Blazor. Portanto, recomendamos habilitar as sessões de servidor temporárias, conforme mostrado abaixo em appsettings.json:

"Azure:SignalR:ServerStickyMode": "Required"
  1. Clique com o botão direito do mouse no projeto e acesse Publicar. Use as configurações a seguir:

    • Destino: Azure
    • Destino específico: há suporte para todos os tipos de Serviço de Aplicativo do Azure.
    • Serviço de Aplicativo: crie ou selecione a instância do Serviço de Aplicativo.

    The animation shows selection of Azure as target, and then Azure App Serice as specific target.

  2. Adicione a dependência do Serviço do Azure SignalR.

    Após a criação do perfil de publicação, você poderá ver uma mensagem de recomendação para adicionar o Serviço do Azure SignalR em Dependências de Serviço. Escolha Configurar para criar ou selecionar um Serviço do Azure SignalR existente no painel.

    On Publish, the link to Configure is highlighted.

    A dependência do serviço realizará as seguintes atividades a fim de permitir que o seu aplicativo seja alternado automaticamente para o Serviço do Azure SignalR quando estiver no Azure:

    • Atualizar HostingStartupAssembly para usar o Serviço do Azure SignalR
    • Adicione a referência do pacote NuGet do Serviço do Azure SignalR.
    • Atualize as propriedades do perfil para salvar as configurações de dependência.
    • Configure o repositório de segredos de sua preferência.
    • Adicione a configuração em appsettings.json para fazer com que o aplicativo tenha como destino o Serviço do Azure SignalR.

    On Summary of changes, the checkboxes are used to select all dependencies.

  3. Publique o aplicativo.

    Seu aplicativo está pronto para ser publicado. Após a conclusão do processo de publicação, o aplicativo será iniciado automaticamente em um navegador.

    Observação

    O aplicativo pode exigir algum tempo para ser iniciado devido à latência de início da implantação do Serviço de Aplicativo do Azure. Você pode usar as ferramentas do depurador de navegador (normalmente pressionando F12) para garantir que o tráfego tenha sido redirecionado para o Serviço do Azure SignalR.

    Blazor SignalR Chat Sample has a text box for your name, and a Chat! button to start a chat.

Está enfrentando problemas? Queremos saber.

Habilitar o Serviço do Azure SignalR para o desenvolvimento local

  1. Adicione uma referência ao SDK do Azure SignalR usando o comando a seguir.

    dotnet add package Microsoft.Azure.SignalR
    
  2. Adicione uma chamada a AddAzureSignalR() em Startup.ConfigureServices(), conforme demonstrado abaixo.

    public void ConfigureServices(IServiceCollection services)
    {
        ...
        services.AddSignalR().AddAzureSignalR();
        ...
    }
    
  3. Configure a cadeia de conexão do Serviço do Azure SignalR em appsettings.json ou usando a ferramenta Gerenciador de Segredos.

Observação

A etapa 2 pode ser substituída por meio da configuração de Assemblies de Inicialização de Hospedagem para usar o SDK do SignalR.

  1. Adicione a configuração para ativar o Serviço do Azure SignalR em appsettings.json:

    "Azure": {
      "SignalR": {
        "Enabled": true,
        "ConnectionString": <your-connection-string>       
      }
    }
    
    
  2. Configure o assembly de inicialização de hospedagem para usar o SDK do Azure SignalR. Edite launchSettings.json e adicione uma configuração como o seguinte exemplo dentro de environmentVariables:

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

Está enfrentando problemas? Queremos saber.

Limpar os recursos

Para limpar os recursos criados neste tutorial, exclua o grupo de recursos usando o portal do Azure.

Recursos adicionais

Próximas etapas

Neste tutorial, você aprendeu a:

  • Criar uma sala de chat simples com o modelo de aplicativo Blazor Server.
  • Trabalhar com os componentes do Razor.
  • Usar a manipulação de eventos e a associação de dados em componentes do Razor.
  • Implantar rapidamente o Serviço de Aplicativo do Azure no Visual Studio.
  • Fazer a migração do SignalR local para o Serviço do Azure SignalR.

Leia mais sobre a alta disponibilidade: