Utiliser le protocole MessagePack Hub dans SignalR pour ASP.NET Core

Cet article part du principe que le lecteur est familiarisé avec les rubriques abordées dans Bien démarrer avec ASP.NET Core SignalR.

Qu’est-ce que MessagePack ?

MessagePack est un format de sérialisation binaire rapide et compact. Il est utile lorsque les performances et la bande passante sont un problème, car il crée des messages plus petits que JSON. Les messages binaires sont illisibles lors de l’analyse des traces réseau et des journaux, sauf si les octets sont transmis via un analyseur MessagePack. SignalR prend en charge le format MessagePack et fournit des API que le client et le serveur peuvent utiliser.

Configurer MessagePack sur le serveur

Pour activer le protocole MessagePack Hub sur le serveur, installez le package Microsoft.AspNetCore.SignalR.Protocols.MessagePack dans votre application. Dans la méthode Startup.ConfigureServices, ajoutez AddMessagePackProtocol à l’appel AddSignalR pour activer la prise en charge de MessagePack sur le serveur.

services.AddSignalR()
    .AddMessagePackProtocol();

Notes

JSON est activé par défaut. L’ajout de MessagePack permet de prendre en charge les clients JSON et MessagePack.

Pour personnaliser la façon dont MessagePack met en forme les données, AddMessagePackProtocol prend un délégué pour la configuration des options. Dans ce délégué, la propriété SerializerOptions est utilisée pour configurer les options de sérialisation MessagePack. Pour plus d’informations sur le fonctionnement des résolveurs, consultez la bibliothèque MessagePack sur MessagePack-CSharp. Les attributs peuvent être utilisés sur les objets que vous souhaitez sérialiser pour définir la façon dont ils doivent être gérés.

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

Avertissement

Nous vous recommandons vivement d’examiner CVE-2020-5234 et d’appliquer les correctifs recommandés. Par exemple, appelez .WithSecurity(MessagePackSecurity.UntrustedData) lors du remplacement de SerializerOptions.

Configurer MessagePack sur le client

Notes

JSON est activé par défaut pour les clients pris en charge. Les clients ne peuvent prendre en charge qu’un seul protocole. L’ajout de la prise en charge de MessagePack remplace tous les protocoles configurés précédemment.

Client .NET

Pour activer MessagePack dans le client .NET, installez le package Microsoft.AspNetCore.SignalR.Protocols.MessagePack et appelez AddMessagePackProtocol sur HubConnectionBuilder.

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

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

Notes

Cet appel AddMessagePackProtocol prend un délégué pour configurer les options comme le serveur.

Client JavaScript

La prise en charge de MessagePack pour le client JavaScript est fournie par le package npm @microsoft/signalr-protocol-msgpack . Installez le package en exécutant la commande suivante dans un interpréteur de commandes :

npm install @microsoft/signalr-protocol-msgpack

Après avoir installé le package npm, le module peut être utilisé directement via un chargeur de module JavaScript ou importé dans le navigateur en référençant le fichier suivant :

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

Les fichiers JavaScript requis suivants doivent être référencés dans l’ordre indiqué ci-dessous :

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

L’ajout .withHubProtocol(new signalR.protocols.msgpack.MessagePackHubProtocol()) à HubConnectionBuilder configure le client pour qu’il utilise le protocole MessagePack lors de la connexion à un serveur.

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

À l’heure actuelle, il n’existe aucune option de configuration pour le protocole MessagePack sur le client JavaScript.

Client Java

Pour activer MessagePack avec Java, installez le package com.microsoft.signalr.messagepack. Lorsque vous utilisez Gradle, ajoutez la ligne suivante à la dependencies section du fichier build.gradle :

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

Lorsque vous utilisez Maven, ajoutez les lignes suivantes à l’intérieur de l’élément <dependencies> du fichier pom.xml :

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

Appelez withHubProtocol(new MessagePackHubProtocol()) sur HubConnectionBuilder.

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

Considérations relatives à MessagePack

Il existe quelques problèmes à connaître lors de l’utilisation du protocole Hub MessagePack.

MessagePack respecte la casse

Le protocole MessagePack respecte la casse. Par exemple, considérons la classe C# suivante :

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

Lors de l’envoi à partir du client JavaScript, vous devez utiliser des noms de propriétés PascalCased, car la casse doit correspondre exactement à la classe C#. Par exemple :

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

L’utilisation de noms camelCased ne sera pas correctement liée à la classe C#. Vous pouvez contourner ce problème à l’aide de l’attribut Key pour spécifier un autre nom pour la propriété MessagePack. Pour plus d’informations, consultez la documentation MessagePack-CSharp.

DateTime.Kind n’est pas conservé lors de la sérialisation/désérialisation

Le protocole MessagePack ne permet pas d’encoder la valeur Kind d’un DateTime. Par conséquent, lors de la désérialisation d’une date, le protocole Hub MessagePack est converti au format UTC si le DateTime.Kind est DateTimeKind.Local sinon, il ne touche pas l’heure et ne la passe pas telle quelle. Si vous utilisez des valeurs DateTime, nous vous recommandons de les convertir en UTC avant de les envoyer. Convertissez-les d’UTC en heure locale lorsque vous les recevez.

Prise en charge de MessagePack dans un environnement de compilation « à l’avance »

La bibliothèque MessagePack-CSharp utilisée par le client et le serveur .NET utilise la génération de code pour optimiser la sérialisation. Par conséquent, elle n’est pas prise en charge par défaut sur les environnements qui utilisent la compilation « anticipée » (comme Xamarin iOS ou Unity). Il est possible d’utiliser MessagePack dans ces environnements en « pré-génération » du code sérialiseur/désérialiseur. Pour plus d’informations, consultez la documentation MessagePack-CSharp. Une fois que vous avez pré-généré les sérialiseurs, vous pouvez les inscrire à l’aide du délégué de configuration passé à 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);
    });

Les vérifications de type sont plus strictes dans MessagePack

Le protocole JSON Hub effectue des conversions de type pendant la désérialisation. Par exemple, si l’objet entrant a une valeur de propriété qui est un nombre ({ foo: 42 }) mais que la propriété de la classe .NET est de type string, la valeur est convertie. Toutefois, MessagePack n’effectue pas cette conversion et lève une exception visible dans les journaux côté serveur (et dans la console) :

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

Pour plus d’informations sur cette limitation, consultez Problème GitHub aspnet/SignalR#2937.

Caractères et chaînes dans Java

Dans le client Java, les objets char sont sérialisés en tant qu’objets à un caractère String. Cela contraste avec le client C# et JavaScript, qui les sérialisent en tant qu’objets short. La spécification MessagePack elle-même ne définit pas de comportement pour les objets char. Il incombe donc à l’auteur de la bibliothèque de déterminer comment les sérialiser. La différence de comportement entre nos clients est le résultat des bibliothèques que nous avons utilisées pour nos implémentations.

Ressources supplémentaires

Cet article part du principe que le lecteur est familiarisé avec les rubriques abordées dans Bien démarrer avec ASP.NET Core SignalR.

Qu’est-ce que MessagePack ?

MessagePack est un format de sérialisation binaire rapide et compact. Il est utile lorsque les performances et la bande passante sont un problème, car il crée des messages plus petits par rapport à JSON. Les messages binaires sont illisibles lors de l’analyse des traces réseau et des journaux, sauf si les octets sont transmis via un analyseur MessagePack. SignalR prend en charge le format MessagePack et fournit des API que le client et le serveur peuvent utiliser.

Configurer MessagePack sur le serveur

Pour activer le protocole MessagePack Hub sur le serveur, installez le package Microsoft.AspNetCore.SignalR.Protocols.MessagePack dans votre application. Dans la méthode Startup.ConfigureServices, ajoutez AddMessagePackProtocol à l’appel AddSignalR pour activer la prise en charge de MessagePack sur le serveur.

Notes

JSON est activé par défaut. L’ajout de MessagePack permet de prendre en charge les clients JSON et MessagePack.

services.AddSignalR()
    .AddMessagePackProtocol();

Pour personnaliser la façon dont MessagePack met en forme vos données, AddMessagePackProtocol prend un délégué pour la configuration des options. Dans ce délégué, la propriété SerializerOptions peut être utilisée pour configurer les options de sérialisation de MessagePack. Pour plus d’informations sur le fonctionnement des résolveurs, consultez la bibliothèque MessagePack sur MessagePack-CSharp. Les attributs peuvent être utilisés sur les objets que vous souhaitez sérialiser pour définir la façon dont ils doivent être gérés.

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

Avertissement

Nous vous recommandons vivement d’examiner CVE-2020-5234 et d’appliquer les correctifs recommandés. Par exemple, appelez .WithSecurity(MessagePackSecurity.UntrustedData) lors du remplacement de SerializerOptions.

Configurer MessagePack sur le client

Notes

JSON est activé par défaut pour les clients pris en charge. Les clients ne peuvent prendre en charge qu’un seul protocole. L’ajout de la prise en charge de MessagePack remplace tous les protocoles précédemment configurés.

Client .NET

Pour activer MessagePack dans le client .NET, installez le package Microsoft.AspNetCore.SignalR.Protocols.MessagePack et appelez AddMessagePackProtocol sur HubConnectionBuilder.

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

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

Notes

Cet appel AddMessagePackProtocol prend un délégué pour configurer les options comme le serveur.

Client JavaScript

La prise en charge de MessagePack pour le client JavaScript est fournie par le package npm @microsoft/signalr-protocol-msgpack . Installez le package en exécutant la commande suivante dans un interpréteur de commandes :

npm install @microsoft/signalr-protocol-msgpack

Après avoir installé le package npm, le module peut être utilisé directement via un chargeur de module JavaScript ou importé dans le navigateur en référençant le fichier suivant :

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

Dans un navigateur, la bibliothèque msgpack5 doit également être référencée. Utilisez une balise <script> pour créer une référence. La bibliothèque se trouve à l'node_modules\msgpack5\dist\msgpack5.js.

Notes

Lors de l’utilisation de l’élément <script> , l’ordre est important. Si signalr-protocol-msgpack.js est référencé avant msgpack5.js, une erreur se produit lors de la tentative de connexion à MessagePack. signalr.js est également requis pour être signalr-protocol-msgpack.js.

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

L’ajout de .withHubProtocol(new signalR.protocols.msgpack.MessagePackHubProtocol()) à HubConnectionBuilderconfigure le client pour qu’il utilise le protocole MessagePack lors de la connexion à un serveur.

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

Notes

À l’heure actuelle, il n’existe aucune option de configuration pour le protocole MessagePack sur le client JavaScript.

Client Java

Pour activer MessagePack avec Java, installez le package com.microsoft.signalr.messagepack. Lorsque vous utilisez Gradle, ajoutez la ligne suivante à la dependencies section du fichier build.gradle :

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

Lorsque vous utilisez Maven, ajoutez les lignes suivantes à l’intérieur de l’élément <dependencies> du fichier pom.xml :

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

Appelez withHubProtocol(new MessagePackHubProtocol()) sur HubConnectionBuilder.

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

Considérations relatives à MessagePack

Il existe quelques problèmes à connaître lors de l’utilisation du protocole Hub MessagePack.

MessagePack respecte la casse

Le protocole MessagePack respecte la casse. Par exemple, considérons la classe C# suivante :

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

Lors de l’envoi à partir du client JavaScript, vous devez utiliser des noms de propriétés PascalCased, car la casse doit correspondre exactement à la classe C#. Par exemple :

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

L’utilisation de noms camelCased ne sera pas correctement liée à la classe C#. Vous pouvez contourner ce problème à l’aide de l’attribut Key pour spécifier un autre nom pour la propriété MessagePack. Pour plus d’informations, consultez la documentation MessagePack-CSharp.

DateTime.Kind n’est pas conservé lors de la sérialisation/désérialisation

Le protocole MessagePack ne permet pas d’encoder la valeur Kind d’un DateTime. Par conséquent, lors de la désérialisation d’une date, le protocole Hub MessagePack est converti au format UTC si le DateTime.Kind est DateTimeKind.Local sinon, il ne touche pas l’heure et ne la passe pas telle quelle. Si vous utilisez des valeurs DateTime, nous vous recommandons de les convertir en UTC avant de les envoyer. Convertissez-les d’UTC en heure locale lorsque vous les recevez.

DateTime.MinValue n’est pas pris en charge par MessagePack en JavaScript

La bibliothèque msgpack5 utilisée par le SignalR client JavaScript ne prend pas en charge le type timestamp96 dans MessagePack. Ce type est utilisé pour encoder des valeurs de date très volumineuses (soit très tôt dans le passé, soit très loin dans le futur). La valeur de DateTime.MinValue est January 1, 0001, qui doit être encodée dans une valeur timestamp96. Pour cette raison, l’envoi DateTime.MinValue à un client JavaScript n’est pas pris en charge. Quand DateTime.MinValue est reçu par le client JavaScript, l’erreur suivante est levée :

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

Généralement, DateTime.MinValue est utilisé pour encoder une valeur ou null une valeur « manquante ». Si vous devez encoder cette valeur dans MessagePack, utilisez une valeur nullable DateTime (DateTime?) ou encodez une valeur distincte bool indiquant si la date est présente.

Pour plus d’informations sur cette limitation, consultez Problème GitHub aspnet/SignalR#2228.

Prise en charge de MessagePack dans un environnement de compilation « à l’avance »

La bibliothèque MessagePack-CSharp utilisée par le client et le serveur .NET utilise la génération de code pour optimiser la sérialisation. Par conséquent, elle n’est pas prise en charge par défaut sur les environnements qui utilisent la compilation « anticipée » (comme Xamarin iOS ou Unity). Il est possible d’utiliser MessagePack dans ces environnements en « pré-génération » du code sérialiseur/désérialiseur. Pour plus d’informations, consultez la documentation MessagePack-CSharp. Une fois que vous avez pré-généré les sérialiseurs, vous pouvez les inscrire à l’aide du délégué de configuration passé à 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);
    });

Les vérifications de type sont plus strictes dans MessagePack

Le protocole JSON Hub effectue des conversions de type pendant la désérialisation. Par exemple, si l’objet entrant a une valeur de propriété qui est un nombre ({ foo: 42 }) mais que la propriété de la classe .NET est de type string, la valeur est convertie. Toutefois, MessagePack n’effectue pas cette conversion et lève une exception visible dans les journaux côté serveur (et dans la console) :

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

Pour plus d’informations sur cette limitation, consultez Problème GitHub aspnet/SignalR#2937.

Caractères et chaînes dans Java

Dans le client Java, les objets char sont sérialisés en tant qu’objets à un caractère String. Cela contraste avec le client C# et JavaScript, qui les sérialisent en tant qu’objets short. La spécification MessagePack elle-même ne définit pas de comportement pour les objets char. Il incombe donc à l’auteur de la bibliothèque de déterminer comment les sérialiser. La différence de comportement entre nos clients est le résultat des bibliothèques que nous avons utilisées pour nos implémentations.

Ressources supplémentaires

Cet article part du principe que le lecteur est familiarisé avec les rubriques abordées dans Bien démarrer avec ASP.NET Core SignalR.

Qu’est-ce que MessagePack ?

MessagePack est un format de sérialisation binaire rapide et compact. Il est utile lorsque les performances et la bande passante sont un problème, car il crée des messages plus petits par rapport à JSON. Les messages binaires sont illisibles lors de l’analyse des traces réseau et des journaux, sauf si les octets sont transmis via un analyseur MessagePack. SignalR prend en charge le format MessagePack et fournit des API que le client et le serveur peuvent utiliser.

Configurer MessagePack sur le serveur

Pour activer le protocole MessagePack Hub sur le serveur, installez le package Microsoft.AspNetCore.SignalR.Protocols.MessagePack dans votre application. Dans la méthode Startup.ConfigureServices, ajoutez AddMessagePackProtocol à l’appel AddSignalR pour activer la prise en charge de MessagePack sur le serveur.

Notes

JSON est activé par défaut. L’ajout de MessagePack permet de prendre en charge les clients JSON et MessagePack.

services.AddSignalR()
    .AddMessagePackProtocol();

Pour personnaliser la façon dont MessagePack met en forme vos données, AddMessagePackProtocol prend un délégué pour la configuration des options. Dans ce délégué, la propriété FormatterResolvers peut être utilisée pour configurer les options de sérialisation de MessagePack. Pour plus d’informations sur le fonctionnement des résolveurs, consultez la bibliothèque MessagePack sur MessagePack-CSharp. Les attributs peuvent être utilisés sur les objets que vous souhaitez sérialiser pour définir la façon dont ils doivent être gérés.

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

Avertissement

Nous vous recommandons vivement d’examiner CVE-2020-5234 et d’appliquer les correctifs recommandés. Par exemple, affectez à la propriété statique MessagePackSecurity.Active à la valeur MessagePackSecurity.UntrustedData. La définition de MessagePackSecurity.Active nécessite l’installation manuelle d’une version 1.9.x de MessagePack. L’installation de MessagePack la version 1.9.x met à niveau la version que SignalR utilise. MessagePack La version 2.x a introduit des modifications cassants et est incompatible avec SignalR les versions 3.1 et antérieures. Quand MessagePackSecurity.Active n’est pas défini sur MessagePackSecurity.UntrustedData, un client malveillant peut provoquer un déni de service. Définissez MessagePackSecurity.Active dans Program.Main, comme indiqué dans le code suivant :

using MessagePack;

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

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

Configurer MessagePack sur le client

Notes

JSON est activé par défaut pour les clients pris en charge. Les clients ne peuvent prendre en charge qu’un seul protocole. L’ajout de la prise en charge de MessagePack remplace tous les protocoles précédemment configurés.

Client .NET

Pour activer MessagePack dans le client .NET, installez le package Microsoft.AspNetCore.SignalR.Protocols.MessagePack et appelez AddMessagePackProtocol sur HubConnectionBuilder.

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

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

Notes

Cet appel AddMessagePackProtocol prend un délégué pour configurer les options comme le serveur.

Client JavaScript

La prise en charge de MessagePack pour le client JavaScript est fournie par le package npm @microsoft/signalr-protocol-msgpack . Installez le package en exécutant la commande suivante dans un interpréteur de commandes :

npm install @microsoft/signalr-protocol-msgpack

Après avoir installé le package npm, le module peut être utilisé directement via un chargeur de module JavaScript ou importé dans le navigateur en référençant le fichier suivant :

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

Dans un navigateur, la bibliothèque msgpack5 doit également être référencée. Utilisez une balise <script> pour créer une référence. La bibliothèque se trouve à l'node_modules\msgpack5\dist\msgpack5.js.

Notes

Lors de l’utilisation de l’élément <script> , l’ordre est important. Si signalr-protocol-msgpack.js est référencé avant msgpack5.js, une erreur se produit lors de la tentative de connexion à MessagePack. signalr.js est également requis pour être signalr-protocol-msgpack.js.

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

L’ajout de .withHubProtocol(new signalR.protocols.msgpack.MessagePackHubProtocol()) à HubConnectionBuilderconfigure le client pour qu’il utilise le protocole MessagePack lors de la connexion à un serveur.

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

Notes

À l’heure actuelle, il n’existe aucune option de configuration pour le protocole MessagePack sur le client JavaScript.

Considérations relatives à MessagePack

Il existe quelques problèmes à connaître lors de l’utilisation du protocole Hub MessagePack.

MessagePack respecte la casse

Le protocole MessagePack respecte la casse. Par exemple, considérons la classe C# suivante :

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

Lors de l’envoi à partir du client JavaScript, vous devez utiliser des noms de propriétés PascalCased, car la casse doit correspondre exactement à la classe C#. Par exemple :

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

L’utilisation de noms camelCased ne sera pas correctement liée à la classe C#. Vous pouvez contourner ce problème à l’aide de l’attribut Key pour spécifier un autre nom pour la propriété MessagePack. Pour plus d’informations, consultez la documentation MessagePack-CSharp.

DateTime.Kind n’est pas conservé lors de la sérialisation/désérialisation

Le protocole MessagePack ne permet pas d’encoder la valeur Kind d’un DateTime. Par conséquent, lors de la désérialisation d’une date, le protocole MessagePack Hub suppose que la date entrante est au format UTC. Si vous utilisez DateTime des valeurs en heure locale, nous vous recommandons de les convertir en UTC avant de les envoyer. Convertissez-les d’UTC en heure locale lorsque vous les recevez.

Pour plus d’informations sur cette limitation, consultez Problème GitHub aspnet/SignalR#2632.

DateTime.MinValue n’est pas pris en charge par MessagePack en JavaScript

La bibliothèque msgpack5 utilisée par le SignalR client JavaScript ne prend pas en charge le type timestamp96 dans MessagePack. Ce type est utilisé pour encoder des valeurs de date très volumineuses (soit très tôt dans le passé, soit très loin dans le futur). La valeur de DateTime.MinValue est January 1, 0001, qui doit être encodée dans une valeur timestamp96. Pour cette raison, l’envoi DateTime.MinValue à un client JavaScript n’est pas pris en charge. Quand DateTime.MinValue est reçu par le client JavaScript, l’erreur suivante est levée :

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

Généralement, DateTime.MinValue est utilisé pour encoder une valeur ou null une valeur « manquante ». Si vous devez encoder cette valeur dans MessagePack, utilisez une valeur nullable DateTime (DateTime?) ou encodez une valeur distincte bool indiquant si la date est présente.

Pour plus d’informations sur cette limitation, consultez Problème GitHub aspnet/SignalR#2228.

Prise en charge de MessagePack dans un environnement de compilation « à l’avance »

La bibliothèque MessagePack-CSharp utilisée par le client et le serveur .NET utilise la génération de code pour optimiser la sérialisation. Par conséquent, elle n’est pas prise en charge par défaut sur les environnements qui utilisent la compilation « anticipée » (comme Xamarin iOS ou Unity). Il est possible d’utiliser MessagePack dans ces environnements en « pré-génération » du code sérialiseur/désérialiseur. Pour plus d’informations, consultez la documentation MessagePack-CSharp. Une fois que vous avez pré-généré les sérialiseurs, vous pouvez les inscrire à l’aide du délégué de configuration passé à AddMessagePackProtocol :

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

Les vérifications de type sont plus strictes dans MessagePack

Le protocole JSON Hub effectue des conversions de type pendant la désérialisation. Par exemple, si l’objet entrant a une valeur de propriété qui est un nombre ({ foo: 42 }) mais que la propriété de la classe .NET est de type string, la valeur est convertie. Toutefois, MessagePack n’effectue pas cette conversion et lève une exception visible dans les journaux côté serveur (et dans la console) :

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

Pour plus d’informations sur cette limitation, consultez Problème GitHub aspnet/SignalR#2937.

Ressources supplémentaires

Cet article part du principe que le lecteur est familiarisé avec les rubriques abordées dans Bien démarrer avec ASP.NET Core SignalR.

Qu’est-ce que MessagePack ?

MessagePack est un format de sérialisation binaire rapide et compact. Il est utile lorsque les performances et la bande passante sont un problème, car il crée des messages plus petits par rapport à JSON. Les messages binaires sont illisibles lors de l’analyse des traces réseau et des journaux, sauf si les octets sont transmis via un analyseur MessagePack. SignalR prend en charge le format MessagePack et fournit des API que le client et le serveur peuvent utiliser.

Configurer MessagePack sur le serveur

Pour activer le protocole MessagePack Hub sur le serveur, installez le package Microsoft.AspNetCore.SignalR.Protocols.MessagePack dans votre application. Dans la méthode Startup.ConfigureServices, ajoutez AddMessagePackProtocol à l’appel AddSignalR pour activer la prise en charge de MessagePack sur le serveur.

Notes

JSON est activé par défaut. L’ajout de MessagePack permet de prendre en charge les clients JSON et MessagePack.

services.AddSignalR()
    .AddMessagePackProtocol();

Pour personnaliser la façon dont MessagePack met en forme vos données, AddMessagePackProtocol prend un délégué pour la configuration des options. Dans ce délégué, la propriété FormatterResolvers peut être utilisée pour configurer les options de sérialisation de MessagePack. Pour plus d’informations sur le fonctionnement des résolveurs, consultez la bibliothèque MessagePack sur MessagePack-CSharp. Les attributs peuvent être utilisés sur les objets que vous souhaitez sérialiser pour définir la façon dont ils doivent être gérés.

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

Avertissement

Nous vous recommandons vivement d’examiner CVE-2020-5234 et d’appliquer les correctifs recommandés. Par exemple, affectez à la propriété statique MessagePackSecurity.Active à la valeur MessagePackSecurity.UntrustedData. La définition de MessagePackSecurity.Active nécessite l’installation manuelle d’une version 1.9.x de MessagePack. L’installation de MessagePack la version 1.9.x met à niveau la version que SignalR utilise. Quand MessagePackSecurity.Active n’est pas défini sur MessagePackSecurity.UntrustedData, un client malveillant peut provoquer un déni de service. Définissez MessagePackSecurity.Active dans Program.Main, comme indiqué dans le code suivant :

using MessagePack;

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

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

Configurer MessagePack sur le client

Notes

JSON est activé par défaut pour les clients pris en charge. Les clients ne peuvent prendre en charge qu’un seul protocole. L’ajout de la prise en charge de MessagePack remplace tous les protocoles précédemment configurés.

Client .NET

Pour activer MessagePack dans le client .NET, installez le package Microsoft.AspNetCore.SignalR.Protocols.MessagePack et appelez AddMessagePackProtocol sur HubConnectionBuilder.

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

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

Notes

Cet appel AddMessagePackProtocol prend un délégué pour configurer les options comme le serveur.

Client JavaScript

La prise en charge de MessagePack pour le client JavaScript est fournie par le package npm @aspnet/signalr-protocol-msgpack. Installez le package en exécutant la commande suivante dans un interpréteur de commandes :

npm install @aspnet/signalr-protocol-msgpack

Après avoir installé le package npm, le module peut être utilisé directement via un chargeur de module JavaScript ou importé dans le navigateur en référençant le fichier suivant :

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

Dans un navigateur, la bibliothèque msgpack5 doit également être référencée. Utilisez une balise <script> pour créer une référence. La bibliothèque se trouve à l'node_modules\msgpack5\dist\msgpack5.js.

Notes

Lors de l’utilisation de l’élément <script> , l’ordre est important. Si signalr-protocol-msgpack.js est référencé avant msgpack5.js, une erreur se produit lors de la tentative de connexion à MessagePack. signalr.js est également requis pour être signalr-protocol-msgpack.js.

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

L’ajout de .withHubProtocol(new signalR.protocols.msgpack.MessagePackHubProtocol()) à HubConnectionBuilderconfigure le client pour qu’il utilise le protocole MessagePack lors de la connexion à un serveur.

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

Notes

À l’heure actuelle, il n’existe aucune option de configuration pour le protocole MessagePack sur le client JavaScript.

Considérations relatives à MessagePack

Il existe quelques problèmes à connaître lors de l’utilisation du protocole Hub MessagePack.

MessagePack respecte la casse

Le protocole MessagePack respecte la casse. Par exemple, considérons la classe C# suivante :

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

Lors de l’envoi à partir du client JavaScript, vous devez utiliser des noms de propriétés PascalCased, car la casse doit correspondre exactement à la classe C#. Par exemple :

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

L’utilisation de noms camelCased ne sera pas correctement liée à la classe C#. Vous pouvez contourner ce problème à l’aide de l’attribut Key pour spécifier un autre nom pour la propriété MessagePack. Pour plus d’informations, consultez la documentation MessagePack-CSharp.

DateTime.Kind n’est pas conservé lors de la sérialisation/désérialisation

Le protocole MessagePack ne permet pas d’encoder la valeur Kind d’un DateTime. Par conséquent, lors de la désérialisation d’une date, le protocole MessagePack Hub suppose que la date entrante est au format UTC. Si vous utilisez DateTime des valeurs en heure locale, nous vous recommandons de les convertir en UTC avant de les envoyer. Convertissez-les d’UTC en heure locale lorsque vous les recevez.

Pour plus d’informations sur cette limitation, consultez Problème GitHub aspnet/SignalR#2632.

DateTime.MinValue n’est pas pris en charge par MessagePack en JavaScript

La bibliothèque msgpack5 utilisée par le SignalR client JavaScript ne prend pas en charge le type timestamp96 dans MessagePack. Ce type est utilisé pour encoder des valeurs de date très volumineuses (soit très tôt dans le passé, soit très loin dans le futur). La valeur de DateTime.MinValue est January 1, 0001, qui doit être encodée dans une valeur timestamp96. Pour cette raison, l’envoi DateTime.MinValue à un client JavaScript n’est pas pris en charge. Quand DateTime.MinValue est reçu par le client JavaScript, l’erreur suivante est levée :

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

Généralement, DateTime.MinValue est utilisé pour encoder une valeur ou null une valeur « manquante ». Si vous devez encoder cette valeur dans MessagePack, utilisez une valeur nullable DateTime (DateTime?) ou encodez une valeur distincte bool indiquant si la date est présente.

Pour plus d’informations sur cette limitation, consultez Problème GitHub aspnet/SignalR#2228.

Prise en charge de MessagePack dans un environnement de compilation « à l’avance »

La bibliothèque MessagePack-CSharp utilisée par le client et le serveur .NET utilise la génération de code pour optimiser la sérialisation. Par conséquent, elle n’est pas prise en charge par défaut sur les environnements qui utilisent la compilation « anticipée » (comme Xamarin iOS ou Unity). Il est possible d’utiliser MessagePack dans ces environnements en « pré-génération » du code sérialiseur/désérialiseur. Pour plus d’informations, consultez la documentation MessagePack-CSharp. Une fois que vous avez pré-généré les sérialiseurs, vous pouvez les inscrire à l’aide du délégué de configuration passé à AddMessagePackProtocol :

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

Les vérifications de type sont plus strictes dans MessagePack

Le protocole JSON Hub effectue des conversions de type pendant la désérialisation. Par exemple, si l’objet entrant a une valeur de propriété qui est un nombre ({ foo: 42 }) mais que la propriété de la classe .NET est de type string, la valeur est convertie. Toutefois, MessagePack n’effectue pas cette conversion et lève une exception visible dans les journaux côté serveur (et dans la console) :

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

Pour plus d’informations sur cette limitation, consultez Problème GitHub aspnet/SignalR#2937.

Ressources supplémentaires