Início Rápido: Criar uma sala de chat usando o Serviço do SignalR

O Serviço Azure SignalR é um serviço do Azure que ajuda os desenvolvedores a criarem facilmente aplicativos Web com recursos em tempo real.

Este artigo mostra como usar o Serviço Azure SignalR. Neste início rápido, você criará um aplicativo de chat usando um aplicativo web ASP.NET Core. Este aplicativo faz uma conexão com o recurso do Serviço Azure SignalR a fim de habilitar atualizações de conteúdo em tempo real. Você hospedará o aplicativo Web localmente e se conectará com vários clientes do navegador. Cada cliente poderá enviar por push as atualizações de conteúdo para todos os outros clientes.

Você pode usar qualquer editor de código para concluir as etapas deste início rápido. O Visual Studio Code é uma opção disponível nas plataformas Windows, macOS e Linux.

O código para este tutorial está disponível para download no repositório AzureSignalR-samples do GitHub. Você pode criar recursos do Azure usados neste início rápido seguindo Criar um script do Serviço do SignalR.

Se você não tiver uma assinatura do Azure, crie uma conta gratuita antes de começar.

Pronto para começar?

Pré-requisitos

Está com problemas? Experimente o guia de solução de problemas ou fale conosco.

Criar um recurso do Azure SignalR

Nesta seção, você cria uma instância básica do Azure SignalR para usar em seu aplicativo. As etapas a seguir usam o portal do Azure para criar uma nova instância, mas você também pode usar a CLI do Azure. Para obter mais informações, consulte o comando az signalr create na referência da CLI do serviço do Azure SignalR.

  1. Entre no portal do Azure.
  2. No canto superior esquerdo da página, escolha + Criar um recurso.
  3. Na página Criar um recurso, na caixa de texto serviços Pesquisa e marketplace, insira signalr e, em seguida, selecione Serviço do SignalR na lista.
  4. Na página Serviço do SignalR, selecione Criar.
  5. Na guia Noções básicas, você insere as informações essenciais para a nova instância do Serviço do SignalR. Insira os valores a seguir:
Campo Valor sugerido Descrição
Assinatura Escolha sua assinatura Selecione a assinatura que você deseja usar para criar uma nova instância do serviço do SignalR.
Grupo de recursos Criar um grupo de recursos chamado SignalRTestResources Selecione ou crie um grupo de recursos para seu recurso do SignalR. É útil criar um novo grupo de recursos para este tutorial em vez de usar um grupo de recursos existente. Para liberar recursos depois de concluir o tutorial, exclua o grupo de recursos.

A exclusão de um grupo de recursos também exclui todos os recursos que pertencem ao grupo. Essa ação não pode ser desfeita. Antes de excluir um grupo de recursos, certifique-se de que ele não contenha os recursos que você deseja manter.

Para obter mais informações, consulte Usando os grupos de recursos para gerenciar seus recursos do Azure.
Nome do recurso testsignalr Insira um nome exclusivo do recurso a ser usado para o recurso do SignalR. Se testsignalr já estiver sendo usado em sua região, adicione um dígito ou caractere até que o nome seja exclusivo.

O nome deve ser uma cadeia de caracteres com 1 a 63 caracteres, e deve conter somente números, letras e o hífen (-). O nome não pode começar nem terminar com o caractere hífen, e os caracteres hífen consecutivos não serão válidos.
Região Escolha a região Selecione a região apropriada para sua nova instância do serviço do SignalR.

O serviço do Azure SignalR não está disponível atualmente em todas as regiões. Para saber mais, confira Disponibilidade por região do serviço do Azure SignalR
Tipo de preços Selecione Alterar e, em seguida, escolha Gratuito (somente desenvolvimento/teste). Escolha Selecionar para confirmar sua escolha de tipo de preço. O serviço do Azure SignalR tem três tipos de preço: Gratuito, Standard e Premium. Os tutoriais usam o tipo Gratuito, a menos que indicado de outra forma nos pré-requisitos.

Para obter mais informações sobre as diferenças de funcionalidade entre tipos e preços, consulte preço do serviço do Azure SignalR
Modo de serviço Escolha o modo de serviço apropriado Use Padrão quando hospedar a lógica do hub do SignalR em seus aplicativos Web e usar o serviço SignalR como um proxy. Use Sem servidor quando usar tecnologias sem servidor, como o Azure Functions, para hospedar a lógica do hub do SignalR.

O modo Clássico é apenas para compatibilidade com versões anteriores e não é recomendável usar.

Para obter mais informações, confira Modo de serviço no serviço do Azure SignalR.

Você não precisa alterar as configurações nas guias Rede e Marcações para os tutoriais do SignalR.

  1. Selecione o botão Revisar + criar na parte inferior da guia Noções básicas.
  2. Na guia Revisar + Criar, revise os valores e, em seguida, selecione Criar. A implantação leva alguns momentos para ser concluída.
  3. Depois que a implantação estiver concluída, selecione o botão Ir para o recurso.
  4. Na tela de recursos do SignalR, selecione Chaves no menu à esquerda, em Configurações.
  5. Copie a Cadeia de conexão para a chave primária. Você precisa dessa cadeia de conexão para configurar seu aplicativo posteriormente neste tutorial.

Criar um aplicativo Web ASP.NET Core

Nesta seção, você usará a CLI (interface de linha de comando) do .NET Core para criar um projeto de aplicativo Web MVC do ASP.NET Core. A vantagem de usar a CLI do .NET Core em relação ao Visual Studio é que ela está disponível nas plataformas Windows, macOS e Linux.

  1. Crie uma pasta para seu projeto. Este início rápido usa a pasta bate-papo.

  2. Na nova pasta, execute o seguinte comando para criar o projeto:

    dotnet new web
    

Adicionar o Gerenciador de Segredos ao projeto

Nesta seção, você adicionará a ferramenta Gerenciador de Segredos ao projeto. A ferramenta Gerenciador de Segredos armazena dados confidenciais para o trabalho de desenvolvimento fora da árvore do projeto. Essa abordagem ajuda a impedir o compartilhamento acidental de segredos do aplicativo no código-fonte.

  1. Na pasta , inicie UserSecretsId executando o comando a seguir:

    dotnet user-secrets init
    
  2. Adicione um segredo chamado Azure:SignalR:ConnectionString ao Gerenciador de Segredos.

    Esse segredo conterá a cadeia de conexão para acessar seu recurso SignalR Service. Azure:SignalR:ConnectionString é a chave de configuração padrão que o SignalR procura para estabelecer uma conexão. Substitua o valor no comando a seguir pela cadeia de conexão do recurso Serviço do SignalR.

    Este comando deve ser executado no mesmo diretório do arquivo csproj.

    dotnet user-secrets set Azure:SignalR:ConnectionString "<Your connection string>"
    

    O Gerenciador de Segredos só será usado para testar o aplicativo Web enquanto ele estiver hospedado localmente. Em um tutorial posterior, você implantará o aplicativo Web de chat no Azure. Após a implantação do aplicativo Web no Azure, você usará uma configuração de aplicativo em vez de armazenar a cadeia de conexão com o Gerenciador de Segredos.

    Esse segredo é acessado com a API de Configuração. Um sinal de dois pontos (:) funciona no nome da configuração com a API de Configuração em todas as plataformas com suporte. Consulte Configuração por ambiente.

Adicionar o Azure SignalR ao aplicativo Web

  1. Adicione uma referência ao pacote NuGet Microsoft.Azure.SignalR, executando o seguinte comando:

    dotnet add package Microsoft.Azure.SignalR
    
  2. Abra Program.cs e atualize o código para o seguinte, ele chama os métodos AddSignalR() e AddAzureSignalR() para usar o Serviço do Azure SignalR:

    var builder = WebApplication.CreateBuilder(args);
    builder.Services.AddSignalR().AddAzureSignalR();
    var app = builder.Build();
    
    app.UseDefaultFiles();
    app.UseRouting();
    app.UseStaticFiles();
    app.MapHub<ChatSampleHub>("/chat");
    app.Run();
    

    Não passar um parâmetro para AddAzureSignalR(), significa que ele usa a chave de configuração padrão para a cadeia de conexão do recurso Serviço do SignalR. A chave de configuração padrão é Azure:SignalR:ConnectionString. Ele também usa ChatSampleHub, que criaremos na seção abaixo.

Adicionar uma classe de hub

No SignalR, um hub é um componente fundamental que expõe um conjunto de métodos que pode ser chamado do cliente. Nesta seção, você definirá uma classe de hub com dois métodos:

  • BroadcastMessage: este método transmite uma mensagem a todos os clientes.
  • Echo: este método envia uma mensagem de volta para o chamador.

Os dois métodos usam a interface Clients fornecida pelo SDK do SignalR do ASP.NET Core. Essa interface fornece acesso a todos os clientes conectados, permitindo que você envie o conteúdo por push aos clientes.

  1. No diretório do projeto, adicione uma nova pasta chamada Hub. Adicione um novo arquivo de código de hub chamado ChatSampleHub.cs à nova pasta.

  2. Adicione o código a seguir a ChatSampleHub.cs para definir a classe de hub e salve o arquivo.

    using Microsoft.AspNetCore.SignalR;
    
    public class ChatSampleHub : Hub
    {
        public Task BroadcastMessage(string name, string message) =>
            Clients.All.SendAsync("broadcastMessage", name, message);
    
        public Task Echo(string name, string message) =>
            Clients.Client(Context.ConnectionId)
                    .SendAsync("echo", name, $"{message} (echo from server)");
    }
    

Adicionar a interface de cliente para o aplicativo Web

A interface do usuário de cliente para este aplicativo de sala de chat será composta por HTML e JavaScript em um arquivo chamado index.html no diretório wwwroot.

Copie o arquivo css/site.css da pasta wwwroot do repositório de exemplos. Substitua o css/site.css do seu projeto pelo o que você copiou.

Crie um novo arquivo no diretório wwwroot chamado index.html. Em seguida, copie e cole o seguinte HTML no arquivo recém-criado.

<!DOCTYPE html>
<html>
<head>
  <meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate" />
  <meta name="viewport" content="width=device-width">
  <meta http-equiv="Pragma" content="no-cache" />
  <meta http-equiv="Expires" content="0" />
  <link href="https://cdn.jsdelivr.net/npm/bootstrap@3.3.7/dist/css/bootstrap.min.css" rel="stylesheet" />
  <link href="css/site.css" rel="stylesheet" />
  <title>Azure SignalR Group Chat</title>
</head>
<body>
  <h2 class="text-center" style="margin-top: 0; padding-top: 30px; padding-bottom: 30px;">Azure SignalR Group Chat</h2>
  <div class="container" style="height: calc(100% - 110px);">
    <div id="messages" style="background-color: whitesmoke; "></div>
    <div style="width: 100%; border-left-style: ridge; border-right-style: ridge;">
      <textarea id="message" style="width: 100%; padding: 5px 10px; border-style: hidden;"
        placeholder="Type message and press Enter to send..."></textarea>
    </div>
    <div style="overflow: auto; border-style: ridge; border-top-style: hidden;">
      <button class="btn-warning pull-right" id="echo">Echo</button>
      <button class="btn-success pull-right" id="sendmessage">Send</button>
    </div>
  </div>
  <div class="modal alert alert-danger fade" id="myModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel">
    <div class="modal-dialog" role="document">
      <div class="modal-content">
        <div class="modal-header">
          <div>Connection Error...</div>
          <div><strong style="font-size: 1.5em;">Hit Refresh/F5</strong> to rejoin. ;)</div>
        </div>
      </div>
    </div>
  </div>

  <!--Reference the SignalR library. -->
  <script src="https://cdnjs.cloudflare.com/ajax/libs/microsoft-signalr/6.0.1/signalr.js"></script>

  <!--Add script to update the page and send messages.-->
  <script type="text/javascript">
    document.addEventListener("DOMContentLoaded", function () {
      function getUserName() {
        function generateRandomName() {
          return Math.random().toString(36).substring(2, 10);
        }

        // Get the user name and store it to prepend to messages.
        var username = generateRandomName();
        var promptMessage = "Enter your name:";
        do {
          username = prompt(promptMessage, username);
          if (!username || username.startsWith("_") || username.indexOf("<") > -1 || username.indexOf(">") > -1) {
            username = "";
            promptMessage = "Invalid input. Enter your name:";
          }
        } while (!username)
        return username;
      }

      username = getUserName();
      // Set initial focus to message input box.
      var messageInput = document.getElementById("message");
      messageInput.focus();

      function createMessageEntry(encodedName, encodedMsg) {
        var entry = document.createElement("div");
        entry.classList.add("message-entry");
        if (encodedName === "_SYSTEM_") {
          entry.innerHTML = encodedMsg;
          entry.classList.add("text-center");
          entry.classList.add("system-message");
        } else if (encodedName === "_BROADCAST_") {
          entry.classList.add("text-center");
          entry.innerHTML = `<div class="text-center broadcast-message">${encodedMsg}</div>`;
        } else if (encodedName === username) {
          entry.innerHTML = `<div class="message-avatar pull-right">${encodedName}</div>` +
            `<div class="message-content pull-right">${encodedMsg}<div>`;
        } else {
          entry.innerHTML = `<div class="message-avatar pull-left">${encodedName}</div>` +
            `<div class="message-content pull-left">${encodedMsg}<div>`;
        }
        return entry;
      }

      function appendMessage(encodedName, encodedMsg) {
        var messageEntry = createMessageEntry(encodedName, encodedMsg);
        var messageBox = document.getElementById("messages");
        messageBox.appendChild(messageEntry);
        messageBox.scrollTop = messageBox.scrollHeight;
      }

      function bindConnectionMessage(connection) {
        var messageCallback = function (name, message) {
          if (!message) return;
          // Html encode display name and message.
          var encodedName = name;
          var encodedMsg = message.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
          appendMessage(encodedName, encodedMsg);
        };
        // Create a function that the hub can call to broadcast messages.
        connection.on("broadcastMessage", messageCallback);
        connection.on("echo", messageCallback);
        connection.onclose(onConnectionError);
      }

      function onConnected(connection) {
        console.log("connection started");
        connection.send("broadcastMessage", "_SYSTEM_", username + " JOINED");
        document.getElementById("sendmessage").addEventListener("click", function (event) {
          // Call the broadcastMessage method on the hub.
          if (messageInput.value) {
            connection.send("broadcastMessage", username, messageInput.value)
              .catch((e) => appendMessage("_BROADCAST_", e.message));
          }

          // Clear text box and reset focus for next comment.
          messageInput.value = "";
          messageInput.focus();
          event.preventDefault();
        });
        document.getElementById("message").addEventListener("keypress", function (event) {
          if (event.keyCode === 13) {
            event.preventDefault();
            document.getElementById("sendmessage").click();
            return false;
          }
        });
        document.getElementById("echo").addEventListener("click", function (event) {
          // Call the echo method on the hub.
          connection.send("echo", username, messageInput.value);

          // Clear text box and reset focus for next comment.
          messageInput.value = "";
          messageInput.focus();
          event.preventDefault();
        });
      }

      function onConnectionError(error) {
        if (error && error.message) {
          console.error(error.message);
        }
        var modal = document.getElementById("myModal");
        modal.classList.add("in");
        modal.style = "display: block;";
      }

      var connection = new signalR.HubConnectionBuilder()
        .withUrl("/chat")
        .build();
      bindConnectionMessage(connection);
      connection.start()
        .then(function () {
          onConnected(connection);
        })
        .catch(function (error) {
          console.error(error.message);
        });
    });
  </script>
</body>
</html>

O código em index.html, chama HubConnectionBuilder.build() para fazer uma conexão HTTP com o recurso Azure SignalR.

Se a conexão for bem-sucedida, essa conexão será passada para bindConnectionMessage, o que adiciona manipuladores de eventos aos envios por push do conteúdo de entrada para o cliente.

HubConnection.start() inicia a comunicação com o hub. Em seguida, o onConnected() adiciona os manipuladores de evento do botão. Esses manipuladores usam a conexão para permitir que esse cliente envie por push as atualizações de conteúdo a todos os clientes conectados.

Compilar e executar o aplicativo localmente

  1. Execute o seguinte comando para executar o aplicativo Web localmente:

    dotnet run
    

    O aplicativo será hospedado localmente com a saída que contém o URL do localhost, por exemplo, como o seguinte:

    Building...
    info: Microsoft.Hosting.Lifetime[14]
          Now listening on: http://localhost:5000
    info: Microsoft.Hosting.Lifetime[0]
          Application started. Press Ctrl+C to shut down.
    info: Microsoft.Hosting.Lifetime[0]
          Hosting environment: Development
    
  2. Abra duas janelas do navegador. Em cada navegador, vá para o URL do localhost mostrado na janela de saída, por exemplo, http://localhost:5000/ como mostra a janela de saída acima. Você receberá uma solicitação para inserir seu nome. Insira um nome de cliente para os dois clientes e teste o envio por push do conteúdo da mensagem entre eles usando o botão Enviar.

    Example of an Azure SignalR group chat

Limpar os recursos

Se for prosseguir para o próximo tutorial, mantenha os recursos criados neste início rápido e reutilize-os.

Se já não for usar o aplicativo de exemplo do início rápido, exclua os recursos do Azure criados neste início rápido para evitar encargos.

Importante

A exclusão de um grupo de recursos é irreversível e incluirá todos os recursos no grupo. Não exclua acidentalmente grupo de recursos ou recursos incorretos. Se você criou os recursos neste exemplo em um grupo de recursos existente que contém os recursos que deseja manter, exclua cada recurso individualmente de sua folha em vez de excluir o grupo de recursos.

Entre no portal do Azure e selecione Grupos de recursos.

Na caixa de texto Filtrar por nome, digite o nome de seu grupo de recursos. As instruções deste início rápido usaram um grupo de recursos chamado SignalRTestResources. Em seu grupo de recursos, na lista de resultados, escolha as reticências (...) >Excluir grupo de recursos.

Selections for deleting a resource group

Você receberá uma solicitação para confirmar a exclusão do grupo de recursos. Insira o nome do grupo de recursos para confirmar e selecione Excluir.

Após alguns instantes, o grupo de recursos, e todos os recursos nele são excluídos.

Está com problemas? Experimente o guia de solução de problemas ou fale conosco.

Próximas etapas

Neste início rápido, você criou um novo recurso do Serviço Azure SignalR. Em seguida, você o usou com um aplicativo Web ASP.NET Core para enviar atualizações de conteúdo em tempo real para vários clientes conectados. Para saber mais sobre como usar o Serviço Azure SignalR, continue no tutorial, que demonstra a autenticação.