Maggio 2018

Volume 33 Numero 5

Il presente articolo è stato tradotto automaticamente.

Cutting Edge - Dietro le quinte di ASP.NET Core SignalR

Dal Dino Esposito

Dino EspositoSignalR è l'ultima aggiunta per la piattaforma di ASP.NET Core e un'attesa prolungata presente che. È possibile utilizzare sostengono che solo con SignalR a bordo possiamo è davvero iniziare esaminando ASP.NET Core come pronto per tutti i tipi di applicazioni. Nessuna applicazione Web grave oggi è possibile eseguire senza una forma di notifica asincrona e funzionalità in tempo reale.

Si sa ASP.NET SignalR è stata completamente riscritta e si trovano ora nella famiglia di librerie di ASP.NET Core. La colonna ultimo mese (msdn.com/magazine/mt846469), offerta una breve panoramica delle funzionalità e le funzionalità di ASP.NET Core SignalR nuovo. In questa colonna verrà approfondito macchine interna.

SignalR è un livello di astrazione bidirezionale, chiamate di procedure remote bidirezionale (RPC) e funziona su una varietà di protocolli di trasporto. È indipendente dall'host e non si limita a HTTP. Nella versione più recente, è possibile trasferire dati binari e non semplicemente JSON basate su messaggi. Quando si configura SignalR per ASP.NET o ASP.NET Core, è possibile selezionare il protocollo di trasporto e il protocollo di messaggio. Se non si apporta una scelta esplicita, il protocollo di trasporto viene scelto automaticamente e la maggior parte dei casi rivela WebSocket. Il protocollo di messaggio, al contrario, è basato su JSON. Diamo un'occhiata cosa accade quando un client, ad esempio, un client Web, ovvero consente di impostare una connessione con un endpoint del server. Il codice seguente viene avviata una connessione.

var progressConnection = new signalR.HubConnection("/progressDemo");
progressConnection.start();

Se si monitorano il traffico Web generato da questo codice con uno strumento come Fiddler, si noterà che vengono inviate due richieste HTTP. Figura 1 Mostra i dettagli della richiesta prima che avvia la conversazione.

Dettagli della richiesta di avvio iniziale
Figura 1 dettagli della richiesta di avvio iniziale

La richiesta iniziale è un POST HTTP destinata a route SignalR specificata nella classe di avvio seguito da un / negoziare segmento. Il codice seguente viene illustrato come definire una route SignalR:

app.UseSignalR(routes =>
{
  routes.MapHub<ProgressHub>("/progressDemo");
});

In base alla route, la chiamata iniziale utilizzerà l'URL: / progressdemo/negotiate.

Si noti che nelle versioni di anteprima di SignalR è stato utilizzato il verbo di opzioni per lo stesso scopo. L'endpoint del server di SignalR restituisce un oggetto JSON configurato nel modo seguente:

{
  "connectionId" : "b6668ac0-1083-499f-870a-2a5376bf5047",
  "availableTransports" : [
    "WebSockets", "ServerSentEvents", "LongPolling"
  ]
}

Come si può notare, la risposta JSON contiene due cose: l'ID univoco della connessione stabilita semplicemente e un elenco di protocolli di trasporto disponibili per l'utilizzo. Nell'esempio di codice indica che i WebSocket, ServerSentEvents e LongPolling può essere utilizzata la configurazione di client e server. Cosa si verifica in seguito dipende dal trasporto scelto dal client.

SignalR tende a usare i WebSocket se possibile. Se non viene verificato ServerSentEvents e dopo che il fallback a LongPolling. Se i WebSocket possono essere usati, una richiesta HTTP GET viene attivata allo stesso URL come prima. Questa volta la richiesta aggiunge inoltre l'ID di connessione come parametro di stringa di query. La richiesta di recupero è effettivamente una richiesta di aggiornamento di protocollo. Più precisamente, un aggiornamento di protocollo è normale HTTP richiesta (un'operazione GET ma possono anche essere un POST) con due intestazioni ad hoc. Uno è l'intestazione di connessione, che deve essere impostata con l'aggiornamento. L'altro è l'aggiornamento, che deve essere impostato sul nome del protocollo richiesto, ovvero in questo caso, i WebSocket. Se l'aggiornamento di protocollo viene accettata, il server restituisce una risposta HTTP 101 cambio protocolli (come illustrato figura 1).

Protocolli di trasporto

SignalR è possibile utilizzare vari protocolli di trasporto. Il client può imporre la connessione avvenga tramite un protocollo specifico, ma per impostazione predefinita il protocollo viene determinato automaticamente. Per richiedere un trasporto specifico, è sufficiente aggiungere un parametro supplementare al codice JavaScript (o se un client Web non viene usato il codice client). Ecco un esempio:

var progressConnection = new signalR.HubConnection(
  "/progressDemo",
  {transport : signalR.TransportType.WebSocket});

Si noti che passando una matrice anziché un nome diretto, è possibile limitare la scelta di uno dei pochi protocolli specificati. Naturalmente, i protocolli di trasporto si differenziano in alcuni aspetti. Figura 2 Elenca le caratteristiche principali di ogni protocollo.

Figura 2 supportati protocolli di trasporto

Protocollo Descrizione
WebSockets Basato su una connessione uno a uno tra il client e server. Client e server di scrittura su una pipe condivisa in modo che il flusso dei dati è bidirezionale. Il protocollo non può essere utilizzato ovunque ed è limitato dal browser e il server in uso per la connessione. Nel client, è richiesto un browser moderno. Le versioni più recenti di tutti i browser comuni in genere funzionano, fatta eccezione per Internet Explorer precedenti alla versione 10. Sul lato server, quando si utilizza IIS o HttpSysServer, è necessario Windows 8 o versione superiore sul client.
ServerSentEvents Basato sull'oggetto EventSource attiva nel server. L'oggetto rappresenta una pipe connettere il server al client. Una volta stabilita la connessione, il server può inviare in modo continuo eventi mentre il client può comunicare solo tramite le chiamate AJAX normale. Il protocollo date nuovamente i giorni iniziali di Netscape e non è supportato nei browser Internet Explorer o Edge.
LongPolling Il protocollo funziona aprendo una connessione con il server da utilizzare per le risposte del future. La connessione rimane in attesa fino a quando non viene inviata una risposta o la richiesta scade. In ogni caso, una volta chiusa la connessione, il client immediatamente ristabilisce, in modo che polling è continuo, ma il traffico è limitato a ciò che è strettamente necessaria. Questo protocollo funziona con tutte le versioni di tutti i browser e viene considerato una soluzione di fallback.

Se la comunicazione tra il client Web e il server è tra domini, il server deve essere abilitata la condivisione CORS. In questo caso, è possibile utilizzare dei protocolli disponibili (si noti che JSONP non è supportato in ASP.NET SignalR Core):

public void ConfigureServices(IServiceCollection services)
{
  services.AddCors();
}

Il browser aggiunge l'intestazione di origine per le chiamate AJAX e WebSockets di ASP.NET SignalR Core. Inoltre, è necessario che il middleware CORS configurato nell'applicazione SignalR per assicurarsi che il browser consente le richieste.

Protocolli di messaggio

SignalR in ASP.NET sempre serializzato scambiati i messaggi utilizzando il formato JSON basata su testo. La più recente dei componenti di base di ASP.NET SignalR aggiunge un protocollo di messaggi binari in base al formato MessagePack. Questo formato di serializzazione binaria consente lo scambio di dati in modo indipendente dalla lingua, molto modo JSON.

MessagePack è compact sia più veloce per il trasferimento a JSON e le dimensioni dei pacchetti di funzionalità che sono anche più compatto rispetto a JSON binario (BSON), ovvero la versione ottimizzata di MongoDB di JSON. Con MessagePack, small integer sia i valori NULL utilizzano un solo byte di dati. In confronto, i valori null JSON utilizza 4 byte. Per ulteriori informazioni sul protocollo, consultare msgpack.org.

Per utilizzare MessagePack da un client Web di ASP.NET Core SignalR, è sufficiente aggiungere un parametro più al codice JavaScript che consente di impostare la connessione, come illustrato di seguito:

var protocol = new signalR.protocols.msgpack.MessagePackHubProtocol();
var progressConnection = new signalR.HubConnection(
  "/progressDemo",
  {
    transport : signalR.TransportType.WebSocket,
    protocol : protocol
  }
);

Si noti che nel caso di un client Web desidero utilizzare MessagePack, è inoltre necessario includere un file JavaScript separato (signalr-msgpackprotocol.min.js) che trova nel pacchetto NPM @aspnet/signalr. MessagePack richiede inoltre che nel server di ASP.NET Core da configurare, come illustrato di seguito:

public void ConfigureServices(IServiceCollection services)
{
  // SignalR already configured. Just add this:
  services.AddMessagePackProtocol();
}

Se si utilizza un client non Web, è necessario eseguire altre operazioni per abilitare MessagePack è un'ulteriore chiamata nell'applicazione client. In particolare, si effettua una chiamata al metodo di estensione che withmessagepackprotocol definito nella classe HubConnectionBuilder.

Client non Web

L'aspetto più interessante della specifica del .NET Standard è che è possibile utilizzare la stessa libreria all'interno di una varietà di applicazioni client finché esiste compatibilità con le API. La libreria client di ASP.NET SignalR Core, è basata su .NET 2.0 Standard, può essere usata da tutte le applicazioni client compilate per un'ampia gamma di piattaforme compatibili, tra cui Microsoft .NET Framework 4.6.1 e versioni successive. Ciò significa che, ad esempio, un'applicazione Windows Forms compilata con le versioni di .NET Framework più recente rispetto a 4.6 invece possibile utilizzare i servizi di un hub di ASP.NET SignalR Core.

Tenendo in considerazione, informazioni su come avviare l'attività di lunga durata descritto nel mese ultimo e monitorarlo all'interno di una nuova applicazione Windows Form. Per iniziare, dopo aver creato lo scheletro di applicazione, fare riferimento il pacchetto NuGet denominato Microsoft.AspNetCore.SignalR.Client e tutte le relative dipendenze, come illustrato di seguito:

private static HubConnection _connection;
private async void Form1_Load(object sender, EventArgs e)
{
  _connection = new HubConnectionBuilder()
    .WithUrl("http://localhost:60000/progressdemo")
    .Build();
  await _connection.StartAsync();
}

Il codice viene eseguito quando il form viene caricata e stabilisce la connessione con l'endpoint di SignalR specificato. Se si desidera che i dati scambiati deve essere serializzato utilizzando il protocollo MessagePack, aggiungere una o più righe per il codice di configurazione dell'oggetto connessione generatore, come indicato di seguito:

private async void Form1_Load(object sender, EventArgs e)
{
  _connection = new HubConnectionBuilder()
    .WithUrl("http://localhost:60000/progressdemo")
    .WithMessagePackProtocol()
    .Build();
  await _connection.StartAsync();
}

L'oggetto di connessione che ricezione deve essere configurato ulteriormente con i gestori di lato client responsabili dell'aggiornamento dell'interfaccia utente quando le notifiche dall'endpoint di ASP.NET SignalR Core torna indietro. Ecco il codice:

_connection.On<int>("updateProgressBar", (perc) =>
{
  this.Invoke(
    (Action) (() => label1.Text = String.Format("{0}%", perc))
});

Nell'esempio di codice, quando viene ricevuta la notifica updateProgressBar, un'etichetta di testo viene aggiornata con il valore ricevuto che rappresenta la percentuale di lavoro attualmente eseguita. È possibile avere gestori tante come si necessità e l'espone controparte SignalR lato server. Figura 3 è illustrata la riscrittura completa del back-end SignalR dell'ultima colonna mese, comporta l'utilizzo un client Windows Form.

Figura 3 riscritto SignalR Back End

_connection.On("initProgressBar", () =>
{
  // Run on the UI thread
  Invoke((Action)(() => label1.Text = "0%"));
});
_connection.On<int>("updateProgressBar", (perc) =>
{
  // Run on the UI thread
  Invoke((Action) (() => label1.Text = String.Format("{0}%", perc)));
});
_connection.On("clearProgressBar", () =>
{
  // Run on the UI thread
  Invoke((Action)(() =>
  {
    label1.Text = "100%";
    button1.Enabled = true;
  }));
});
await _connection.StartAsync();

Esistono un paio di anomalie, che è necessario essere consapevoli di durante la scrittura dei client non - Web SignalR. In primo luogo, i gestori di client devono essere completamente configurati durante l'avvio della connessione. In particolare, ciò significa che la chiamata a StartAsync devono essere eseguiti dopo che tutte le chiamate al metodo nel < T > scadenza sono state apportate.

In secondo luogo, tenere presente che non si desidera eseguire lato server e possibilmente lunghe, operazione che SignalR informano sullo stesso thread dell'interfaccia utente di Windows. L'applicazione client che renderebbe non risponde. Per risolvere il problema, è necessario avviare l'operazione lato server in un altro thread, illustrato di seguito:

private void button1_Click(object sender, EventArgs e)
{
  Task.Run(() =>
  {
    var client = new WebClient();
    client.UploadString("http://localhost:60000/task/lengthy);
  });
}

Successivamente, quando l'hub di SignalR lato server notifica nuovamente, modifiche alla scadenza devono essere trasmesse al thread dell'interfaccia utente principale prima di tali eventi possono verificarsi. Eseguire questa operazione tramite il metodo Invoke nel gestore di client. Il metodo Invoke Ottiene un delegato e viene eseguita sul thread dell'interfaccia utente, come illustrato di seguito:

Invoke((Action)((perc) =>
  {
    label1.Text = String.Format("{0}%", perc);
  }));

Figura 4 Mostra l'applicazione Windows Forms di esempio in azione con un'etichetta progressivamente aggiornata con l'operazione lato server qualsiasi avanzamento del lavoro.

Applicazione Windows Form Client aggiornati da un Hub di SignalR Core ASP.NET
Figura 4 il Windows Form dell'applicazione Client aggiornati da un Hub di SignalR Core ASP.NET

L'applicazione Windows Forms può ricevere notifiche tramite uno degli approcci supportati: broadcast, connessione diretta, gruppi, singolo utente e lo streaming. Dispongo di più informazioni in una colonna future.

Conclusioni

SignalR ASP.NET Core supporta gli stessi protocolli di trasporto della versione precedente di ASP.NET, tra cui i WebSocket, ServerSentEvents e LongPolling. Inoltre, supporta un protocollo di messaggi binari, oltre il formato JSON standard.

Come il suo predecessore, ASP.NET SignalR Core può essere chiamato da una varietà di client diversi, tra cui le applicazioni Windows Forms risultare datate. La chiave per ottenere ampia compatibilità è supportata la specifica di .NET 2.0 Standard. Come abbiamo visto nell'articolo, se il client non è un'applicazione .NET Core, deve essere compilato per una versione di .NET Framework compatibile con lo standard più recente. La versione minima richiesta è .NET Framework 4.6.1.

Assicurarsi di estrarre il codice sorgente per questo articolo, è reperibile in bit.ly/2FxCKTs.


Dino Espositoha scritto più di 20 articoli e i manuali 1.000 in carriera 25 anni. Autore di "The Sabbatical Break," Mostra un stile: manifestazioni teatrali, Esposito è occupato la scrittura di software per un mondo ecologica come strategist digitale in BaxEnergy. Seguire quest'ultimo su Twitter: @despos.

Ringraziamenti esperto Microsoft seguente per la revisione dell'articolo: Andrew Stanton-infermiera


Viene illustrato in questo articolo nel forum di MSDN Magazine