Delen via


MessagePack Hub Protocol gebruiken in SignalR voor ASP.NET Core

In dit artikel wordt ervan uitgegaan dat de lezer bekend is met de onderwerpen die worden behandeld in Aan de slag met ASP.NET Core SignalR.

Wat is MessagePack?

MessagePack is een snelle en compacte binaire serialisatieformaat. Het is handig wanneer prestaties en bandbreedte een probleem zijn omdat er kleinere berichten worden gemaakt dan JSON-. De binaire berichten zijn onleesbaar wanneer u netwerktraceringen en logboeken bekijkt, tenzij de bytes worden doorgegeven via een MessagePack-parser. SignalR heeft ingebouwde ondersteuning voor de MessagePack-indeling en biedt API's die de client en server kunnen gebruiken.

MessagePack configureren op de server

Als u het MessagePack Hub Protocol op de server wilt inschakelen, installeert u het Microsoft.AspNetCore.SignalR.Protocols.MessagePack-pakket in uw app. Voeg in de methode Startup.ConfigureServicesAddMessagePackProtocol toe aan de AddSignalR aanroep om ondersteuning voor MessagePack op de server in te schakelen.

services.AddSignalR()
    .AddMessagePackProtocol();

Notitie

JSON is standaard ingeschakeld. Het toevoegen van MessagePack maakt ondersteuning mogelijk voor zowel JSON- als MessagePack-clients.

Als u de indeling van gegevens in MessagePack wilt aanpassen, neemt AddMessagePackProtocol een gemachtigde voor het configureren van opties. In deze gemachtigde wordt de eigenschap SerializerOptions gebruikt om serialisatieopties voor MessagePack te configureren. Ga naar de MessagePack-bibliotheek op MessagePack-CSharp-voor meer informatie over de werking van de resolvers. Kenmerken kunnen worden gebruikt voor de objecten die u wilt serialiseren om te definiëren hoe ze moeten worden verwerkt.

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

Waarschuwing

We raden u ten zeerste aan om CVE-2020-5234 te bekijken en de aanbevolen patches toe te passen. Bijvoorbeeld het aanroepen van .WithSecurity(MessagePackSecurity.UntrustedData) bij het vervangen van de SerializerOptions.

MessagePack configureren op de client

Notitie

JSON is standaard ingeschakeld voor de ondersteunde clients. Clients kunnen slechts één protocol ondersteunen. Het toevoegen van MessagePack-ondersteuning vervangt eventuele eerder geconfigureerde protocollen.

.NET-client

Als u MessagePack wilt inschakelen in de .NET-client, installeert u het Microsoft.AspNetCore.SignalR.Protocols.MessagePack-pakket en roept u AddMessagePackProtocol aan op HubConnectionBuilder.

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

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

Notitie

Deze AddMessagePackProtocol-oproep gebruikt een delegate om opties te configureren, net zoals de server doet.

JavaScript-client

MessagePack-ondersteuning voor de JavaScript-client wordt geleverd door het pakket @microsoft/signalr-protocol-msgpack npm. Installeer het pakket door de volgende opdracht uit te voeren in een opdrachtshell:

npm install @microsoft/signalr-protocol-msgpack

Na de installatie van het npm-pakket kan de module rechtstreeks worden gebruikt via een JavaScript-modulelaadprogramma of in de browser worden geïmporteerd door te verwijzen naar het volgende bestand:

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

In de onderstaande volgorde moet worden verwezen naar de volgende vereiste JavaScript-bestanden:

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

Door .withHubProtocol(new signalR.protocols.msgpack.MessagePackHubProtocol()) toe te voegen aan de HubConnectionBuilder wordt de client geconfigureerd voor het gebruik van het MessagePack-protocol bij het maken van verbinding met een server.

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

Op dit moment zijn er geen configuratieopties voor het MessagePack-protocol op de JavaScript-client.

Java-client

Als u MessagePack met Java wilt inschakelen, installeert u het com.microsoft.signalr.messagepack-pakket. Wanneer u Gradle gebruikt, voegt u de volgende regel toe aan de sectie dependencies van het bestand build.gradle:

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

Wanneer u Maven gebruikt, voegt u de volgende regels toe binnen het <dependencies> element van het pom.xml-bestand:

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

Bel withHubProtocol(new MessagePackHubProtocol()) op HubConnectionBuilder.

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

Overwegingen voor MessagePack

Er zijn enkele problemen waarmee u rekening moet houden bij het gebruik van het MessagePack Hub Protocol.

MessagePack is hoofdlettergevoelig

Het MessagePack-protocol is hoofdlettergevoelig. Denk bijvoorbeeld aan de volgende C#-klasse:

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

Wanneer u verzendt vanuit de JavaScript-client, moet u PascalCased eigenschapsnamen gebruiken, omdat de behuizing exact moet overeenkomen met de C#-klasse. Bijvoorbeeld:

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

Als u camelCased-namen gebruikt, zullen ze niet correct worden verbonden met de C#-klasse. U kunt dit omzeilen door het kenmerk Key te gebruiken om een andere naam op te geven voor de eigenschap MessagePack. Zie de MessagePack-CSharp documentatievoor meer informatie.

DateTime.Kind blijft niet behouden bij het serialiseren/deserialiseren

Het MessagePack-protocol biedt geen manier om de Kind waarde van een DateTimete coderen. Als een datum wordt gedeserialiseerd, zal het MessagePack Hub Protocol het converteren naar de UTC-indeling als DateTime.KindDateTimeKind.Local is; anders zal de tijd onveranderd worden doorgegeven. Als u met DateTime waarden werkt, raden we u aan om te converteren naar UTC voordat u ze verzendt. Converteer ze van UTC naar lokale tijd wanneer u ze ontvangt.

MessagePack-ondersteuning in van tevoren compilatieomgeving

De MessagePack-CSharp bibliotheek die wordt gebruikt door de .NET-client en -server maakt gebruik van codegeneratie om serialisatie te optimaliseren. Als gevolg hiervan wordt het niet standaard ondersteund voor omgevingen die gebruikmaken van compilatie vooraf, zoals de gebruikersinterface van de net-app met meerdere platforms (.NET MAUI) of Unity. Het is mogelijk om MessagePack in deze omgevingen te gebruiken door de serializer-/deserializer-code vooraf te genereren. Zie de MessagePack-CSharp documentatievoor meer informatie. Nadat u de serializers vooraf hebt gegenereerd, kunt u deze registreren met behulp van de configuratie-delegate die is doorgegeven aan 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);
    });

Typecontroles zijn strikter in MessagePack

Het JSON Hub Protocol voert typeconversies uit tijdens deserialisatie. Als het binnenkomende object bijvoorbeeld een eigenschapswaarde heeft die een getal ({ foo: 42 }) is, maar de eigenschap in de .NET-klasse van het type stringis, wordt de waarde geconverteerd. MessagePack voert deze conversie echter niet uit en genereert een uitzondering die kan worden weergegeven in logboeken aan de serverzijde (en in de console):

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

Zie GitHub-probleem aspnet/SignalR#2937voor meer informatie over deze beperking.

Tekens en tekenreeksen in Java

In de Java-cliënt worden char-objecten geserialiseerd als eenteken-String-objecten. Dit is in tegenstelling tot de C#- en JavaScript-client, die ze serialiseert als short objecten. De MessagePack-specificatie zelf definieert geen gedrag voor char objecten, dus het is aan de auteur van de bibliotheek om te bepalen hoe ze moeten worden geserialiseerd. Het verschil in gedrag tussen onze klanten is het resultaat van de bibliotheken die we voor onze implementaties hebben gebruikt.

Aanvullende informatiebronnen

In dit artikel wordt ervan uitgegaan dat de lezer bekend is met de onderwerpen die worden behandeld in Aan de slag met ASP.NET Core SignalR.

Wat is MessagePack?

MessagePack is een snel en compact binair serialisatieformaat. Het is handig wanneer prestaties en bandbreedte een probleem zijn omdat er kleinere berichten worden gemaakt in vergelijking met JSON-. De binaire berichten zijn onleesbaar wanneer u netwerktraceringen en logboeken bekijkt, tenzij de bytes worden doorgegeven via een MessagePack-parser. SignalR heeft ingebouwde ondersteuning voor de MessagePack-indeling en biedt API's die de client en server kunnen gebruiken.

MessagePack configureren op de server

Als u het MessagePack Hub Protocol op de server wilt inschakelen, installeert u het Microsoft.AspNetCore.SignalR.Protocols.MessagePack-pakket in uw app. Voeg in de methode Startup.ConfigureServicesAddMessagePackProtocol toe aan de AddSignalR aanroep om ondersteuning voor MessagePack op de server in te schakelen.

Notitie

JSON is standaard ingeschakeld. Het toevoegen van MessagePack maakt ondersteuning mogelijk voor zowel JSON- als MessagePack-clients.

services.AddSignalR()
    .AddMessagePackProtocol();

Als u wilt aanpassen hoe Uw gegevens in MessagePack worden opgemaakt, neemt AddMessagePackProtocol een gemachtigde voor het configureren van opties. In deze gemachtigde kan de eigenschap SerializerOptions worden gebruikt om serialisatieopties voor MessagePack te configureren. Ga naar de MessagePack-bibliotheek op MessagePack-CSharp-voor meer informatie over de werking van de resolvers. Kenmerken kunnen worden gebruikt voor de objecten die u wilt serialiseren om te definiëren hoe ze moeten worden verwerkt.

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

Waarschuwing

We raden u ten zeerste aan om CVE-2020-5234 te bekijken en de aanbevolen patches toe te passen. Bijvoorbeeld het aanroepen van .WithSecurity(MessagePackSecurity.UntrustedData) bij het vervangen van de SerializerOptions.

MessagePack configureren op de client

Notitie

JSON is standaard ingeschakeld voor de ondersteunde clients. Clients kunnen slechts één protocol ondersteunen. Het toevoegen van MessagePack-ondersteuning vervangt alle eerder geconfigureerde protocollen.

.NET-client

Als u MessagePack wilt inschakelen in de .NET-client, installeert u het Microsoft.AspNetCore.SignalR.Protocols.MessagePack-pakket en roept u AddMessagePackProtocol aan op HubConnectionBuilder.

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

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

Notitie

Deze AddMessagePackProtocol oproep neemt een gemachtigde voor het configureren van opties, net zoals de server.

JavaScript-client

MessagePack-ondersteuning voor de JavaScript-client wordt geleverd door het pakket @microsoft/signalr-protocol-msgpack npm. Installeer het pakket door de volgende opdracht uit te voeren in een opdrachtshell:

npm install @microsoft/signalr-protocol-msgpack

Na de installatie van het npm-pakket kan de module rechtstreeks worden gebruikt via een JavaScript-modulelaadprogramma of in de browser worden geïmporteerd door te verwijzen naar het volgende bestand:

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

In een browser moet ook naar de msgpack5 bibliotheek worden verwezen. Gebruik een <script>-tag om een verwijzing te maken. De bibliotheek is te vinden op node_modules\msgpack5\dist\msgpack5.js.

Notitie

Wanneer u het element <script> gebruikt, is de volgorde belangrijk. Als signalr-protocol-msgpack.js wordt verwezen voordat msgpack5.js, treedt er een fout op wanneer u verbinding probeert te maken met MessagePack. signalr.js is ook vereist voordat 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>

Door .withHubProtocol(new signalR.protocols.msgpack.MessagePackHubProtocol()) toe te voegen aan de HubConnectionBuilder wordt de client geconfigureerd voor het gebruik van het MessagePack-protocol bij het maken van verbinding met een server.

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

Notitie

Op dit moment zijn er geen configuratieopties voor het MessagePack-protocol op de JavaScript-client.

Java client

Als u MessagePack met Java wilt inschakelen, installeert u het com.microsoft.signalr.messagepack-pakket. Wanneer u Gradle gebruikt, voegt u de volgende regel toe aan de sectie dependencies van het bestand build.gradle:

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

Wanneer u Maven gebruikt, voegt u de volgende regels toe binnen het <dependencies> element van het pom.xml-bestand:

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

Bel withHubProtocol(new MessagePackHubProtocol()) op HubConnectionBuilder.

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

Overwegingen voor MessagePack

Er zijn enkele problemen waarmee u rekening moet houden bij het gebruik van het MessagePack Hub Protocol.

MessagePack is hoofdlettergevoelig

Het MessagePack-protocol is hoofdlettergevoelig. Denk bijvoorbeeld aan de volgende C#-klasse:

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

Wanneer u verzendt vanuit de JavaScript-client, moet u PascalCased eigenschapsnamen gebruiken, omdat de behuizing exact moet overeenkomen met de C#-klasse. Bijvoorbeeld:

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

Als u camelCased-naam gebruikt, wordt deze niet correct gekoppeld aan de C#-klasse. U kunt dit omzeilen door het kenmerk Key te gebruiken om een andere naam op te geven voor de eigenschap MessagePack. Zie de MessagePack-CSharp documentatievoor meer informatie.

DateTime.Kind wordt niet behouden bij het serialiseren/deserialiseren.

Het MessagePack-protocol biedt geen manier om de Kind waarde van een DateTimete coderen. Bij het deserialiseren van een datum, converteert het MessagePack Hub Protocol dit naar de UTC-indeling als DateTime.KindDateTimeKind.Local is; anders wordt de tijd niet aangeraakt en wordt deze als zodanig doorgegeven. Als u met DateTime waarden werkt, raden we u aan om te converteren naar UTC voordat u ze verzendt. Converteer ze van UTC naar lokale tijd wanneer u ze ontvangt.

DateTime.MinValue wordt niet ondersteund door MessagePack in JavaScript

De msgpack5-bibliotheek die wordt gebruikt door de SignalR JavaScript-client biedt geen ondersteuning voor het timestamp96 type in MessagePack. Dit type wordt gebruikt om zeer grote datumwaarden te coderen (zeer vroeg in het verleden of heel ver in de toekomst). De waarde van DateTime.MinValue is January 1, 0001, die moet worden gecodeerd in een timestamp96 waarde. Daarom wordt het verzenden van DateTime.MinValue naar een JavaScript-client niet ondersteund. Wanneer DateTime.MinValue wordt ontvangen door de JavaScript-client, wordt de volgende fout gegenereerd:

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

Meestal wordt DateTime.MinValue gebruikt om een 'ontbrekende' of null waarde te coderen. Als u die waarde in MessagePack moet coderen, gebruikt u een nullable DateTime waarde (DateTime?) of codeert u een afzonderlijke bool waarde die aangeeft of de datum aanwezig is.

Zie GitHub-probleem aspnet/SignalR#2228voor meer informatie over deze beperking.

Ondersteuning voor MessagePack in een "ahead-of-time" compilatieomgeving

De MessagePack-CSharp bibliotheek die wordt gebruikt door de .NET-client en -server maakt gebruik van codegeneratie om serialisatie te optimaliseren. Als gevolg hiervan wordt het niet standaard ondersteund voor omgevingen die gebruikmaken van compilatie vooraf, zoals de gebruikersinterface van de net-app met meerdere platforms (.NET MAUI) of Unity. Het is mogelijk om MessagePack in deze omgevingen te gebruiken door de serializer-/deserializer-code vooraf te genereren. Zie de MessagePack-CSharp documentatievoor meer informatie. Nadat u de serializers vooraf hebt gegenereerd, kunt u deze registreren met behulp van de configuratie-gemachtigde die is doorgegeven aan 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);
    });

Typecontroles zijn strikter in MessagePack

Het JSON Hub Protocol voert typeconversies uit tijdens deserialisatie. Als het binnenkomende object bijvoorbeeld een eigenschapswaarde heeft die een getal ({ foo: 42 }) is, maar de eigenschap in de .NET-klasse van het type stringis, wordt de waarde geconverteerd. MessagePack voert deze conversie echter niet uit en genereert een uitzondering die kan worden weergegeven in logboeken aan de serverzijde (en in de console):

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

Zie GitHub-probleem aspnet/SignalR#2937voor meer informatie over deze beperking.

Tekens en tekenreeksen in Java

In de Java-client worden char-objecten geserialiseerd als eenteken String-objecten. Dit is in tegenstelling tot de C#- en JavaScript-client, die ze serialiseert als short objecten. De MessagePack-specificatie zelf definieert geen gedrag voor char objecten, dus het is aan de auteur van de bibliotheek om te bepalen hoe ze moeten worden geserialiseerd. Het verschil in gedrag tussen onze klanten is het resultaat van de bibliotheken die we voor onze implementaties hebben gebruikt.

Aanvullende informatiebronnen

In dit artikel wordt ervan uitgegaan dat de lezer bekend is met de onderwerpen die worden behandeld in Aan de slag met ASP.NET Core SignalR.

Wat is MessagePack?

MessagePack is een snel en compact binair serialisatieformaat. Het is handig wanneer prestaties en bandbreedte een probleem zijn omdat er kleinere berichten worden gemaakt in vergelijking met JSON-. De binaire berichten zijn onleesbaar wanneer u netwerktraceringen en logboeken bekijkt, tenzij de bytes worden doorgegeven via een MessagePack-parser. SignalR heeft ingebouwde ondersteuning voor de MessagePack-indeling en biedt API's die de client en server kunnen gebruiken.

MessagePack configureren op de server

Als u het MessagePack Hub Protocol op de server wilt inschakelen, installeert u het Microsoft.AspNetCore.SignalR.Protocols.MessagePack-pakket in uw app. Voeg in de methode Startup.ConfigureServicesAddMessagePackProtocol toe aan de AddSignalR aanroep om ondersteuning voor MessagePack op de server in te schakelen.

Notitie

JSON is standaard ingeschakeld. Het toevoegen van MessagePack maakt ondersteuning mogelijk voor zowel JSON- als MessagePack-clients.

services.AddSignalR()
    .AddMessagePackProtocol();

Als u wilt aanpassen hoe Uw gegevens in MessagePack worden opgemaakt, neemt AddMessagePackProtocol een gemachtigde voor het configureren van opties. In deze gemachtigde kan de eigenschap FormatterResolvers worden gebruikt om serialisatieopties voor MessagePack te configureren. Ga naar de MessagePack-bibliotheek op MessagePack-CSharp-voor meer informatie over de werking van de resolvers. Kenmerken kunnen worden gebruikt voor de objecten die u wilt serialiseren om te definiëren hoe ze moeten worden verwerkt.

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

Waarschuwing

We raden u ten zeerste aan om CVE-2020-5234 te bekijken en de aanbevolen patches toe te passen. Stel bijvoorbeeld de statische eigenschap MessagePackSecurity.Active in op MessagePackSecurity.UntrustedData. Als u de MessagePackSecurity.Active instelt, moet u handmatig een 1.9.x-versie van MessagePackinstalleren. Als u MessagePack 1.9.x installeert, wordt de versie die SignalR gebruikt, bijgewerkt. MessagePack versie 2.x heeft belangrijke wijzigingen geïntroduceerd en is niet compatibel met SignalR versie 3.1 en eerder. Wanneer MessagePackSecurity.Active niet is ingesteld op MessagePackSecurity.UntrustedData, kan een kwaadwillende client een denial of service veroorzaken. Stel MessagePackSecurity.Active in Program.Mainin, zoals wordt weergegeven in de volgende code:

using MessagePack;

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

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

MessagePack configureren op de client

Notitie

JSON is standaard ingeschakeld voor de ondersteunde clients. Clients kunnen slechts één protocol ondersteunen. Het toevoegen van MessagePack-ondersteuning vervangt alle eerder geconfigureerde protocollen.

.NET client

Als u MessagePack wilt inschakelen in de .NET-client, installeert u het Microsoft.AspNetCore.SignalR.Protocols.MessagePack-pakket en roept u AddMessagePackProtocol aan op HubConnectionBuilder.

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

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

Notitie

Deze AddMessagePackProtocol-oproep neemt een delegate aan om opties te configureren, net zoals de server.

JavaScript-client

MessagePack-ondersteuning voor de JavaScript-client wordt geleverd door het pakket @microsoft/signalr-protocol-msgpack npm. Installeer het pakket door de volgende opdracht uit te voeren in een opdrachtshell:

npm install @microsoft/signalr-protocol-msgpack

Na de installatie van het npm-pakket kan de module rechtstreeks worden gebruikt via een JavaScript-modulelaadprogramma of in de browser worden geïmporteerd door te verwijzen naar het volgende bestand:

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

In een browser moet ook naar de msgpack5 bibliotheek worden verwezen. Gebruik een <script>-tag om een verwijzing te maken. De bibliotheek is te vinden op node_modules\msgpack5\dist\msgpack5.js.

Notitie

Wanneer u het element <script> gebruikt, is de volgorde belangrijk. Als signalr-protocol-msgpack.js wordt verwezen voordat msgpack5.js, treedt er een fout op wanneer u verbinding probeert te maken met MessagePack. signalr.js is ook vereist voordat 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>

Door .withHubProtocol(new signalR.protocols.msgpack.MessagePackHubProtocol()) toe te voegen aan de HubConnectionBuilder wordt de client geconfigureerd voor het gebruik van het MessagePack-protocol bij het maken van verbinding met een server.

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

Notitie

Op dit moment zijn er geen configuratieopties voor het MessagePack-protocol op de JavaScript-client.

Overwegingen voor MessagePack

Er zijn enkele problemen waarmee u rekening moet houden bij het gebruik van het MessagePack Hub Protocol.

MessagePack is hoofdlettergevoelig

Het MessagePack-protocol is hoofdlettergevoelig. Denk bijvoorbeeld aan de volgende C#-klasse:

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

Wanneer u verzendt vanuit de JavaScript-client, moet u PascalCased eigenschapsnamen gebruiken, omdat de behuizing exact moet overeenkomen met de C#-klasse. Bijvoorbeeld:

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

Als u camelCased-namen gebruikt, zullen deze niet correct worden verbonden met de C#-klasse. U kunt dit omzeilen door het kenmerk Key te gebruiken om een andere naam op te geven voor de eigenschap MessagePack. Zie de MessagePack-CSharp documentatievoor meer informatie.

DateTime.Kind wordt niet behouden tijdens het serialiseren en deserialiseren.

Het MessagePack-protocol biedt geen manier om de Kind waarde van een DateTimete coderen. Als gevolg hiervan wordt bij het deserialiseren van een datum in het MessagePack Hub-protocol ervan uitgegaan dat de binnenkomende datum de UTC-indeling heeft. Als u werkt met DateTime waarden in lokale tijd, raden we u aan om te converteren naar UTC voordat u ze verzendt. Converteer ze van UTC naar lokale tijd wanneer u ze ontvangt.

Zie GitHub-probleem aspnet/SignalR#2632voor meer informatie over deze beperking.

DateTime.MinValue wordt niet ondersteund door MessagePack in JavaScript

De msgpack5-bibliotheek die wordt gebruikt door de SignalR JavaScript-client biedt geen ondersteuning voor het timestamp96 type in MessagePack. Dit type wordt gebruikt om zeer grote datumwaarden te coderen (zeer vroeg in het verleden of heel ver in de toekomst). De waarde van DateTime.MinValue is January 1, 0001, die moet worden gecodeerd in een timestamp96 waarde. Daarom wordt het verzenden van DateTime.MinValue naar een JavaScript-client niet ondersteund. Wanneer DateTime.MinValue wordt ontvangen door de JavaScript-client, wordt de volgende fout gegenereerd:

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

Meestal wordt DateTime.MinValue gebruikt om een 'ontbrekende' of null waarde te coderen. Als u die waarde in MessagePack moet coderen, gebruikt u een nullable DateTime waarde (DateTime?) of codeert u een afzonderlijke bool waarde die aangeeft of de datum aanwezig is.

Zie GitHub-probleem aspnet/SignalR#2228voor meer informatie over deze beperking.

MessagePack-ondersteuning in een voorafgaande compilatieomgeving

De MessagePack-CSharp bibliotheek die wordt gebruikt door de .NET-client en -server maakt gebruik van codegeneratie om serialisatie te optimaliseren. Als gevolg hiervan wordt het niet standaard ondersteund voor omgevingen die gebruikmaken van compilatie vooraf, zoals de gebruikersinterface van de net-app met meerdere platforms (.NET MAUI) of Unity. Het is mogelijk om MessagePack in deze omgevingen te gebruiken door de serializer-/deserializer-code vooraf te genereren. Zie de MessagePack-CSharp documentatievoor meer informatie. Nadat u de serializers vooraf hebt gegenereerd, kunt u deze registreren met behulp van de configuratie-gemachtigde die is doorgegeven aan AddMessagePackProtocol:

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

Typecontroles zijn strikter in MessagePack

Het JSON Hub Protocol voert typeconversies uit tijdens deserialisatie. Als het binnenkomende object bijvoorbeeld een eigenschapswaarde heeft die een getal ({ foo: 42 }) is, maar de eigenschap in de .NET-klasse van het type stringis, wordt de waarde geconverteerd. MessagePack voert deze conversie echter niet uit en genereert een uitzondering die kan worden weergegeven in logboeken aan de serverzijde (en in de console):

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

Zie GitHub-probleem aspnet/SignalR#2937voor meer informatie over deze beperking.

Aanvullende informatiebronnen

In dit artikel wordt ervan uitgegaan dat de lezer bekend is met de onderwerpen die worden behandeld in Aan de slag met ASP.NET Core SignalR.

Wat is MessagePack?

MessagePack is een snelle en compacte binaire serialisatieformaat. Het is handig wanneer prestaties en bandbreedte een probleem zijn omdat er kleinere berichten worden gemaakt in vergelijking met JSON-. De binaire berichten zijn onleesbaar wanneer u netwerktraceringen en logboeken bekijkt, tenzij de bytes worden doorgegeven via een MessagePack-parser. SignalR heeft ingebouwde ondersteuning voor de MessagePack-indeling en biedt API's die de client en server kunnen gebruiken.

MessagePack configureren op de server

Als u het MessagePack Hub Protocol op de server wilt inschakelen, installeert u het Microsoft.AspNetCore.SignalR.Protocols.MessagePack-pakket in uw app. Voeg in de methode Startup.ConfigureServicesAddMessagePackProtocol toe aan de AddSignalR aanroep om ondersteuning voor MessagePack op de server in te schakelen.

Notitie

JSON is standaard ingeschakeld. Het toevoegen van MessagePack maakt ondersteuning mogelijk voor zowel JSON- als MessagePack-clients.

services.AddSignalR()
    .AddMessagePackProtocol();

Als u wilt aanpassen hoe Uw gegevens in MessagePack worden opgemaakt, neemt AddMessagePackProtocol een gemachtigde voor het configureren van opties. In deze gemachtigde kan de eigenschap FormatterResolvers worden gebruikt om serialisatieopties voor MessagePack te configureren. Ga naar de MessagePack-bibliotheek op MessagePack-CSharp-voor meer informatie over de werking van de resolvers. Kenmerken kunnen worden gebruikt voor de objecten die u wilt serialiseren om te definiëren hoe ze moeten worden verwerkt.

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

Waarschuwing

We raden u ten zeerste aan om CVE-2020-5234 te bekijken en de aanbevolen patches toe te passen. Stel bijvoorbeeld de statische eigenschap MessagePackSecurity.Active in op MessagePackSecurity.UntrustedData. Als u de MessagePackSecurity.Active instelt, moet u handmatig een 1.9.x-versie van MessagePackinstalleren. Als u MessagePack 1.9.x installeert, wordt de versie die SignalR gebruikt, bijgewerkt. Wanneer MessagePackSecurity.Active niet is ingesteld op MessagePackSecurity.UntrustedData, kan een kwaadwillende client een denial of service veroorzaken. Stel MessagePackSecurity.Active in Program.Mainin, zoals wordt weergegeven in de volgende code:

using MessagePack;

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

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

MessagePack configureren op de client

Notitie

JSON is standaard ingeschakeld voor de ondersteunde clients. Clients kunnen slechts één protocol ondersteunen. Het toevoegen van MessagePack-ondersteuning vervangt alle eerder geconfigureerde protocollen.

.NET-client

Als u MessagePack wilt inschakelen in de .NET-client, installeert u het Microsoft.AspNetCore.SignalR.Protocols.MessagePack-pakket en roept u AddMessagePackProtocol aan op HubConnectionBuilder.

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

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

Notitie

Deze AddMessagePackProtocol oproep accepteert een delegate om opties te configureren, net zoals bij de server.

JavaScript-client

MessagePack-ondersteuning voor de JavaScript-client wordt geleverd door het pakket @aspnet/signalr-protocol-msgpack npm. Installeer het pakket door de volgende opdracht uit te voeren in een opdrachtshell:

npm install @aspnet/signalr-protocol-msgpack

Na de installatie van het npm-pakket kan de module rechtstreeks worden gebruikt via een JavaScript-modulelaadprogramma of in de browser worden geïmporteerd door te verwijzen naar het volgende bestand:

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

In een browser moet ook naar de msgpack5 bibliotheek worden verwezen. Gebruik een <script>-tag om een verwijzing te maken. De bibliotheek is te vinden op node_modules\msgpack5\dist\msgpack5.js.

Notitie

Wanneer u het element <script> gebruikt, is de volgorde belangrijk. Als signalr-protocol-msgpack.js wordt verwezen voordat msgpack5.js, treedt er een fout op wanneer u verbinding probeert te maken met MessagePack. signalr.js is ook vereist voordat 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>

Door .withHubProtocol(new signalR.protocols.msgpack.MessagePackHubProtocol()) toe te voegen aan de HubConnectionBuilder wordt de client geconfigureerd voor het gebruik van het MessagePack-protocol bij het maken van verbinding met een server.

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

Notitie

Op dit moment zijn er geen configuratieopties voor het MessagePack-protocol op de JavaScript-client.

Overwegingen voor MessagePack

Er zijn enkele problemen waarmee u rekening moet houden bij het gebruik van het MessagePack Hub Protocol.

MessagePack is hoofdlettergevoelig

Het MessagePack-protocol is hoofdlettergevoelig. Denk bijvoorbeeld aan de volgende C#-klasse:

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

Wanneer u verzendt vanuit de JavaScript-client, moet u PascalCased eigenschapsnamen gebruiken, omdat de behuizing exact moet overeenkomen met de C#-klasse. Bijvoorbeeld:

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

Het gebruik van camelCased-namen zal niet correct binden aan de C#-klasse. U kunt dit omzeilen door het kenmerk Key te gebruiken om een andere naam op te geven voor de eigenschap MessagePack. Zie de MessagePack-CSharp documentatievoor meer informatie.

DateTime.Kind wordt niet behouden bij het serialiseren/deserialiseren

Het MessagePack-protocol biedt geen manier om de Kind waarde van een DateTimete coderen. Als gevolg hiervan wordt bij het deserialiseren van een datum in het MessagePack Hub-protocol ervan uitgegaan dat de binnenkomende datum de UTC-indeling heeft. Als u werkt met DateTime waarden in lokale tijd, raden we u aan om te converteren naar UTC voordat u ze verzendt. Converteer ze van UTC naar lokale tijd wanneer u ze ontvangt.

Zie GitHub-probleem aspnet/SignalR#2632voor meer informatie over deze beperking.

DateTime.MinValue wordt niet ondersteund door MessagePack in JavaScript

De msgpack5-bibliotheek die wordt gebruikt door de SignalR JavaScript-client biedt geen ondersteuning voor het timestamp96 type in MessagePack. Dit type wordt gebruikt om zeer grote datumwaarden te coderen (zeer vroeg in het verleden of heel ver in de toekomst). De waarde van DateTime.MinValue is January 1, 0001 die in een timestamp96-waarde moet worden gecodeerd. Daarom wordt het verzenden van DateTime.MinValue naar een JavaScript-client niet ondersteund. Wanneer DateTime.MinValue wordt ontvangen door de JavaScript-client, wordt de volgende fout gegenereerd:

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

Meestal wordt DateTime.MinValue gebruikt om een 'ontbrekende' of null waarde te coderen. Als u die waarde in MessagePack moet coderen, gebruikt u een nullable DateTime waarde (DateTime?) of codeert u een afzonderlijke bool waarde die aangeeft of de datum aanwezig is.

Zie GitHub-probleem aspnet/SignalR#2228voor meer informatie over deze beperking.

MessagePack-ondersteuning in "ahead-of-time" compilatieomgeving

De MessagePack-CSharp bibliotheek die wordt gebruikt door de .NET-client en -server maakt gebruik van codegeneratie om serialisatie te optimaliseren. Als gevolg hiervan wordt het niet standaard ondersteund voor omgevingen die gebruikmaken van compilatie vooraf, zoals de gebruikersinterface van de net-app met meerdere platforms (.NET MAUI) of Unity. Het is mogelijk om MessagePack in deze omgevingen te gebruiken door de serializer-/deserializer-code vooraf te genereren. Raadpleeg de MessagePack-CSharp documentatievoor meer informatie. Nadat u de serializers vooraf hebt gegenereerd, kunt u ze registreren met behulp van de configuratie-gedelegeerde die aan AddMessagePackProtocolis doorgegeven:

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

Typecontroles zijn strikter in MessagePack

Het JSON Hub Protocol voert typeconversies uit tijdens deserialisatie. Als het binnenkomende object bijvoorbeeld een eigenschapswaarde heeft die een getal ({ foo: 42 }) is, maar de eigenschap in de .NET-klasse van het type stringis, wordt de waarde geconverteerd. MessagePack voert deze conversie echter niet uit en genereert een uitzondering die kan worden weergegeven in logboeken aan de serverzijde (en in de console):

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

Zie GitHub-probleem aspnet/SignalR#2937voor meer informatie over deze beperking.

Aanvullende informatiebronnen