Guida introduttiva: Creare una chat room usando Servizio SignalR

Il servizio Azure SignalR è un servizio di Azure che consente agli sviluppatori di compilare facilmente applicazioni Web con funzionalità in tempo reale.

Questo articolo illustra come iniziare a usare il servizio Azure SignalR. In questa guida introduttiva si creerà un'applicazione di chat usando un'app Web ASP.NET Core. Questa app stabilirà una connessione alla risorsa del servizio Azure SignalR per abilitare gli aggiornamenti dei contenuti in tempo reale. L'applicazione Web sarà ospitata in locale e verrà stabilita la connessione con più client browser. Ogni client sarà in grado di eseguire il push degli aggiornamenti dei contenuti a tutti gli altri client.

Per completare i passaggi descritti in questa guida di avvio rapido è possibile usare qualsiasi editor di codice. Una scelta possibile è Visual Studio Code, disponibile per le piattaforme Windows, macOS e Linux.

Il codice per questa esercitazione è disponibile per il download nel repository GitHub AzureSignalR-samples. È possibile creare le risorse di Azure usate in questa guida introduttiva seguendo creare uno script di Servizio SignalR.

Se non si ha una sottoscrizione di Azure, creare un account gratuito prima di iniziare.

Pronti a iniziare?

Prerequisiti

Problemi? Vedere la guida alla risoluzione dei problemi oppure segnalarli.

Creare una risorsa di Azure SignalR

In questa sezione viene creata un'istanza di Azure SignalR di base da usare per l'app. I passaggi seguenti usano il portale di Azure per creare una nuova istanza, ma è anche possibile usare l'interfaccia della riga di comando di Azure. Per altre informazioni, vedere il comando az signalr create nella guida di riferimento all'interfaccia della riga di comando di Servizio Azure SignalR.

  1. Accedi al portale di Azure.
  2. Nell'angolo in alto a sinistra della pagina selezionare + Crea una risorsa.
  3. Nella pagina Crea una risorsa, nella casella di testo servizio di ricerca e marketplace immettere signalr e quindi selezionare Servizio SignalR dall'elenco.
  4. Nella pagina Servizio SignalR selezionare Crea.
  5. Nella scheda Informazioni di base immettere le informazioni essenziali per la nuova istanza di Servizio SignalR. Immettere i valori seguenti:
Campo Valore consigliato Descrizione
Abbonamento Scegliere la sottoscrizione in uso Selezionare la sottoscrizione da usare per creare una nuova istanza di Servizio SignalR.
Gruppo di risorse Creare un gruppo di risorse denominato SignalRTestResources Selezionare o creare un gruppo di risorse per la risorsa SignalR. È utile creare un nuovo gruppo di risorse per questa esercitazione anziché usare un gruppo di risorse esistente. Per liberare risorse dopo aver completato l'esercitazione, eliminare il gruppo di risorse.

L'eliminazione di un gruppo di risorse elimina anche tutte le risorse che appartengono al gruppo. Non è possibile annullare questa azione. Prima di eliminare un gruppo di risorse, assicurarsi che non contenga risorse da conservare.

Per altre informazioni, vedere Using resource groups to manage your Azure resources (Uso di Gruppi di risorse per gestire le risorse di Azure).
Nome risorsa testsignalr Immettere un nome risorsa univoco da usare per la risorsa SignalR. Se testsignalr è già stato eseguito nell'area, aggiungere una cifra o un carattere fino a quando il nome non è univoco.

Il nome deve essere una stringa contenente da 1 a 63 caratteri che possono includere solo numeri, lettere e il segno meno (-). Il nome non può iniziare o terminare con il trattino e i caratteri trattini consecutivi non sono validi.
Area Scegli la tua area geografica Selezionare l'area appropriata per la nuova istanza di Servizio SignalR.

Servizio Azure SignalR non è attualmente disponibile in tutte le aree. Per altre informazioni, vedere disponibilità dell'area Servizio Azure SignalR
Piano tariffario Selezionare Cambia e quindi scegliere Gratuito (solo sviluppo/test). Scegliere Seleziona per confermare la scelta del piano tariffario. Servizio Azure SignalR ha tre piani tariffari: Gratuito, Standard e Premium. Le esercitazioni usano il livello Gratuito , a meno che non sia specificato diversamente nei prerequisiti.

Per altre informazioni sulle differenze di funzionalità tra i livelli e i prezzi, vedere Servizio Azure SignalR prezzi
Modalità di servizio Scegliere la modalità di servizio appropriata Usare Default quando si ospita la logica dell'hub SignalR nelle app Web e si usa il servizio SignalR come proxy. Usare Serverless quando si usano tecnologie serverless, ad esempio Funzioni di Azure per ospitare la logica dell'hub SignalR.

La modalità classica è solo per la compatibilità con le versioni precedenti e non è consigliabile usarla.

Per altre informazioni, vedere Modalità di servizio in Servizio Azure SignalR.

Non è necessario modificare le impostazioni nelle schede Rete e Tag per le esercitazioni su SignalR.

  1. Selezionare il pulsante Rivedi e crea nella parte inferiore della scheda Informazioni di base .
  2. Nella scheda Rivedi e crea esaminare i valori e quindi selezionare Crea. Il completamento della distribuzione richiede alcuni istanti.
  3. Al termine della distribuzione, selezionare il pulsante Vai alla risorsa .
  4. Nella pagina della risorsa SignalR selezionare Chiavi dal menu a sinistra, sotto Impostazioni.
  5. Copiare la stringa di Connessione ion per la chiave primaria. Questa stringa di connessione è necessaria per configurare l'app più avanti in questa esercitazione.

Creare un'app Web ASP.NET Core

In questa sezione verrà usata l'interfaccia della riga di comando di .NET Core per creare un progetto di app Web ASP.NET Core MVC. Il vantaggio di usare l'interfaccia della riga di comando di .NET Core rispetto a Visual Studio è che è disponibile nelle piattaforme Windows, macOS e Linux.

  1. Creare una cartella per il progetto. Questa guida introduttiva usa la cartella chattest .

  2. Nella nuova cartella eseguire il comando seguente per creare il progetto:

    dotnet new web
    

Aggiungere Secret Manager al progetto

In questa sezione verrà aggiunto lo strumento Secret Manager al progetto. Lo strumento Secret Manager archivia i dati sensibili per operazioni di sviluppo al di fuori dell'albero del progetto. Questo approccio contribuisce a impedire la condivisione accidentale dei segreti dell'app nel codice sorgente.

  1. Nella cartella init UserSecretsId eseguire il comando seguente:

    dotnet user-secrets init
    
  2. Aggiungere un segreto denominato Azure:SignalR:ConnectionString a Secret Manager.

    Questo segreto conterrà la stringa di connessione per accedere alla risorsa del servizio SignalR. Azure:SignalR:ConnectionString è la chiave di configurazione predefinita cercata da SignalR per stabilire una connessione. Sostituire il valore nel comando seguente con la stringa di connessione per la propria risorsa del servizio SignalR.

    È necessario eseguire questo comando nella stessa directory del csproj file.

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

    Secret Manager verrà usato solo per il test dell'app Web mentre è ospitata in locale. In un'esercitazione successiva si distribuirà l'app Web di chat in Azure. Dopo la distribuzione dell'app Web in Azure, sarà possibile usare un'impostazione dell'applicazione invece di archiviare la stringa di connessione con Secret Manager.

    È possibile accedere al segreto con l'API di configurazione. Con tale API è possibile usare i due punti (:) nel nome di configurazione in tutte le piattaforme supportate. Vedere la configurazione in base all'ambiente.

Aggiungere Azure SignalR all'app Web

  1. Aggiungere un riferimento al pacchetto NuGet Microsoft.Azure.SignalR eseguendo il comando seguente:

    dotnet add package Microsoft.Azure.SignalR
    
  2. Aprire Program.cs e aggiornare il codice con il codice seguente, chiama i AddSignalR() metodi e AddAzureSignalR() per usare Servizio 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();
    

    Non passando un parametro a AddAzureSignalR() significa che usa la chiave di configurazione predefinita per la risorsa Servizio SignalR stringa di connessione. La chiave di configurazione predefinita è Azure:SignalR:ConnectionString. Viene usato anche ChatSampleHub il quale verrà creato nella sezione seguente.

Aggiungere una classe hub

In SignalR un hub è un componente di base che espone un set di metodi che possono essere chiamati dal client. In questa sezione si definisce una classe hub con due metodi:

  • BroadcastMessage: questo metodo trasmette un messaggio a tutti i client.
  • Echo: questo metodo invia un messaggio al chiamante.

Entrambi i metodi usano l'interfaccia Clients fornita da ASP.NET Core SignalR SDK. Questa interfaccia consente di accedere a tutti i client connessi, rendendo possibile il push del contenuto ai client.

  1. Nella directory del progetto aggiungere una nuova cartella denominata Hub. Aggiungere un nuovo file di codice hub denominato ChatSampleHub.cs alla nuova cartella.

  2. Aggiungere il codice seguente a ChatSampleHub.cs per definire la classe hub e salvare il file.

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

Aggiungere l'interfaccia client per l'app Web

L'interfaccia utente client per questa app di chat room sarà costituita da HTML e JavaScript in un file denominato index.html nella directory wwwroot.

Copiare il file css/site.css dalla cartella wwwroot del repository degli esempi. Sostituire il file css/site.css del progetto con quello copiato.

Creare un nuovo file nella directory wwwroot denominata index.html, copiare e incollare il codice HTML seguente nel file appena creato.

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

Il codice in index.html chiama HubConnectionBuilder.build() per stabilire una connessione HTTP alla risorsa di Azure SignalR.

Se la connessione ha esito positivo, viene passata a bindConnectionMessage, che consente di aggiungere i gestori di eventi per i push dei contenuti in ingresso al client.

HubConnection.start() avvia la comunicazione con l'hub. onConnected() quindi aggiunge i gestori eventi del pulsante. Questi gestori usano la connessione per consentire a questo client di eseguire il push degli aggiornamenti dei contenuti a tutti i client connessi.

Compilare ed eseguire l'app in locale

  1. Eseguire il comando seguente per eseguire l'app Web in locale:

    dotnet run
    

    L'app verrà ospitata in locale con output contenente l'URL localhost, ad esempio, come indicato di seguito:

    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. Aprire due finestre del browser. In ogni browser passare all'URL localhost visualizzato nella finestra di output, ad esempio, http://localhost:5000/ come illustrato nella finestra di output precedente. Verrà richiesto di immettere il proprio nome. Immettere un nome per entrambi i client e verificare il push del contenuto del messaggio tra i due client usando il pulsante Invia.

    Example of an Azure SignalR group chat

Pulire le risorse

Se si proseguirà con l'esercitazione successiva, sarà possibile conservare le risorse create in questo argomento di avvio rapido e riutilizzarle.

Se si è terminato di lavorare con l'applicazione di esempio di avvio rapido, è possibile eliminare le risorse di Azure create in questo argomento di avvio rapido per evitare i costi correlati.

Importante

L'eliminazione di un gruppo di risorse è irreversibile e interessa tutte le risorse del gruppo. Assicurarsi di non eliminare accidentalmente il gruppo di risorse sbagliato o le risorse errate. Se sono state create le risorse in questo esempio in un gruppo di risorse esistente che contiene risorse da conservare, è possibile eliminare ogni risorsa singolarmente dal relativo pannello anziché eliminare il gruppo di risorse.

Accedere al portale di Azure e selezionare Gruppi di risorse.

Nella casella di testo Filtra per nome digitare il nome del gruppo di risorse. Per le istruzioni di questa guida introduttiva è stato usato un gruppo di risorse denominato SignalRTestResources. Nel gruppo di risorse nell'elenco dei risultati selezionare i puntini di sospensione (...) >Eliminare un gruppo di risorse.

Selections for deleting a resource group

Verrà chiesto di confermare l'eliminazione del gruppo di risorse. Immettere il nome del gruppo di risorse per confermare e selezionare Elimina.

Dopo qualche istante, il gruppo di risorse e tutte le risorse che contiene vengono eliminati.

Problemi? Vedere la guida alla risoluzione dei problemi oppure segnalarli.

Passaggi successivi

In questo argomento di avvio rapido è stata creata una nuova risorsa del servizio Azure SignalR È stata quindi usata con un'app Web ASP.NET Core per eseguire il push degli aggiornamenti del contenuto in tempo reale a più client connessi. Per altre informazioni sull'uso del servizio Azure SignalR, continuare con l'esercitazione sull'autenticazione.