Esercitazione: Creare un'app di chat Blazor Server

Questa esercitazione illustra come creare e modificare un'app Blazor Server. Nello specifico:

  • Creare una chat room semplice con il modello di app Blazor Server.
  • Usare i componenti Razor.
  • Usare la gestione degli eventi e il data binding nei componenti Razor.
  • Distribuzione rapida nel servizio app Azure in Visual Studio.
  • Eseguire la migrazione da SignalR locale a Servizio Azure SignalR.

Pronti a iniziare?

Prerequisiti

Problemi? Segnalarli.

Creare una chat room locale nell'app Blazor Server

A partire da Visual Studio 2019 versione 16.2.0, Servizio Azure SignalR è integrato nel processo di pubblicazione dell'applicazione Web per semplificare la gestione delle dipendenze tra l'app Web e il servizio SignalR. È possibile lavorare in un'istanza locale di SignalR in un ambiente di sviluppo locale e lavorare in Servizio Azure SignalR per app Azure Servizio contemporaneamente senza modifiche al codice.

  1. Creare un'app blazor chat:

    1. In Visual Studio scegliere Crea un nuovo progetto.

    2. Selezionare Blazor App(App Blazor).

    3. Assegnare un nome all'applicazione e scegliere una cartella.

    4. Selezionare il modello App Server Blazor.

      Nota

      Assicurarsi di aver già installato .NET Core SDK 3.0+ per consentire a Visual Studio di riconoscere correttamente il framework di destinazione.

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

    5. È anche possibile creare un progetto eseguendo il dotnet new comando nell'interfaccia della riga di comando di .NET:

      dotnet new blazorserver -o BlazorChat
      
  2. Aggiungere un nuovo file C# denominato BlazorChatSampleHub.cs e creare una nuova classe BlazorChatSampleHub derivata dalla classe per l'app Hub di chat. Per altre informazioni sulla creazione di hub, vedere Creare e usare 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. Aggiungere un endpoint per l'hub nel Startup.Configure() metodo .

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapBlazorHub();
        endpoints.MapFallbackToPage("/_Host");
        endpoints.MapHub<BlazorChatSampleHub>(BlazorChatSampleHub.HubUrl);
    });
    
  4. Installare il Microsoft.AspNetCore.SignalR.Client pacchetto per usare il client SignalR.

    dotnet add package Microsoft.AspNetCore.SignalR.Client --version 3.1.7
    
  5. Creare un nuovo componente Razor denominato ChatRoom.razor nella Pages cartella per implementare il client SignalR. Seguire la procedura seguente o usare il file ChatRoom.razor .

    1. Aggiungere la @page direttiva e le istruzioni using. Usare la @inject direttiva per inserire il NavigationManager servizio.

      @page "/chatroom"
      @inject NavigationManager navigationManager
      @using Microsoft.AspNetCore.SignalR.Client;
      
    2. @code Nella sezione aggiungere i membri seguenti al nuovo client SignalR per inviare e ricevere messaggi.

      @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. Aggiungere il markup dell'interfaccia utente prima della @code sezione per interagire con il client 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. Aggiornare il NavMenu.razor componente per inserire un nuovo NavLink componente da collegare alla chat room in 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. Aggiungere alcune classi CSS al site.css file per applicare uno stile agli elementi dell'interfaccia utente nella pagina della 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. Premere F5 per eseguire lo script. È ora possibile avviare la chat:

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

Problemi? Segnalarli.

Pubblicare in Azure

Quando si distribuisce l'app Blazor nel servizio app Azure, è consigliabile usare Servizio Azure SignalR. Servizio Azure SignalR consente di aumentare le prestazioni di un'app Blazor Server a un numero elevato di connessioni SignalR simultanee. Inoltre, la copertura globale del servizio SignalR e i data center ad alte prestazioni aiutano significativamente a ridurre la latenza dovuta alla geografia.

Importante

In un'app Blazor Server, gli stati dell'interfaccia utente vengono mantenuti sul lato server, il che significa che è necessaria una sessione server permanente per mantenere lo stato. Se è presente un singolo server app, le sessioni permanenti vengono assicurate dalla progettazione. Tuttavia, se sono presenti più server app, è probabile che la negoziazione del client e la connessione vengano recarsi a server diversi che potrebbero causare una gestione incoerente dello stato dell'interfaccia utente in un'app Blazor. Di conseguenza, è consigliabile abilitare sessioni server permanenti, come illustrato di seguito in appsettings.json:

"Azure:SignalR:ServerStickyMode": "Required"
  1. Fare clic con il pulsante destro del mouse sul progetto e scegliere Pubblica. Usare le seguenti impostazioni:

    • Destinazione: Azure
    • Destinazione specifica: sono supportati tutti i tipi di servizio app Azure.
    • servizio app: creare o selezionare l'istanza di servizio app.

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

  2. Aggiungere la dipendenza Servizio Azure SignalR.

    Dopo la creazione del profilo di pubblicazione, è possibile visualizzare un messaggio di raccomandazione per aggiungere il servizio Azure SignalR in Dipendenze del servizio. Selezionare Configura per creare un nuovo oggetto o selezionare un Servizio Azure SignalR esistente nel riquadro.

    On Publish, the link to Configure is highlighted.

    La dipendenza del servizio eseguirà le attività seguenti per consentire all'app di passare automaticamente a Servizio Azure SignalR quando in Azure:

    • Aggiornare HostingStartupAssembly per usare il servizio Azure SignalR.
    • Aggiungere il riferimento al pacchetto NuGet Servizio Azure SignalR.
    • Aggiornare le proprietà del profilo per salvare le impostazioni di dipendenza.
    • Configurare l'archivio segreti in base alla scelta.
    • Aggiungere la configurazione in appsettings.json per rendere la destinazione dell'app Servizio Azure SignalR.

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

  3. Pubblica l'app.

    Ora l'app è pronta per la pubblicazione. Al termine del processo di pubblicazione, l'app viene avviata automaticamente in un browser.

    Nota

    L'app potrebbe richiedere tempo per l'avvio a causa della latenza di avvio della distribuzione del servizio app Azure. È possibile usare gli strumenti del debugger del browser (in genere premendo F12) per assicurarsi che il traffico sia stato reindirizzato a Servizio Azure SignalR.

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

Problemi? Segnalarli.

Abilitare Servizio Azure SignalR per lo sviluppo locale

  1. Aggiungere un riferimento ad Azure SignalR SDK usando il comando seguente.

    dotnet add package Microsoft.Azure.SignalR
    
  2. Aggiungere una chiamata a AddAzureSignalR() in Startup.ConfigureServices() come illustrato di seguito.

    public void ConfigureServices(IServiceCollection services)
    {
        ...
        services.AddSignalR().AddAzureSignalR();
        ...
    }
    
  3. Configurare il Servizio Azure SignalR stringa di connessione in appsettings.json o tramite lo strumento Secret Manager.

Nota

Il passaggio 2 può essere sostituito con la configurazione degli assembly di avvio dell'hosting per l'uso di SignalR SDK.

  1. Aggiungere la configurazione per attivare Servizio Azure SignalR in appsettings.json:

    "Azure": {
      "SignalR": {
        "Enabled": true,
        "ConnectionString": <your-connection-string>       
      }
    }
    
    
  2. Configurare l'assembly di avvio dell'hosting per l'uso di Azure SignalR SDK. Modificare l'avvio Impostazioni.json e aggiungere una configurazione simile all'esempio seguente all'interno di environmentVariables:

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

Problemi? Segnalarli.

Pulire le risorse

Per pulire le risorse create in questa esercitazione, eliminare il gruppo di risorse usando il portale di Azure.

Risorse aggiuntive

Passaggi successivi

Questa esercitazione ha descritto come:

  • Creare una chat room semplice con il modello di app Blazor Server.
  • Usare i componenti Razor.
  • Usare la gestione degli eventi e il data binding nei componenti Razor.
  • Distribuzione rapida nel servizio app Azure in Visual Studio.
  • Eseguire la migrazione da SignalR locale a Servizio Azure SignalR.

Altre informazioni sulla disponibilità elevata: