Il presente articolo è stato tradotto automaticamente.

Cutting Edge

Creazione di una barra di avanzamento con SignalR

Dino Esposito

Scaricare il codice di esempio

Dino EspositoNegli ultimi due fascicoli di questa colonna ho discusso di come costruire un sito Web ASP.NET soluzione per il problema di sempreverde di monitorare l'avanzamento di un'attività remota dal lato client di un'applicazione Web. Nonostante il successo e l'adozione di AJAX, una soluzione completa e ampiamente accettata per la visualizzazione di una barra di avanzamento sensibile al contesto, all'interno di un'applicazione Web senza ricorrere a Silverlight o Flash è ancora carente.

Per essere onesti, non ci sono molti modi in cui uno può realizzare questo. Si potrebbe creare il proprio soluzione se si vuole, ma il modello sottostante non sarà che diverso da quello che presentato — in particolare di targeting ASP.NET MVC — nelle colonne passate. Questo mese, sono tornato allo stesso argomento, ma verrà illustrato come costruire un progress bar utilizzando una libreria di nuova e ancora in corso: SignalR.

SignalR è un Microsoft.NET Framework libreria e jQuery plug-in fase di sviluppo da ASP.NET team, forse per essere inclusa in futuro comunicati di ASP.Piattaforma di NET. Esso presenta alcune funzionalità estremamente promettente che attualmente manca nella.NET Framework e che sempre di più gli sviluppatori sono esigenti.

SignalR in un colpo d'occhio

SignalR è una libreria di client e server integrata che consente i client basati su browser e ASP.Componenti server basata su rete per avere una conversazione bidirezionale e multistep. In altre parole, la conversazione non si limita a uno scambio di dati di richiesta/risposta singola, apolidi; piuttosto, continua fino a chiusa in modo esplicito. La conversazione si svolge su una connessione persistente e consente al client di inviare più messaggi al server e la risposta del server — e, molto più interessante — invia messaggi asincroni per il client.

Dovrebbe venire come nessuna sorpresa che la canonica demo che utilizzerà per illustrare le funzionalità principali del SignalR è un'applicazione di chat. Il client avvia la conversazione inviando un messaggio al server; il server — una pagina ASP.NETTO dell'endpoint — risponde e mantiene in ascolto per le nuove convocazioni.

SignalR in modo specifico per uno scenario Web e richiede jQuery 1.6 (o più recente) nel client e ASP.NET sul server. È possibile installare SignalR via NuGet o scaricando i bit direttamente dal repository GitHub a github.com/SignalR/SignalR. Figura 1 mostra la pagina di NuGet con tutti i pacchetti SignalR. Come minimo, è necessario scaricare SignalR, con dipendenze sulla SignalR.Server per la parte lato server del quadro e SignalR.Js per la parte client Web del quadro. Gli altri pacchetti che vedere in Figura 1 scopi più specifici come ad esempio fornendo una.NET client, un resolver di dipendenza Ninject e un meccanismo di trasporto alternativo basato su Web HTML5 socket.

SignalR Packages Available on the NuGet Platform
Figura 1 SignalR pacchetti disponibili sulla piattaforma NuGet

All'interno l'esempio Chat

Prima tenta di creare una soluzione di barra di progresso, sarebbe utile prendere confidenza con la libreria di dare un'occhiata ad esempio chat distribuito con il codice sorgente scaricabile (archive.msdn.microsoft.com/mag201203CuttingEdge) e altre informazioni a cui fa riferimento il post correlati (pochi) attualmente disponibili sul Web. Si noti, però, che il SignalR non è un progetto rilasciato.

Nel contesto di una pagina ASP.Progetto NET MVC, si avvia facendo riferimento a un gruppo di file script, come illustrato di seguito:

    <script src="@Url.Content("~/Scripts/jquery-1.6.4.min.js")"
      type="text/javascript"></script>
    <script src="@Url.Content("~/Scripts/jquery.signalr.min.js")"
      type="text/javascript"></script>
    <script src="@Url.Content("~/signalr/hubs")"
      type="text/javascript"></script>

Notare che non c'è nulla di specifico ad ASP.NET MVC in SignalR e la biblioteca può essere usato ugualmente bene con le applicazioni Web Form.

Un punto interessante sottolineare è che i primi due link di riferimento un file di script specifici. Il terzo link, invece, ancora fa riferimento alcuni contenuti JavaScript, ma che il contenuto è generato al volo — e che dipende da qualche altro codice hanno all'interno dell'host ASP.NET applicazione. Si noti inoltre che hai bisogno della libreria JSON2 se avete intenzione di supportare le versioni di Internet Explorer precedenti alla versione 8.

Dopo il caricamento della pagina, puoi completare l'installazione del client e aprire la connessione. Figura 2 di seguito viene illustrato il codice necessario. Si desidera chiamare questo codice all'interno dell'evento pronto di jQuery. Il codice associa i gestori di script agli elementi HTML — unobtrusive JavaScript — e prepara la conversazione di SignalR.

Figura 2 impostazione SignalR libreria per un esempio di Chat

    <script type="text/javascript">
      $(document).ready(function () {    // Add handler to Send button
        $("#sendButton").click(function () {
          chat.send($('#msg').val());
        });
        // Create a proxy for the server endpoint
        var chat = $.connection.chat; 
        // Add a client-side callback to process any data
        // received from the server
        chat.addMessage = function (message) {
          $('#messages').append('<li>' + message + '</li>');
        };
        // Start the conversation
        $.connection.hub.start();
      });
    </script>

Vale la pena notare che l'oggetto fortifica $ è definito nel file di script SignalR. L'oggetto di chiacchierata, al contrario, è un oggetto dinamico, nel senso che il suo codice è generato al volo e viene iniettato nella pagina client tramite riferimento allo script Hub. L'oggetto chiacchierata è in definitiva un proxy JavaScript per un oggetto sul lato server. A questo punto dovrebbe essere chiaro che il client codice Figura 2 significa (e) poco senza una forte controparte sul lato server.

L'ASP.Progetto NET dovrebbe includere un riferimento all'assembly SignalR e le sue dipendenze, come Microsoft.Web.Infrastructure. Il codice sul lato server include una classe gestita che corrisponda all'oggetto JavaScript che è stato creato. Con riferimento al codice in Figura 2, è necessario disporre di un oggetto sul lato server con la stessa interfaccia dell'oggetto Chat sul lato client. Questa classe server erediterà dalla classe Hub definita nell'assembly SignalR. Ecco la firma della classe:

using System;
using SignalR.Hubs;
namespace SignalrProgressDemo.Progress
{
  public class Chat : Hub
  {
    public void Send(String message)
    {
      Clients.addMessage(message);
    }
  }
}

Ogni metodo pubblico nella classe deve corrispondere a un metodo di JavaScript sul client. O, almeno, qualsiasi metodo richiamato su un oggetto JavaScript deve avere un metodo corrispondente nella classe server. Quindi, il metodo Send vedete richiamato il codice di script di Figura 2 finisce per mettere una chiamata al metodo Send dell'oggetto Chat, come definito in precedenza. Per inviare dati al client, il codice del server utilizza la proprietà client sulla classe Hub. Il membro di clienti è di tipo dinamico, che consente di fare riferimento in modo dinamico scoraggiare­minate oggetti. In particolare, la proprietà client contiene un riferimento a un oggetto lato server costruito dopo l'interfaccia dell'oggetto client: l'oggetto di Chat. Perché la Chat oggetto Figura 2 dispone di un metodo addMessage, lo stesso metodo di addMessage dovrebbe essere esposto anche dall'oggetto Chat sul lato server.

Verso una Progress Bar Demo

Ora facciamo uso SignalR di costruire un sistema di notifica che segnala al cliente qualsiasi progresso sta fatto sul server durante un compito forse lungo. Come primo passo, creiamo una classe di lato server che incapsula il compito. Il nome che è assegnare a questa classe, mentre scelto arbitrariamente, interesserà il codice client che scriverò più tardi. Questo significa, semplicemente, che avete un motivo in più per scegliere il nome della classe con cura. Ancora più importante, questa classe eredita da una SignalR fornito classe denominata Hub. Ecco la firma:

public class BookingHub : Hub
{
  ...
}

La classe BookingHub avrà alcuni metodi pubblici — principalmente static void metodi ad accettare qualsiasi sequenza di parametri di input che ha un senso alla loro destinazione. Ogni metodo pubblico su una classe mozzo rappresenta un endpoint possibile per il cliente richiamare. Ad esempio, aggiungiamo un metodo prenotare un volo:

public void BookFlight(String from, String to)
{
  ...
}

Questo metodo dovrebbe contenere tutta la logica che esegue l'azione determinata (che è, prenotazione di un volo). Il codice conterrà anche a varie chiamate di fasi che in qualche modo riferiranno qualsiasi progresso al client. Diciamo che lo scheletro del metodo che bookflight è simile al seguente:

public void BookFlight(String from, String to)
{
  // Book first leg  var ref1 = BookFlight(from, to);  // Book return flight
  var ref2 = BookFlight(to, from);
  // Handle payment
  PayFlight(ref1, ref2);
}

In collaborazione con queste operazioni principali, si desidera informare l'utente circa i progressi compiuti. La classe base Hub offre una proprietà denominata client definito di tipo dinamico. In altre parole, voi avrete richiamare un metodo su questo oggetto per richiamare il cliente. La forma e la forma di questo metodo, però, sono determinati dal cliente stesso. Spostiamo al client, quindi.

Come già accennato, nella pagina client avrete qualche codice di script che viene eseguito quando la pagina viene caricata. Se si utilizza jQuery, l'evento viene $(documento) è un buon posto per l'esecuzione di questo codice. In primo luogo, si ottiene un proxy dell'oggetto server:

var bookingHub = $.connection.bookingHub;
// Some config work
...
// Open the connection
$.connection.hub.start();

Il nome dell'oggetto che pronuncia sul componente nativo $fortifica SignalR è solo un proxy creato in modo dinamico che espone l'interfaccia pubblica dell'oggetto BookingHub per il client. Il proxy viene generato tramite il link signalr-mozzi che avete in <script> sezione della pagina. La convenzione di denominazione utilizzata per i nomi è camelCase, il che significa che la classe BookingHub in c# diventa oggetto bookingHub in JavaScript. Su questo oggetto trovare metodi che corrispondono all'interfaccia pubblica dell'oggetto server. Inoltre, per i metodi, la convenzione di denominazione utilizza gli stessi nomi, ma il seguito. È possibile aggiungere un gestore click di un pulsante HTML e avviare un'operazione di server tramite AJAX, come illustrato di seguito:

bookingHub.bookFlight("fco", "jfk");

È ora possibile definire metodi client per gestire eventuali risposte. Ad esempio, è possibile definire su proxy client un metodo displayMessage che riceve un messaggio e lo visualizza attraverso un tag span HTML:

bookingHub.displayMessage = function (message) {
  $("#msg").html(message);
};

Nota che sei responsabile per la firma del display­metodo del messaggio. Decidere ciò che è stato passato e tipo è aspettarsi ogni ingresso di essere.

Per chiudere il cerchio, c'è un solo numero finale: chi sta chiamando displayMessage e chi è in ultima analisi responsabile per il passaggio dei dati? È il codice lato server Hub. Si chiama displayMessage (e qualsiasi altro metodo di callback si desidera avere in luogo) da all'interno dell'oggetto Hub tramite l'oggetto client. Figura 3 mostra la versione finale della classe Hub.

Nella figura 3 la versione finale della classe Hub

public void BookFlight(String from, String to)
{
  // Book first leg
  Clients.displayMessage(    String.Format("Booking flight: {0}-{1} ...", from, to));
  Thread.Sleep(2000);
  // Book return
  Clients.displayMessage(    String.Format("Booking flight: {0}-{1} ...", to, from));
  Thread.Sleep(3000);
  // Book return
  Clients.displayMessage(    String.Format("Booking flight: {0}-{1} ...", to, from));
  Thread.Sleep(2000);
  // Some return value
  Clients.displayMessage("Flight booked successfully.");
}

Si noti che in questo caso, il nome di displayMessage deve corrispondere perfettamente il caso che è stato utilizzato nel codice JavaScript. Se si digita esso a qualcosa come DisplayMessage, non sarà possibile ottenere qualsiasi eccezione — ma nessun codice verrà eseguito, neanche.

Il codice di Hub viene implementato come un oggetto di attività, quindi ottiene il suo proprio thread per l'esecuzione e non pregiudica l'applicazione ASP.Pool di thread netto.

Se i risultati di attività un server nel lavoro asincrono pianificata, preleverà un thread dal pool del lavoratore standard. Il vantaggio è che SignalR gestori richieste sono asincroni, nel senso che mentre sono in stato di attesa, in attesa di nuovi messaggi, non sono utilizzando un thread a tutti. Quando un messaggio viene ricevuto e non c'è lavoro da fare, una pagina ASP.Thread di lavoro netto viene utilizzato.

Una barra di avanzamento True con HTML

In passato le colonne, come pure in questo uno, ho usato la barra di avanzamento del termine frequentemente senza mai mostrare un calibro classico bar come un esempio di interfaccia utente del client. Avendo un misuratore di bar è un simpatico effetto visivo e non richiede un codice più complesso nell'infrastruttura async. Tuttavia, Figura 4 illustrato il codice JavaScript che costruisce un misuratore bar al volo dato un valore percentuale. È possibile modificare l'aspetto degli elementi HTML tramite classi CSS corretto.

Figura 4 creazione di una barra di Gauge basate su HTML

var GaugeBar = GaugeBar || {};
GaugeBar.generate = function (percentage) {
  if (typeof (percentage) != "number")
    return;
  if (percentage > 100 || percentage < 0)
    return;
  var colspan = 1;
  var markup = "<table class='gauge-bar-table'><tr>" +
    "<td style='width:" + percentage.toString() +
    "%' class='gauge-bar-completed'></td>";
  if (percentage < 100) {
    markup += "<td class='gauge-bar-tobedone' style='width:" +
      (100 - percentage).toString() +
      "%'></td>";
    colspan++;
  }
  markup += "</tr><tr class='gauge-bar-statusline'><td colspan='" +
    colspan.toString() +
    "'>" +
    percentage.toString() +
    "% completed</td></tr></table>";
  return markup;
}

Questo metodo viene richiamato da un gestore click del pulsante:

bookingHub.updateGaugeBar = function (perc) {
  $("#bar").html(GaugeBar.generate(perc));
};

Quindi viene richiamato il metodo di updateGaugeBar da un altro metodo di Hub che utilizza solo un callback client differenti al progresso della relazione. È possibile sostituire solo displayMessage utilizzato in precedenza con updateGaugeBar all'interno di un metodo di Hub.

Non solo i client Web

Ho presentato SignalR principalmente come un'API che richiede un front-end Web. Anche se questo è probabilmente il più avvincente scenario in cui si potrebbe desiderare di usarlo, SignalR è in alcun modo limitato a supportare solo i client Web. È possibile scaricare un client per.NETTE delle applicazioni desktop e un altro client verrà rilasciato presto per supportare i client Windows Phone.

Questa colonna solo scalfito la superficie del SignalR, nel senso che ha presentato l'approccio più semplice e più efficacia per programmarlo. In un articolo futuro, io indagare alcuni della magia che lo fa sotto il cofano e come i pacchetti vengono spostati lungo il filo. Restate sintonizzati.

Dino Esposito è l'autore di "Programming Microsoft ASP.NET MVC3 "(Microsoft Press, 2011) e coautore di"Microsoft.NET: Architettura delle applicazioni per l'impresa"(Microsoft Press, 2008). Con sede in Italia, egli è un oratore frequenti a eventi del settore in tutto il mondo. Può seguirlo su Twitter a twitter.com/despos.

Grazie all'esperto tecnica seguente per la revisione di questo articolo: Damian Edwards