Inicio rápido: Creación de un salón de chat con SignalR Service

Azure SignalR Service es un servicio de Azure que ayuda a los desarrolladores a compilar fácilmente aplicaciones web con características en tiempo real.

En este artículo se muestra cómo empezar a trabajar con Azure SignalR Service. En este inicio rápido, creará una aplicación de chat con una aplicación web de ASP.NET Core. Esta aplicación establecerá una conexión con el recurso de Azure SignalR Service para habilitar las actualizaciones de contenido en tiempo real. Hospedará la aplicación web localmente y se conectará con varios clientes de explorador. Cada cliente podrá insertar actualizaciones de contenido en todos los demás clientes.

Puede usar cualquier editor de código para realizar los pasos de esta guía de inicio rápido. Una opción es Visual Studio Code, que está disponible en las plataformas Windows, macOS y Linux.

El código de este tutorial está disponible para su descarga en el repositorio de GitHub AzureSignalR-samples. Puede crear los recursos de Azure usados en este inicio rápido siguiendo el artículo Creación de una instancia de SignalR Service.

Si no tiene una suscripción a Azure, cree una cuenta gratuita antes de empezar.

¿Estás listo para empezar?

Requisitos previos

¿Tiene problemas? Consulte la guía de solución de problemas o póngase en contacto con nosotros.

Creación de un recurso de Azure SignalR

En esta sección, creará una instancia básica de Azure SignalR que se usará para la aplicación. En los pasos siguientes se usa Azure Portal para crear una instancia, pero también puede usar la CLI de Azure. Para obtener más información, vea el comando az signalr create en la referencia de la CLI de Azure SignalR Service.

  1. Inicie sesión en Azure Portal.
  2. En la parte superior izquierda de la página, seleccione + Crear un recurso.
  3. En la página Crear un recurso, en el cuadro de texto Search services and marketplace (Servicios de búsqueda y Marketplace), escriba signalr y, después, seleccione SignalR Service en la lista.
  4. En la página SignalR Service, seleccione Crear.
  5. En la pestaña Aspectos básicos, escriba la información esencial para la nueva instancia de SignalR Service. Escriba los siguientes valores:
Campo Valor sugerido Descripción
Suscripción Elija una suscripción Seleccione la suscripción que quiere usar para crear una instancia de SignalR Service.
Grupos de recursos Cree un grupo de recursos denominado SignalRTestResources Seleccione o cree un grupo de recursos para el recurso SignalR. Es útil crear un grupo de recursos para este tutorial en lugar de usar un grupo de recursos existente. Para liberar recursos después de completar el tutorial, elimine el grupo de recursos.

Al eliminar un grupo de recursos también se eliminarán todos los recursos que pertenezcan a él. Esta acción no se puede deshacer. Antes de eliminar un grupo de recursos, asegúrese de que no incluye los recursos que quiere conservar.

Para obtener más información, consulte Uso de grupos de recursos para administrar los recursos de Azure.
Nombre del recurso testsignalr Escriba un nombre de recurso único para usarlo en el recurso SignalR. Si testsignalr ya se ha usado en la región, agregue un dígito o carácter hasta que el nombre sea único.

El nombre debe ser una cadena de entre 1 y 63 caracteres y solo puede contener números, letras y el carácter de guion (-). El nombre no puede empezar ni terminar con el carácter de guion y no se pueden usar varios guiones consecutivos.
Región Elija la región. Seleccione la región adecuada para la nueva instancia de SignalR Service.

Azure SignalR Service no está disponible actualmente en todas las regiones. Para obtener más información, vea Disponibilidad en regiones para Azure SignalR Service.
Plan de tarifa Seleccione Cambiar y luego elija Free (Dev/Test Only) (Gratis (solo desarrollo/pruebas)). Elija Seleccionar para confirmar el plan de tarifa que elija. Azure SignalR Service tiene tres planes de tarifa: Gratis, Estándar y Premium. Los tutoriales usan el nivel Gratis, a menos que se indique lo contrario en los requisitos previos.

Para obtener más información sobre las diferencias de función entre los niveles y los precios, vea Precios de Azure SignalR Service.
Modo de servicio Elección del modo de servicio adecuado Use el Valor predeterminado cuando hospede la lógica del centro de SignalR en las aplicaciones web y use SignalR Service como proxy. Use Sin servidor cuando use tecnologías sin servidor, como Azure Functions, para hospedar la lógica del centro de SignalR.

El modo Clásico solo es para la compatibilidad con versiones anteriores y no se recomienda su uso.

Para obtener más información, vea Modo de servicio en Azure SignalR Service.

No es necesario cambiar la configuración en las pestañas Redes y Etiquetas de los tutoriales de SignalR.

  1. Seleccione el botón Revisar y crear de la parte inferior de la pestaña Aspectos básicos.
  2. En la pestaña Revisar y crear, revise los valores y luego seleccione Crear. La implementación tarda unos minutos en completarse.
  3. Cuando se complete la implementación, seleccione el botón Ir al grupo de recursos.
  4. En la página de recursos de SignalR, seleccione Claves en el menú de la izquierda, en Configuración.
  5. Copie la cadena de conexión de la clave principal. Necesitará esta cadena de conexión para configurar la aplicación más adelante en este tutorial.

Cree una aplicación web ASP.NET Core

En esta sección, usará la interfaz de la línea de comandos (CLI) de .NET Core para crear un proyecto de aplicación web de ASP.NET Core MVC. La ventaja de usar la CLI de .NET Core frente a Visual Studio es que está disponible en las plataformas Windows, macOS y Linux.

  1. Cree una carpeta para el proyecto. En este inicio rápido se usa la carpeta chattest.

  2. En la nueva carpeta, ejecute el siguiente comando para crear el proyecto:

    dotnet new web
    

Adición de Secret Manager al proyecto

En esta sección, agregará la herramienta Secret Manager al proyecto. La herramienta Secret Manager almacena información confidencial para el trabajo de desarrollo fuera de su árbol de proyecto. Este enfoque ayuda a evitar el uso compartido por accidente de secretos de la aplicación en el código fuente.

  1. En la carpeta, inicializar UserSecretsId ejecutando el siguiente comando:

    dotnet user-secrets init
    
  2. Agregue un secreto llamado Azure:SignalR:ConnectionString a Secret Manager.

    Este secreto contendrá la cadena de conexión para tener acceso al recurso de SignalR Service. Azure__SignalR__ConnectionString es la clave de configuración predeterminada que busca SignalR con el fin de establecer una conexión. Sustituya el valor del siguiente comando por la cadena de conexión del recurso de SignalR Service.

    Este comando debe ejecutarse en el mismo directorio que el archivo csproj.

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

    Secret Manager solo se usará para probar la aplicación web mientras se hospeda localmente. En un tutorial posterior, se implementará la aplicación web de chat en Azure. Una vez que la aplicación web se haya implementado en Azure, usará una configuración de la aplicación en lugar de almacenar la cadena de conexión con Secret Manager.

    A este secreto se accede con la API de configuración. Un signo de dos puntos (:) funciona en el nombre de configuración con la API de configuración en todas las plataformas compatibles. Consulte Configuración en ASP.NET Core.

Adición de Azure SignalR a la aplicación web

  1. Para agregar una referencia al paquete NuGet Microsoft.Azure.SignalR, ejecute el comando siguiente:

    dotnet add package Microsoft.Azure.SignalR
    
  2. Abra Program.cs y actualice el código a lo siguiente, llama a los métodos AddSignalR() y AddAzureSignalR() para usar Azure SignalR Service:

    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();
    

    No pasar un parámetro a AddAzureSignalR() significa que usa la clave de configuración predeterminada para la cadena de conexión del recurso de SignalR Service. La clave de la configuración predeterminada es Azure:SignalR:ConnectionString. También usa ChatSampleHub, que crearemos en la sección siguiente.

Adición de una clase de hub

En SignalR, un concentrador es un componente básico que expone un conjunto de métodos al que se puede llamar desde el cliente. En esta sección, define una clase de hub con dos métodos:

  • BroadcastMessage: este método difunde un mensaje a todos los clientes.
  • Echo: este método devuelve un mensaje al autor de la llamada.

Los dos métodos usan la interfaz Clients proporcionada por el SDK de ASP.NET Core SignalR. Esta interfaz le da acceso a todos los clientes conectados, así puede insertar contenido en los clientes.

  1. En el directorio del proyecto, agregue una nueva carpeta denominada Hub. Agregue un nuevo archivo de código de centro denominado ChatSampleHub.cs a la nueva carpeta.

  2. Agregue el código siguiente a ChatSampleHub.cs para definir la clase de centro y guarde el archivo.

    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)");
    }
    

Adición de la interfaz de cliente para la aplicación web

La interfaz de usuario del cliente en esta aplicación de salón de chat se compondrá de HTML y JavaScript en un archivo llamado index.html en el directorio wwwroot.

Copie el archivo css/site.css de la carpeta wwwroot del repositorio de ejemplos. Reemplace el archivo css/site.css por el que ha copiado.

Cree un archivo en el directorio wwwroot denominado index.html y copie y pegue el siguiente código HTML en el archivo recién creado.

<!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>

El código de index.html llama a HubConnectionBuilder.build() para realizar una conexión HTTP al recurso de Azure SignalR.

Si la conexión es correcta, esa conexión se pasa a bindConnectionMessage, que agrega controladores de eventos para las inserciones de contenido entrante al cliente.

HubConnection.start() inicia la comunicación con el hub. A continuación, onConnected() agrega los controladores de eventos de botón. Estos controladores utilizan la conexión para permitir que este cliente inserte las actualizaciones de contenido en todos los clientes conectados.

Compilación y ejecución de la aplicación en un entorno local

  1. Ejecute el siguiente comando para ejecutar la aplicación localmente:

    dotnet run
    

    La aplicación se hospedará localmente con una salida que contiene la dirección URL de localhost, por ejemplo, como la siguiente:

    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 dos ventanas de explorador. En cada explorador, vaya a la dirección URL de localhost que se muestra en la ventana de salida, por ejemplo http://localhost:5000/, como se muestra en la ventana de salida anterior. Se le pide que escriba su nombre. Escriba un nombre de cliente para ambos clientes y pruebe a insertar el contenido del mensaje entre ambos clientes con el botón Enviar.

    Example of an Azure SignalR group chat

Limpieza de recursos

Si va a seguir con el tutorial siguiente, puede mantener los recursos creados en este inicio rápido y volverlos a usar.

Si ya ha terminado con la aplicación de ejemplo del inicio rápido, puede eliminar los recursos de Azure que se han creado para evitar cargos.

Importante

La eliminación de un grupo de recursos es irreversible e incluye todos los recursos de ese grupo. Asegúrese de no eliminar por accidente el grupo de recursos o los recursos equivocados. Si ha creado los recursos este ejemplo en un grupo de recursos existente que contiene recursos que quiere conservar, puede eliminar cada recurso individualmente de sus hojas, en lugar de eliminar el grupo de recursos.

Inicie sesión en Azure Portal y después seleccione Grupos de recursos.

Escriba el nombre del grupo de recursos en el cuadro de texto Filtrar por nombre. Las instrucciones de esta guía de inicio rápido usan un grupo de recursos llamado SignalRTestResources. En el grupo de recursos, en la lista de resultados, seleccione los puntos suspensivos (...) >Eliminar grupo de recursos.

Selections for deleting a resource group

Se le pedirá que confirme la eliminación del grupo de recursos. Escriba el nombre del grupo de recursos para confirmar y seleccione Eliminar.

Transcurridos unos instantes, el grupo de recursos y todos sus recursos se eliminan.

¿Tiene problemas? Consulte la guía de solución de problemas o póngase en contacto con nosotros.

Pasos siguientes

En este inicio rápido, ha creado un nuevo recurso de Azure SignalR Service. Luego, lo ha usado con una aplicación web ASP.NET Core para insertar actualizaciones de contenido en tiempo real en varios clientes conectados. Para más información sobre cómo usar Azure SignalR Service, continúe con el siguiente tutorial que muestra cómo realizar la autenticación.