Usare il protocollo hub MessagePack in SignalR per ASP.NET Core

Questo articolo presuppone che il lettore abbia familiarità con gli argomenti trattati in Introduzione a ASP.NET Core SignalR.

Che cos'è MessagePack?

MessagePack è un formato di serializzazione binario veloce e compatto. È utile quando le prestazioni e la larghezza di banda rappresentano un problema perché crea messaggi più piccoli rispetto a JSON. I messaggi binari sono illeggibili quando si esaminano le tracce di rete e i log, a meno che i byte non vengano passati tramite un parser MessagePack. SignalR include il supporto predefinito per il formato MessagePack e fornisce API per il client e il server da usare.

Configurare MessagePack nel server

Per abilitare il protocollo hub MessagePack nel server, installare il Microsoft.AspNetCore.SignalR.Protocols.MessagePack pacchetto nell'app. Startup.ConfigureServices Nel metodo aggiungere AddMessagePackProtocol alla AddSignalR chiamata per abilitare il supporto messagePack nel server.

services.AddSignalR()
    .AddMessagePackProtocol();

Nota

JSON è abilitato per impostazione predefinita. L'aggiunta di MessagePack abilita il supporto per i client JSON e MessagePack.

Per personalizzare il modo in cui MessagePack formatta i dati, AddMessagePackProtocol accetta un delegato per la configurazione delle opzioni. In tale delegato, la SerializerOptions proprietà viene utilizzata per configurare le opzioni di serializzazione messagePack. Per altre informazioni sul funzionamento dei resolver, visitare la libreria MessagePack in MessagePack-CSharp. Gli attributi possono essere usati negli oggetti da serializzare per definire la modalità di gestione.

services.AddSignalR()
    .AddMessagePackProtocol(options =>
    {
        options.SerializerOptions = MessagePackSerializerOptions.Standard
            .WithResolver(new CustomResolver())
            .WithSecurity(MessagePackSecurity.UntrustedData);
    });

Avviso

È consigliabile esaminare CVE-2020-5234 e applicare le patch consigliate. Ad esempio, chiamando .WithSecurity(MessagePackSecurity.UntrustedData) quando si sostituisce .SerializerOptions

Configurare MessagePack nel client

Nota

JSON è abilitato per impostazione predefinita per i client supportati. I client possono supportare un solo protocollo. L'aggiunta del supporto di MessagePack sostituisce tutti i protocolli configurati in precedenza.

Client .NET

Per abilitare MessagePack nel client .NET, installare il Microsoft.AspNetCore.SignalR.Protocols.MessagePack pacchetto e chiamare AddMessagePackProtocol su HubConnectionBuilder.

using Microsoft.AspNetCore.SignalR.Client;
using Microsoft.Extensions.DependencyInjection;

var hubConnection = new HubConnectionBuilder()
                        .WithUrl("/chathub")
                        .AddMessagePackProtocol()
                        .Build();

Nota

Questa AddMessagePackProtocol chiamata accetta un delegato per configurare le opzioni esattamente come il server.

Client JavaScript

Il supporto di MessagePack per il client JavaScript viene fornito dal pacchetto npm @microsoft/signalr-protocol-msgpack . Installare il pacchetto eseguendo il comando seguente in una shell dei comandi:

npm install @microsoft/signalr-protocol-msgpack

Dopo aver installato il pacchetto npm, il modulo può essere usato direttamente tramite un caricatore di moduli JavaScript o importato nel browser facendo riferimento al file seguente:

node_modules\@microsoft\signalr-protocol-msgpack\dist\browser\signalr-protocol-msgpack.js

Nell'ordine indicato di seguito è necessario fare riferimento ai file javaScript seguenti:

<script src="~/lib/signalr/signalr.js"></script>
<script src="~/lib/signalr/signalr-protocol-msgpack.js"></script>

L'aggiunta .withHubProtocol(new signalR.protocols.msgpack.MessagePackHubProtocol()) HubConnectionBuilder a configura il client per l'uso del protocollo MessagePack durante la connessione a un server.

const connection = new signalR.HubConnectionBuilder()
    .withUrl("/chathub")
    .withHubProtocol(new signalR.protocols.msgpack.MessagePackHubProtocol())
    .build();

Al momento, non sono disponibili opzioni di configurazione per il protocollo MessagePack nel client JavaScript.

Client Java

Per abilitare MessagePack con Java, installare il com.microsoft.signalr.messagepack pacchetto. Quando si usa Gradle, aggiungere la riga seguente alla dependencies sezione del file build.gradle :

implementation 'com.microsoft.signalr.messagepack:signalr-messagepack:5.0.0'

Quando si usa Maven, aggiungere le righe seguenti all'interno dell'elemento <dependencies> del pom.xml file:

<dependency>
    <groupId>com.microsoft.signalr.messagepack</groupId>
    <artifactId>signalr</artifactId>
    <version>5.0.0</version>
</dependency>

Chiamare withHubProtocol(new MessagePackHubProtocol()) su HubConnectionBuilder.

HubConnection messagePackConnection = HubConnectionBuilder.create("YOUR HUB URL HERE")
    .withHubProtocol(new MessagePackHubProtocol())
    .build();

Considerazioni su MessagePack

Esistono alcuni problemi da tenere presenti quando si usa il protocollo hub MessagePack.

MessagePack fa distinzione tra maiuscole e minuscole

Il protocollo MessagePack fa distinzione tra maiuscole e minuscole. Si consideri ad esempio la classe C# seguente:

public class ChatMessage
{
    public string Sender { get; }
    public string Message { get; }
}

Quando si invia dal client JavaScript, è necessario usare PascalCased i nomi delle proprietà, perché la combinazione di maiuscole e minuscole deve corrispondere esattamente alla classe C#. Ad esempio:

connection.invoke("SomeMethod", { Sender: "Sally", Message: "Hello!" });

L'uso dei camelCased nomi non verrà associato correttamente alla classe C#. È possibile risolvere questo problema usando l'attributo Key per specificare un nome diverso per la proprietà MessagePack. Per altre informazioni, vedere la documentazione di MessagePack-CSharp.

DateTime.Kind non viene mantenuto durante la serializzazione/deserializzazione

Il protocollo MessagePack non fornisce un modo per codificare il Kind valore di un oggetto DateTime. Di conseguenza, quando si deserializza una data, il protocollo dell'hub MessagePack verrà convertito nel formato UTC se in DateTime.Kind DateTimeKind.Local caso contrario non tocca l'ora e lo passerà così com'è. Se si utilizzano DateTime valori, è consigliabile eseguire la conversione in formato UTC prima di inviarli. Convertirli dall'ora UTC all'ora locale quando li ricevi.

Supporto di MessagePack nell'ambiente di compilazione "in anticipo"

La libreria MessagePack-CSharp usata dal client e dal server .NET usa la generazione di codice per ottimizzare la serializzazione. Di conseguenza, non è supportato per impostazione predefinita in ambienti che usano la compilazione "in anticipo", ad esempio Xamarin iOS o Unity. È possibile usare MessagePack in questi ambienti "pregenerando" il codice serializzatore/deserializzatore. Per altre informazioni, vedere la documentazione di MessagePack-CSharp. Dopo aver pregenerato i serializzatori, è possibile registrarli usando il delegato di configurazione passato a AddMessagePackProtocol:

services.AddSignalR()
    .AddMessagePackProtocol(options =>
    {
        StaticCompositeResolver.Instance.Register(
            MessagePack.Resolvers.GeneratedResolver.Instance,
            MessagePack.Resolvers.StandardResolver.Instance
        );
        options.SerializerOptions = MessagePackSerializerOptions.Standard
            .WithResolver(StaticCompositeResolver.Instance)
            .WithSecurity(MessagePackSecurity.UntrustedData);
    });

I controlli dei tipi sono più rigorosi in MessagePack

Il protocollo dell'hub JSON eseguirà conversioni di tipi durante la deserializzazione. Ad esempio, se l'oggetto in ingresso ha un valore di proprietà che è un numero ({ foo: 42 }) ma la proprietà nella classe .NET è di tipo string, il valore verrà convertito. MessagePack, tuttavia, non esegue questa conversione e genererà un'eccezione che può essere visualizzata nei log lato server (e nella console):

InvalidDataException: Error binding arguments. Make sure that the types of the provided values match the types of the hub method being invoked.

Per altre informazioni su questa limitazione, vedere Problema di GitHub aspnet/SignalR#2937.

Caratteri e stringhe in Java

Nel client Java gli char oggetti verranno serializzati come oggetti un carattere String . Questo è in contrasto con il client C# e JavaScript, che li serializza come short oggetti. La specifica MessagePack stessa non definisce il comportamento per char gli oggetti, quindi spetta all'autore della libreria determinare come serializzarle. La differenza di comportamento tra i client è il risultato delle librerie usate per le implementazioni.

Risorse aggiuntive

Questo articolo presuppone che il lettore abbia familiarità con gli argomenti trattati in Introduzione a ASP.NET Core SignalR.

Che cos'è MessagePack?

MessagePack è un formato di serializzazione binario veloce e compatto. È utile quando le prestazioni e la larghezza di banda rappresentano un problema perché crea messaggi più piccoli rispetto a JSON. I messaggi binari sono illeggibili quando si esaminano le tracce di rete e i log, a meno che i byte non vengano passati tramite un parser MessagePack. SignalR include il supporto predefinito per il formato MessagePack e fornisce API per il client e il server da usare.

Configurare MessagePack nel server

Per abilitare il protocollo hub MessagePack nel server, installare il Microsoft.AspNetCore.SignalR.Protocols.MessagePack pacchetto nell'app. Startup.ConfigureServices Nel metodo aggiungere AddMessagePackProtocol alla AddSignalR chiamata per abilitare il supporto messagePack nel server.

Nota

JSON è abilitato per impostazione predefinita. L'aggiunta di MessagePack abilita il supporto per i client JSON e MessagePack.

services.AddSignalR()
    .AddMessagePackProtocol();

Per personalizzare la modalità di formattazione dei dati di MessagePack, AddMessagePackProtocol accetta un delegato per la configurazione delle opzioni. In tale delegato, la SerializerOptions proprietà può essere utilizzata per configurare le opzioni di serializzazione messagePack. Per altre informazioni sul funzionamento dei resolver, visitare la libreria MessagePack in MessagePack-CSharp. Gli attributi possono essere usati negli oggetti da serializzare per definire la modalità di gestione.

services.AddSignalR()
    .AddMessagePackProtocol(options =>
    {
        options.SerializerOptions = MessagePackSerializerOptions.Standard
            .WithResolver(new CustomResolver())
            .WithSecurity(MessagePackSecurity.UntrustedData);
    });

Avviso

È consigliabile esaminare CVE-2020-5234 e applicare le patch consigliate. Ad esempio, chiamando .WithSecurity(MessagePackSecurity.UntrustedData) quando si sostituisce .SerializerOptions

Configurare MessagePack nel client

Nota

JSON è abilitato per impostazione predefinita per i client supportati. I client possono supportare un solo protocollo. L'aggiunta del supporto messagePack sostituirà tutti i protocolli configurati in precedenza.

Client .NET

Per abilitare MessagePack nel client .NET, installare il Microsoft.AspNetCore.SignalR.Protocols.MessagePack pacchetto e chiamare AddMessagePackProtocol su HubConnectionBuilder.

using Microsoft.AspNetCore.SignalR.Client;
using Microsoft.Extensions.DependencyInjection;

var hubConnection = new HubConnectionBuilder()
                        .WithUrl("/chathub")
                        .AddMessagePackProtocol()
                        .Build();

Nota

Questa AddMessagePackProtocol chiamata accetta un delegato per configurare le opzioni esattamente come il server.

Client JavaScript

Il supporto di MessagePack per il client JavaScript viene fornito dal pacchetto npm @microsoft/signalr-protocol-msgpack . Installare il pacchetto eseguendo il comando seguente in una shell dei comandi:

npm install @microsoft/signalr-protocol-msgpack

Dopo aver installato il pacchetto npm, il modulo può essere usato direttamente tramite un caricatore di moduli JavaScript o importato nel browser facendo riferimento al file seguente:

node_modules\@microsoft\signalr-protocol-msgpack\dist\browser\signalr-protocol-msgpack.js

In un browser è necessario fare riferimento anche alla msgpack5 libreria. Usare un <script> tag per creare un riferimento. La libreria è disponibile in node_modules\msgpack5\dist\msgpack5.js.

Nota

Quando si usa l'elemento , l'ordine <script> è importante. Se signalr-protocol-msgpack.js viene fatto riferimento prima msgpack5.jsdi , si verifica un errore durante il tentativo di connessione con MessagePack. signalr.js è necessario anche prima signalr-protocol-msgpack.jsdi .

<script src="~/lib/signalr/signalr.js"></script>
<script src="~/lib/msgpack5/msgpack5.js"></script>
<script src="~/lib/signalr/signalr-protocol-msgpack.js"></script>

L'aggiunta .withHubProtocol(new signalR.protocols.msgpack.MessagePackHubProtocol()) HubConnectionBuilder a configurerà il client per l'uso del protocollo MessagePack durante la connessione a un server.

const connection = new signalR.HubConnectionBuilder()
    .withUrl("/chathub")
    .withHubProtocol(new signalR.protocols.msgpack.MessagePackHubProtocol())
    .build();

Nota

Al momento, non sono disponibili opzioni di configurazione per il protocollo MessagePack nel client JavaScript.

Client Java

Per abilitare MessagePack con Java, installare il com.microsoft.signalr.messagepack pacchetto. Quando si usa Gradle, aggiungere la riga seguente alla dependencies sezione del file build.gradle :

implementation 'com.microsoft.signalr.messagepack:signalr-messagepack:5.0.0'

Quando si usa Maven, aggiungere le righe seguenti all'interno dell'elemento <dependencies> del pom.xml file:

<dependency>
    <groupId>com.microsoft.signalr.messagepack</groupId>
    <artifactId>signalr</artifactId>
    <version>5.0.0</version>
</dependency>

Chiamare withHubProtocol(new MessagePackHubProtocol()) su HubConnectionBuilder.

HubConnection messagePackConnection = HubConnectionBuilder.create("YOUR HUB URL HERE")
    .withHubProtocol(new MessagePackHubProtocol())
    .build();

Considerazioni su MessagePack

Esistono alcuni problemi da tenere presenti quando si usa il protocollo hub MessagePack.

MessagePack fa distinzione tra maiuscole e minuscole

Il protocollo MessagePack fa distinzione tra maiuscole e minuscole. Si consideri ad esempio la classe C# seguente:

public class ChatMessage
{
    public string Sender { get; }
    public string Message { get; }
}

Quando si invia dal client JavaScript, è necessario usare PascalCased i nomi delle proprietà, perché la combinazione di maiuscole e minuscole deve corrispondere esattamente alla classe C#. Ad esempio:

connection.invoke("SomeMethod", { Sender: "Sally", Message: "Hello!" });

L'uso dei camelCased nomi non verrà associato correttamente alla classe C#. È possibile risolvere questo problema usando l'attributo Key per specificare un nome diverso per la proprietà MessagePack. Per altre informazioni, vedere la documentazione di MessagePack-CSharp.

DateTime.Kind non viene mantenuto durante la serializzazione/deserializzazione

Il protocollo MessagePack non fornisce un modo per codificare il Kind valore di un oggetto DateTime. Di conseguenza, quando si deserializza una data, il protocollo dell'hub MessagePack verrà convertito nel formato UTC se in DateTime.Kind DateTimeKind.Local caso contrario non tocca l'ora e lo passerà così com'è. Se si utilizzano DateTime valori, è consigliabile eseguire la conversione in formato UTC prima di inviarli. Convertirli dall'ora UTC all'ora locale quando li ricevi.

DateTime.MinValue non è supportato da MessagePack in JavaScript

La libreria msgpack5 usata dal SignalR client JavaScript non supporta il timestamp96 tipo in MessagePack. Questo tipo viene usato per codificare valori di data molto grandi (molto presto nel passato o molto lontano in futuro). Il valore di DateTime.MinValue è January 1, 0001, che deve essere codificato in un timestamp96 valore. Per questo motivo, l'invio DateTime.MinValue a un client JavaScript non è supportato. Quando DateTime.MinValue viene ricevuto dal client JavaScript, viene generato l'errore seguente:

Uncaught Error: unable to find ext type 255 at decoder.js:427

In genere, DateTime.MinValue viene usato per codificare un valore o null "mancante". Se è necessario codificare tale valore in MessagePack, usare un valore nullable DateTime (DateTime?) o codificare un valore separato bool che indica se la data è presente.

Per altre informazioni su questa limitazione, vedere Problema di GitHub aspnet/SignalR#2228.

Supporto di MessagePack nell'ambiente di compilazione "in anticipo"

La libreria MessagePack-CSharp usata dal client e dal server .NET usa la generazione di codice per ottimizzare la serializzazione. Di conseguenza, non è supportato per impostazione predefinita in ambienti che usano la compilazione "in anticipo", ad esempio Xamarin iOS o Unity. È possibile usare MessagePack in questi ambienti "pregenerando" il codice serializzatore/deserializzatore. Per altre informazioni, vedere la documentazione di MessagePack-CSharp. Dopo aver pregenerato i serializzatori, è possibile registrarli usando il delegato di configurazione passato a AddMessagePackProtocol:

services.AddSignalR()
    .AddMessagePackProtocol(options =>
    {
        StaticCompositeResolver.Instance.Register(
            MessagePack.Resolvers.GeneratedResolver.Instance,
            MessagePack.Resolvers.StandardResolver.Instance
        );
        options.SerializerOptions = MessagePackSerializerOptions.Standard
            .WithResolver(StaticCompositeResolver.Instance)
            .WithSecurity(MessagePackSecurity.UntrustedData);
    });

I controlli dei tipi sono più rigorosi in MessagePack

Il protocollo dell'hub JSON eseguirà conversioni di tipi durante la deserializzazione. Ad esempio, se l'oggetto in ingresso ha un valore di proprietà che è un numero ({ foo: 42 }) ma la proprietà nella classe .NET è di tipo string, il valore verrà convertito. MessagePack, tuttavia, non esegue questa conversione e genererà un'eccezione che può essere visualizzata nei log lato server (e nella console):

InvalidDataException: Error binding arguments. Make sure that the types of the provided values match the types of the hub method being invoked.

Per altre informazioni su questa limitazione, vedere Problema di GitHub aspnet/SignalR#2937.

Caratteri e stringhe in Java

Nel client Java gli char oggetti verranno serializzati come oggetti un carattere String . Questo è in contrasto con il client C# e JavaScript, che li serializza come short oggetti. La specifica MessagePack stessa non definisce il comportamento per char gli oggetti, quindi spetta all'autore della libreria determinare come serializzarle. La differenza di comportamento tra i client è il risultato delle librerie usate per le implementazioni.

Risorse aggiuntive

Questo articolo presuppone che il lettore abbia familiarità con gli argomenti trattati in Introduzione a ASP.NET Core SignalR.

Che cos'è MessagePack?

MessagePack è un formato di serializzazione binario veloce e compatto. È utile quando le prestazioni e la larghezza di banda rappresentano un problema perché crea messaggi più piccoli rispetto a JSON. I messaggi binari sono illeggibili quando si esaminano le tracce di rete e i log, a meno che i byte non vengano passati tramite un parser MessagePack. SignalR include il supporto predefinito per il formato MessagePack e fornisce API per il client e il server da usare.

Configurare MessagePack nel server

Per abilitare il protocollo hub MessagePack nel server, installare il Microsoft.AspNetCore.SignalR.Protocols.MessagePack pacchetto nell'app. Startup.ConfigureServices Nel metodo aggiungere AddMessagePackProtocol alla AddSignalR chiamata per abilitare il supporto messagePack nel server.

Nota

JSON è abilitato per impostazione predefinita. L'aggiunta di MessagePack abilita il supporto per i client JSON e MessagePack.

services.AddSignalR()
    .AddMessagePackProtocol();

Per personalizzare la modalità di formattazione dei dati di MessagePack, AddMessagePackProtocol accetta un delegato per la configurazione delle opzioni. In tale delegato, la FormatterResolvers proprietà può essere utilizzata per configurare le opzioni di serializzazione messagePack. Per altre informazioni sul funzionamento dei resolver, visitare la libreria MessagePack in MessagePack-CSharp. Gli attributi possono essere usati negli oggetti da serializzare per definire la modalità di gestione.

services.AddSignalR()
    .AddMessagePackProtocol(options =>
    {
        options.FormatterResolvers = new List<MessagePack.IFormatterResolver>()
        {
            MessagePack.Resolvers.StandardResolver.Instance
        };
    });

Avviso

È consigliabile esaminare CVE-2020-5234 e applicare le patch consigliate. Ad esempio, impostando la MessagePackSecurity.Active proprietà statica su MessagePackSecurity.UntrustedData. L'impostazione di richiede l'installazione MessagePackSecurity.Active manuale di una versione 1.9.x di MessagePack. L'installazione MessagePack di 1.9.x consente di aggiornare la versione SignalR usata. MessagePack La versione 2.x ha introdotto modifiche di rilievo ed è incompatibile con SignalR le versioni 3.1 e precedenti. Quando MessagePackSecurity.Active non è impostato su MessagePackSecurity.UntrustedData, un client dannoso potrebbe causare un attacco Denial of Service. Impostare MessagePackSecurity.Active in Program.Main, come illustrato nel codice seguente:

using MessagePack;

public static void Main(string[] args)
{
  MessagePackSecurity.Active = MessagePackSecurity.UntrustedData;

  CreateHostBuilder(args).Build().Run();
}

Configurare MessagePack nel client

Nota

JSON è abilitato per impostazione predefinita per i client supportati. I client possono supportare un solo protocollo. L'aggiunta del supporto messagePack sostituirà tutti i protocolli configurati in precedenza.

Client .NET

Per abilitare MessagePack nel client .NET, installare il Microsoft.AspNetCore.SignalR.Protocols.MessagePack pacchetto e chiamare AddMessagePackProtocol su HubConnectionBuilder.

using Microsoft.AspNetCore.SignalR.Client;
using Microsoft.Extensions.DependencyInjection;

var hubConnection = new HubConnectionBuilder()
                        .WithUrl("/chathub")
                        .AddMessagePackProtocol()
                        .Build();

Nota

Questa AddMessagePackProtocol chiamata accetta un delegato per configurare le opzioni esattamente come il server.

Client JavaScript

Il supporto di MessagePack per il client JavaScript viene fornito dal pacchetto npm @microsoft/signalr-protocol-msgpack . Installare il pacchetto eseguendo il comando seguente in una shell dei comandi:

npm install @microsoft/signalr-protocol-msgpack

Dopo aver installato il pacchetto npm, il modulo può essere usato direttamente tramite un caricatore di moduli JavaScript o importato nel browser facendo riferimento al file seguente:

node_modules\@microsoft\signalr-protocol-msgpack\dist\browser\signalr-protocol-msgpack.js

In un browser è necessario fare riferimento anche alla msgpack5 libreria. Usare un <script> tag per creare un riferimento. La libreria è disponibile in node_modules\msgpack5\dist\msgpack5.js.

Nota

Quando si usa l'elemento , l'ordine <script> è importante. Se signalr-protocol-msgpack.js viene fatto riferimento prima msgpack5.jsdi , si verifica un errore durante il tentativo di connessione con MessagePack. signalr.js è necessario anche prima signalr-protocol-msgpack.jsdi .

<script src="~/lib/signalr/signalr.js"></script>
<script src="~/lib/msgpack5/msgpack5.js"></script>
<script src="~/lib/signalr/signalr-protocol-msgpack.js"></script>

L'aggiunta .withHubProtocol(new signalR.protocols.msgpack.MessagePackHubProtocol()) HubConnectionBuilder a configurerà il client per l'uso del protocollo MessagePack durante la connessione a un server.

const connection = new signalR.HubConnectionBuilder()
    .withUrl("/chathub")
    .withHubProtocol(new signalR.protocols.msgpack.MessagePackHubProtocol())
    .build();

Nota

Al momento, non sono disponibili opzioni di configurazione per il protocollo MessagePack nel client JavaScript.

Considerazioni su MessagePack

Esistono alcuni problemi da tenere presenti quando si usa il protocollo hub MessagePack.

MessagePack fa distinzione tra maiuscole e minuscole

Il protocollo MessagePack fa distinzione tra maiuscole e minuscole. Si consideri ad esempio la classe C# seguente:

public class ChatMessage
{
    public string Sender { get; }
    public string Message { get; }
}

Quando si invia dal client JavaScript, è necessario usare PascalCased i nomi delle proprietà, perché la combinazione di maiuscole e minuscole deve corrispondere esattamente alla classe C#. Ad esempio:

connection.invoke("SomeMethod", { Sender: "Sally", Message: "Hello!" });

L'uso dei camelCased nomi non verrà associato correttamente alla classe C#. È possibile risolvere questo problema usando l'attributo Key per specificare un nome diverso per la proprietà MessagePack. Per altre informazioni, vedere la documentazione di MessagePack-CSharp.

DateTime.Kind non viene mantenuto durante la serializzazione/deserializzazione

Il protocollo MessagePack non fornisce un modo per codificare il Kind valore di un oggetto DateTime. Di conseguenza, quando si deserializza una data, il protocollo hub MessagePack presuppone che la data in ingresso sia in formato UTC. Se si lavora con DateTime i valori nell'ora locale, è consigliabile eseguire la conversione in formato UTC prima di inviarli. Convertirli dall'ora UTC all'ora locale quando li ricevi.

Per altre informazioni su questa limitazione, vedere Problema di GitHub aspnet/SignalR#2632.

DateTime.MinValue non è supportato da MessagePack in JavaScript

La libreria msgpack5 usata dal SignalR client JavaScript non supporta il timestamp96 tipo in MessagePack. Questo tipo viene usato per codificare valori di data molto grandi (molto presto nel passato o molto lontano in futuro). Il valore di DateTime.MinValue è January 1, 0001, che deve essere codificato in un timestamp96 valore. Per questo motivo, l'invio DateTime.MinValue a un client JavaScript non è supportato. Quando DateTime.MinValue viene ricevuto dal client JavaScript, viene generato l'errore seguente:

Uncaught Error: unable to find ext type 255 at decoder.js:427

In genere, DateTime.MinValue viene usato per codificare un valore o null "mancante". Se è necessario codificare tale valore in MessagePack, usare un valore nullable DateTime (DateTime?) o codificare un valore separato bool che indica se la data è presente.

Per altre informazioni su questa limitazione, vedere Problema di GitHub aspnet/SignalR#2228.

Supporto di MessagePack nell'ambiente di compilazione "in anticipo"

La libreria MessagePack-CSharp usata dal client e dal server .NET usa la generazione di codice per ottimizzare la serializzazione. Di conseguenza, non è supportato per impostazione predefinita in ambienti che usano la compilazione "in anticipo", ad esempio Xamarin iOS o Unity. È possibile usare MessagePack in questi ambienti "pregenerando" il codice serializzatore/deserializzatore. Per altre informazioni, vedere la documentazione di MessagePack-CSharp. Dopo aver pregenerato i serializzatori, è possibile registrarli usando il delegato di configurazione passato a AddMessagePackProtocol:

services.AddSignalR()
    .AddMessagePackProtocol(options =>
    {
        options.FormatterResolvers = new List<MessagePack.IFormatterResolver>()
        {
            MessagePack.Resolvers.GeneratedResolver.Instance,
            MessagePack.Resolvers.StandardResolver.Instance
        };
    });

I controlli dei tipi sono più rigorosi in MessagePack

Il protocollo dell'hub JSON eseguirà conversioni di tipi durante la deserializzazione. Ad esempio, se l'oggetto in ingresso ha un valore di proprietà che è un numero ({ foo: 42 }) ma la proprietà nella classe .NET è di tipo string, il valore verrà convertito. MessagePack, tuttavia, non esegue questa conversione e genererà un'eccezione che può essere visualizzata nei log lato server (e nella console):

InvalidDataException: Error binding arguments. Make sure that the types of the provided values match the types of the hub method being invoked.

Per altre informazioni su questa limitazione, vedere Problema di GitHub aspnet/SignalR#2937.

Risorse aggiuntive

Questo articolo presuppone che il lettore abbia familiarità con gli argomenti trattati in Introduzione a ASP.NET Core SignalR.

Che cos'è MessagePack?

MessagePack è un formato di serializzazione binario veloce e compatto. È utile quando le prestazioni e la larghezza di banda rappresentano un problema perché crea messaggi più piccoli rispetto a JSON. I messaggi binari sono illeggibili quando si esaminano le tracce di rete e i log, a meno che i byte non vengano passati tramite un parser MessagePack. SignalR include il supporto predefinito per il formato MessagePack e fornisce API per il client e il server da usare.

Configurare MessagePack nel server

Per abilitare il protocollo hub MessagePack nel server, installare il Microsoft.AspNetCore.SignalR.Protocols.MessagePack pacchetto nell'app. Startup.ConfigureServices Nel metodo aggiungere AddMessagePackProtocol alla AddSignalR chiamata per abilitare il supporto messagePack nel server.

Nota

JSON è abilitato per impostazione predefinita. L'aggiunta di MessagePack abilita il supporto per i client JSON e MessagePack.

services.AddSignalR()
    .AddMessagePackProtocol();

Per personalizzare la modalità di formattazione dei dati di MessagePack, AddMessagePackProtocol accetta un delegato per la configurazione delle opzioni. In tale delegato, la FormatterResolvers proprietà può essere utilizzata per configurare le opzioni di serializzazione messagePack. Per altre informazioni sul funzionamento dei resolver, visitare la libreria MessagePack in MessagePack-CSharp. Gli attributi possono essere usati negli oggetti da serializzare per definire la modalità di gestione.

services.AddSignalR()
    .AddMessagePackProtocol(options =>
    {
        options.FormatterResolvers = new List<MessagePack.IFormatterResolver>()
        {
            MessagePack.Resolvers.StandardResolver.Instance
        };
    });

Avviso

È consigliabile esaminare CVE-2020-5234 e applicare le patch consigliate. Ad esempio, impostando la MessagePackSecurity.Active proprietà statica su MessagePackSecurity.UntrustedData. L'impostazione di richiede l'installazione MessagePackSecurity.Active manuale di una versione 1.9.x di MessagePack. L'installazione MessagePack di 1.9.x consente di aggiornare la versione SignalR usata. Quando MessagePackSecurity.Active non è impostato su MessagePackSecurity.UntrustedData, un client dannoso potrebbe causare un attacco Denial of Service. Impostare MessagePackSecurity.Active in Program.Main, come illustrato nel codice seguente:

using MessagePack;

public static void Main(string[] args)
{
  MessagePackSecurity.Active = MessagePackSecurity.UntrustedData;

  CreateHostBuilder(args).Build().Run();
}

Configurare MessagePack nel client

Nota

JSON è abilitato per impostazione predefinita per i client supportati. I client possono supportare un solo protocollo. L'aggiunta del supporto messagePack sostituirà tutti i protocolli configurati in precedenza.

Client .NET

Per abilitare MessagePack nel client .NET, installare il Microsoft.AspNetCore.SignalR.Protocols.MessagePack pacchetto e chiamare AddMessagePackProtocol su HubConnectionBuilder.

using Microsoft.AspNetCore.SignalR.Client;
using Microsoft.Extensions.DependencyInjection;

var hubConnection = new HubConnectionBuilder()
                        .WithUrl("/chathub")
                        .AddMessagePackProtocol()
                        .Build();

Nota

Questa AddMessagePackProtocol chiamata accetta un delegato per configurare le opzioni esattamente come il server.

Client JavaScript

Il supporto di MessagePack per il client JavaScript viene fornito dal pacchetto npm @aspnet/signalr-protocol-msgpack . Installare il pacchetto eseguendo il comando seguente in una shell dei comandi:

npm install @aspnet/signalr-protocol-msgpack

Dopo aver installato il pacchetto npm, il modulo può essere usato direttamente tramite un caricatore di moduli JavaScript o importato nel browser facendo riferimento al file seguente:

node_modules\@aspnet\signalr-protocol-msgpack\dist\browser\signalr-protocol-msgpack.js

In un browser è necessario fare riferimento anche alla msgpack5 libreria. Usare un <script> tag per creare un riferimento. La libreria è disponibile in node_modules\msgpack5\dist\msgpack5.js.

Nota

Quando si usa l'elemento , l'ordine <script> è importante. Se signalr-protocol-msgpack.js viene fatto riferimento prima msgpack5.jsdi , si verifica un errore durante il tentativo di connessione con MessagePack. signalr.js è necessario anche prima signalr-protocol-msgpack.jsdi .

<script src="~/lib/signalr/signalr.js"></script>
<script src="~/lib/msgpack5/msgpack5.js"></script>
<script src="~/lib/signalr/signalr-protocol-msgpack.js"></script>

L'aggiunta .withHubProtocol(new signalR.protocols.msgpack.MessagePackHubProtocol()) HubConnectionBuilder a configurerà il client per l'uso del protocollo MessagePack durante la connessione a un server.

const connection = new signalR.HubConnectionBuilder()
    .withUrl("/chathub")
    .withHubProtocol(new signalR.protocols.msgpack.MessagePackHubProtocol())
    .build();

Nota

Al momento, non sono disponibili opzioni di configurazione per il protocollo MessagePack nel client JavaScript.

Considerazioni su MessagePack

Esistono alcuni problemi da tenere presenti quando si usa il protocollo hub MessagePack.

MessagePack fa distinzione tra maiuscole e minuscole

Il protocollo MessagePack fa distinzione tra maiuscole e minuscole. Si consideri ad esempio la classe C# seguente:

public class ChatMessage
{
    public string Sender { get; }
    public string Message { get; }
}

Quando si invia dal client JavaScript, è necessario usare PascalCased i nomi delle proprietà, perché la combinazione di maiuscole e minuscole deve corrispondere esattamente alla classe C#. Ad esempio:

connection.invoke("SomeMethod", { Sender: "Sally", Message: "Hello!" });

L'uso dei camelCased nomi non verrà associato correttamente alla classe C#. È possibile risolvere questo problema usando l'attributo Key per specificare un nome diverso per la proprietà MessagePack. Per altre informazioni, vedere la documentazione di MessagePack-CSharp.

DateTime.Kind non viene mantenuto durante la serializzazione/deserializzazione

Il protocollo MessagePack non fornisce un modo per codificare il Kind valore di un oggetto DateTime. Di conseguenza, quando si deserializza una data, il protocollo hub MessagePack presuppone che la data in ingresso sia in formato UTC. Se si lavora con DateTime i valori nell'ora locale, è consigliabile eseguire la conversione in formato UTC prima di inviarli. Convertirli dall'ora UTC all'ora locale quando li ricevi.

Per altre informazioni su questa limitazione, vedere Problema di GitHub aspnet/SignalR#2632.

DateTime.MinValue non è supportato da MessagePack in JavaScript

La libreria msgpack5 usata dal SignalR client JavaScript non supporta il timestamp96 tipo in MessagePack. Questo tipo viene usato per codificare valori di data molto grandi (molto presto nel passato o molto lontano in futuro). Il valore di DateTime.MinValue è January 1, 0001 che deve essere codificato in un timestamp96 valore. Per questo motivo, l'invio DateTime.MinValue a un client JavaScript non è supportato. Quando DateTime.MinValue viene ricevuto dal client JavaScript, viene generato l'errore seguente:

Uncaught Error: unable to find ext type 255 at decoder.js:427

In genere, DateTime.MinValue viene usato per codificare un valore o null "mancante". Se è necessario codificare tale valore in MessagePack, usare un valore nullable DateTime (DateTime?) o codificare un valore separato bool che indica se la data è presente.

Per altre informazioni su questa limitazione, vedere Problema di GitHub aspnet/SignalR#2228.

Supporto di MessagePack nell'ambiente di compilazione "in anticipo"

La libreria MessagePack-CSharp usata dal client e dal server .NET usa la generazione di codice per ottimizzare la serializzazione. Di conseguenza, non è supportato per impostazione predefinita in ambienti che usano la compilazione "in anticipo", ad esempio Xamarin iOS o Unity. È possibile usare MessagePack in questi ambienti "pregenerando" il codice serializzatore/deserializzatore. Per altre informazioni, vedere la documentazione di MessagePack-CSharp. Dopo aver pregenerato i serializzatori, è possibile registrarli usando il delegato di configurazione passato a AddMessagePackProtocol:

services.AddSignalR()
    .AddMessagePackProtocol(options =>
    {
        options.FormatterResolvers = new List<MessagePack.IFormatterResolver>()
        {
            MessagePack.Resolvers.GeneratedResolver.Instance,
            MessagePack.Resolvers.StandardResolver.Instance
        };
    });

I controlli dei tipi sono più rigorosi in MessagePack

Il protocollo dell'hub JSON eseguirà conversioni di tipi durante la deserializzazione. Ad esempio, se l'oggetto in ingresso ha un valore di proprietà che è un numero ({ foo: 42 }) ma la proprietà nella classe .NET è di tipo string, il valore verrà convertito. MessagePack, tuttavia, non esegue questa conversione e genererà un'eccezione che può essere visualizzata nei log lato server (e nella console):

InvalidDataException: Error binding arguments. Make sure that the types of the provided values match the types of the hub method being invoked.

Per altre informazioni su questa limitazione, vedere Problema di GitHub aspnet/SignalR#2937.

Risorse aggiuntive