Dela via


Använda MessagePack Hub Protocol i SignalR för ASP.NET Core

Den här artikeln förutsätter att läsaren är bekant med de ämnen som beskrivs i Komma igång med ASP.NET Core SignalR.

Vad är MessagePack?

MessagePack är ett snabbt och kompakt binärt serialiseringsformat. Det är användbart när prestanda och bandbredd är ett problem eftersom det skapar mindre meddelanden än JSON-. Binärmeddelandena kan inte läsas när du tittar på nätverksspårningar och loggar om inte byte skickas via en MessagePack-parser. SignalR har inbyggt stöd för MessagePack-formatet och tillhandahåller API:er som klienten och servern kan använda.

Konfigurera MessagePack på servern

Om du vill aktivera MessagePack Hub-protokollet på servern installerar du Microsoft.AspNetCore.SignalR.Protocols.MessagePack-paketet i din app. I metoden Startup.ConfigureServices lägger du till AddMessagePackProtocol i AddSignalR-anropet för att aktivera MessagePack-stöd på servern.

services.AddSignalR()
    .AddMessagePackProtocol();

Obs

JSON är aktiverat som standard. Genom att lägga till MessagePack får du stöd för både JSON- och MessagePack-klienter.

För att anpassa hur MessagePack formaterar data tar AddMessagePackProtocol en delegering för att konfigurera alternativ. I den delegaten används egenskapen SerializerOptions för att konfigurera serialiseringsalternativ för MessagePack. För mer information om hur lösare fungerar, besök MessagePack-biblioteket på MessagePack-CSharp. Attribut kan användas på de objekt som du vill serialisera för att definiera hur de ska hanteras.

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

Varning

Vi rekommenderar starkt att du granskar CVE-2020-5234 och tillämpar de rekommenderade korrigeringarna. Du kan till exempel anropa .WithSecurity(MessagePackSecurity.UntrustedData) när du ersätter SerializerOptions.

Konfigurera MessagePack på klienten

Obs

JSON är aktiverat som standard för klienter som stöds. Klienter kan bara stödja ett enda protokoll. Om du lägger till MessagePack-stöd ersätts alla tidigare konfigurerade protokoll.

.NET-klient

Om du vill aktivera MessagePack i .NET-klienten installerar du Microsoft.AspNetCore.SignalR.Protocols.MessagePack-paketet och anropar AddMessagePackProtocolHubConnectionBuilder.

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

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

Obs

Det här AddMessagePackProtocol-anropet tar en delegat för att konfigurera alternativen på samma sätt som servern.

JavaScript-klient

MessagePack-stöd för JavaScript-klienten tillhandahålls av @microsoft/signalr-protocol-msgpack npm-paketet. Installera paketet genom att köra följande kommando i ett kommandogränssnitt:

npm install @microsoft/signalr-protocol-msgpack

När du har installerat npm-paketet kan modulen användas direkt via en JavaScript-modulinläsare eller importeras till webbläsaren genom att referera till följande fil:

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

Följande nödvändiga javaScript-filer måste refereras i den ordning som visas nedan:

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

Genom att lägga till .withHubProtocol(new signalR.protocols.msgpack.MessagePackHubProtocol()) i HubConnectionBuilder konfigureras klienten att använda MessagePack-protokollet vid anslutning till en server.

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

För närvarande finns det inga konfigurationsalternativ för MessagePack-protokollet på JavaScript-klienten.

Java-klient

Om du vill aktivera MessagePack med Java installerar du com.microsoft.signalr.messagepack-paketet. När du använder Gradle lägger du till följande rad i avsnittet dependencies i filen build.gradle:

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

När du använder Maven lägger du till följande rader i <dependencies>-elementet i pom.xml-filen:

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

Anropa withHubProtocol(new MessagePackHubProtocol())HubConnectionBuilder.

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

Överväganden för MessagePack

Det finns några problem att känna till när du använder MessagePack Hub-protokollet.

MessagePack är skiftlägeskänsligt

Protokollet MessagePack är skiftlägeskänsligt. Tänk till exempel på följande C#-klass:

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

När du skickar från JavaScript-klienten måste du använda PascalCased egenskapsnamn, eftersom höljet måste matcha C#-klassen exakt. Till exempel:

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

Att använda camelCased-identifierare binder inte korrekt till C#-klassen. Du kan kringgå detta med hjälp av attributet Key för att ange ett annat namn för egenskapen MessagePack. Mer information finns i MessagePack-CSharp dokumentationen.

DateTime.Kind bevaras inte vid serialisering/deserialisering

MessagePack-protokollet ger inte något sätt att koda Kind värdet för en DateTime. När ett datum deserialiseras konverteras därför MessagePack Hub Protocol till UTC-format om DateTime.Kind är DateTimeKind.Local annars rör det inte tiden och skickar det som det är. Om du arbetar med DateTime värden rekommenderar vi att du konverterar till UTC innan du skickar dem. Konvertera dem från UTC till lokal tid när du tar emot dem.

MessagePack-stöd i förhandskompileringens miljö

MessagePack-CSharp--biblioteket som används av .NET-klienten och -servern använder kodgenerering för att optimera serialiseringen. Därför stöds det inte som standard på miljöer som använder kompilering i förväg, till exempel NET Multi-platform App UI (.NET MAUI) eller Unity. Det är möjligt att använda MessagePack i dessa miljöer genom att "förgenerera" serialiseraren/deserialiserarkoden. Mer information finns i MessagePack-CSharp dokumentationen. När du har genererat serialiserarna i förväg kan du registrera dem med hjälp av konfigurationsdelegaten som skickas till 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);
    });

Typkontroller är striktare i MessagePack

JSON Hub Protocol utför typkonverteringar under deserialiseringen. Om det inkommande objektet till exempel har ett egenskapsvärde som är ett tal ({ foo: 42 }) men egenskapen för .NET-klassen är av typen stringkonverteras värdet. MessagePack utför dock inte den här konverteringen och utlöser ett undantag som kan visas i loggar på serversidan (och i konsolen):

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

Mer information om den här begränsningen finns i GitHub-problem aspnet/SignalR#2937.

Tecken och strängar i Java

I Java-klienten kommer char-objekt att serialiseras som ett-teckens-String-objekt. Detta står i kontrast till C#- och JavaScript-klienten, som serialiserar dem som short objekt. Själva MessagePack-specifikationen definierar inte beteendet för char objekt, så det är upp till biblioteksförfattaren att avgöra hur de ska serialiseras. Skillnaden i beteende mellan våra klienter är ett resultat av de bibliotek som vi använde för våra implementeringar.

Ytterligare resurser

Den här artikeln förutsätter att läsaren är bekant med de ämnen som beskrivs i Komma igång med ASP.NET Core SignalR.

Vad är MessagePack?

MessagePack är ett snabbt och kompakt binärt serialiseringsformat. Det är användbart när prestanda och bandbredd är ett problem eftersom det skapar mindre meddelanden jämfört med JSON-. Binärmeddelandena kan inte läsas när du tittar på nätverksspårningar och loggar om inte byte skickas via en MessagePack-parser. SignalR har inbyggt stöd för MessagePack-formatet och tillhandahåller API:er som klienten och servern kan använda.

Konfigurera MessagePack på servern

Om du vill aktivera MessagePack Hub-protokollet på servern installerar du Microsoft.AspNetCore.SignalR.Protocols.MessagePack-paketet i din app. I metoden Startup.ConfigureServices lägger du till AddMessagePackProtocol i AddSignalR-anropet för att aktivera MessagePack-stöd på servern.

Obs

JSON är aktiverat som standard. Genom att lägga till MessagePack får du stöd för både JSON- och MessagePack-klienter.

services.AddSignalR()
    .AddMessagePackProtocol();

För att anpassa hur MessagePack ska formatera dina data, tar AddMessagePackProtocol en delegering för att konfigurera alternativ. I den delegeringen kan egenskapen SerializerOptions användas för att konfigurera serialiseringsalternativ för MessagePack. För mer information om hur lösare fungerar, besök MessagePack-biblioteket på MessagePack-CSharp. Attribut kan användas på de objekt som du vill serialisera för att definiera hur de ska hanteras.

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

Varning

Vi rekommenderar starkt att du granskar CVE-2020-5234 och tillämpar de rekommenderade korrigeringarna. Du kan till exempel anropa .WithSecurity(MessagePackSecurity.UntrustedData) när du ersätter SerializerOptions.

Konfigurera MessagePack på klienten

Obs

JSON är aktiverat som standard för klienter som stöds. Klienter kan bara stödja ett enda protokoll. Om du lägger till MessagePack-stöd ersätts alla tidigare konfigurerade protokoll.

.NET-klient

Om du vill aktivera MessagePack i .NET-klienten installerar du Microsoft.AspNetCore.SignalR.Protocols.MessagePack-paketet och anropar AddMessagePackProtocolHubConnectionBuilder.

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

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

Obs

Det här AddMessagePackProtocol-anropet tar en delegat för att konfigurera alternativen på samma sätt som servern.

JavaScript-klient

MessagePack-stöd för JavaScript-klienten tillhandahålls av @microsoft/signalr-protocol-msgpack npm-paketet. Installera paketet genom att köra följande kommando i ett kommandogränssnitt:

npm install @microsoft/signalr-protocol-msgpack

När du har installerat npm-paketet kan modulen användas direkt via en JavaScript-modulinläsare eller importeras till webbläsaren genom att referera till följande fil:

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

I en webbläsare måste även msgpack5-biblioteket refereras till. Använd en <script> tagg för att skapa en referens. Biblioteket finns på node_modules\msgpack5\dist\msgpack5.js.

Obs

När du använder elementet <script> är ordningen viktig. Om signalr-protocol-msgpack.js refereras före msgpack5.jsuppstår ett fel när du försöker ansluta till MessagePack. signalr.js krävs också innan 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>

Om du lägger till .withHubProtocol(new signalR.protocols.msgpack.MessagePackHubProtocol()) i HubConnectionBuilder konfigureras klienten att använda MessagePack-protokollet vid anslutning till en server.

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

Obs

För närvarande finns det inga konfigurationsalternativ för MessagePack-protokollet på JavaScript-klienten.

Java-klient

Om du vill aktivera MessagePack med Java installerar du com.microsoft.signalr.messagepack-paketet. När du använder Gradle lägger du till följande rad i avsnittet dependencies i filen build.gradle:

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

När du använder Maven lägger du till följande rader i <dependencies>-elementet i pom.xml-filen:

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

Anropa withHubProtocol(new MessagePackHubProtocol())HubConnectionBuilder.

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

Överväganden för MessagePack

Det finns några problem att känna till när du använder MessagePack Hub-protokollet.

MessagePack är skiftlägeskänsligt

Protokollet MessagePack är skiftlägeskänsligt. Tänk till exempel på följande C#-klass:

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

När du skickar från JavaScript-klienten måste du använda PascalCased egenskapsnamn, eftersom höljet måste matcha C#-klassen exakt. Till exempel:

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

Att använda camelCased-identifierare binder inte korrekt till C#-klassen. Du kan kringgå detta med hjälp av attributet Key för att ange ett annat namn för egenskapen MessagePack. Mer information finns i MessagePack-CSharp dokumentationen.

DateTime.Kind bevaras inte vid serialisering/deserialisering

MessagePack-protokollet ger inte något sätt att koda Kind värdet för en DateTime. När ett datum deserialiseras konverteras därför MessagePack Hub Protocol till UTC-format om DateTime.Kind är DateTimeKind.Local annars rör det inte tiden och skickar det som det är. Om du arbetar med DateTime värden rekommenderar vi att du konverterar till UTC innan du skickar dem. Konvertera dem från UTC till lokal tid när du tar emot dem.

DateTime.MinValue stöds inte av MessagePack i JavaScript

msgpack5-biblioteket som används av SignalR JavaScript-klienten stöder inte timestamp96 typen i MessagePack. Den här typen används för att koda mycket stora datumvärden (antingen mycket tidigt i det förflutna eller mycket långt i framtiden). Värdet för DateTime.MinValue är January 1, 0001, som måste kodas i ett timestamp96 värde. Därför stöds inte sändning av DateTime.MinValue till en JavaScript-klient. När DateTime.MinValue tas emot av JavaScript-klienten utlöses följande fel:

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

Vanligtvis används DateTime.MinValue för att koda ett värde som "saknas" eller null. Om du behöver koda det värdet i MessagePack använder du ett nullbart DateTime värde (DateTime?) eller kodar ett separat bool värde som anger om datumet finns.

Mer information om den här begränsningen finns i GitHub-problem aspnet/SignalR#2228.

MessagePack-stöd i förhandskompileringens miljö

MessagePack-CSharp--biblioteket som används av .NET-klienten och -servern använder kodgenerering för att optimera serialiseringen. Därför stöds det inte som standard på miljöer som använder kompilering i förväg, till exempel NET Multi-platform App UI (.NET MAUI) eller Unity. Det är möjligt att använda MessagePack i dessa miljöer genom att "förgenerera" serialiseraren/deserialiserarkoden. Mer information finns i MessagePack-CSharp dokumentationen. När du har genererat serialiserarna i förväg kan du registrera dem med hjälp av konfigurationsdelegaten som skickas till 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);
    });

Typkontroller är striktare i MessagePack

JSON Hub Protocol utför typkonverteringar under deserialiseringen. Om det inkommande objektet till exempel har ett egenskapsvärde som är ett tal ({ foo: 42 }) men egenskapen för .NET-klassen är av typen stringkonverteras värdet. MessagePack utför dock inte den här konverteringen och utlöser ett undantag som kan visas i loggar på serversidan (och i konsolen):

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

Mer information om den här begränsningen finns i GitHub-problem aspnet/SignalR#2937.

Tecken och strängar i Java

I Java-klienten kommer char-objekt att serialiseras som ett-teckens-String-objekt. Detta står i kontrast till C#- och JavaScript-klienten, som serialiserar dem som short objekt. Själva MessagePack-specifikationen definierar inte beteendet för char objekt, så det är upp till biblioteksförfattaren att avgöra hur de ska serialiseras. Skillnaden i beteende mellan våra klienter är ett resultat av de bibliotek som vi använde för våra implementeringar.

Ytterligare resurser

Den här artikeln förutsätter att läsaren är bekant med de ämnen som beskrivs i Komma igång med ASP.NET Core SignalR.

Vad är MessagePack?

MessagePack är ett snabbt och kompakt binärt serialiseringsformat. Det är användbart när prestanda och bandbredd är ett problem eftersom det skapar mindre meddelanden jämfört med JSON-. Binärmeddelandena kan inte läsas när du tittar på nätverksspårningar och loggar om inte byte skickas via en MessagePack-parser. SignalR har inbyggt stöd för MessagePack-formatet och tillhandahåller API:er som klienten och servern kan använda.

Konfigurera MessagePack på servern

Om du vill aktivera MessagePack Hub-protokollet på servern installerar du Microsoft.AspNetCore.SignalR.Protocols.MessagePack-paketet i din app. I metoden Startup.ConfigureServices lägger du till AddMessagePackProtocol i AddSignalR-anropet för att aktivera MessagePack-stöd på servern.

Obs

JSON är aktiverat som standard. Genom att lägga till MessagePack får du stöd för både JSON- och MessagePack-klienter.

services.AddSignalR()
    .AddMessagePackProtocol();

För att anpassa hur MessagePack ska formatera dina data, tar AddMessagePackProtocol en delegering för att konfigurera alternativ. I den delegeringen kan egenskapen FormatterResolvers användas för att konfigurera serialiseringsalternativ för MessagePack. För mer information om hur lösare fungerar, besök MessagePack-biblioteket på MessagePack-CSharp. Attribut kan användas på de objekt som du vill serialisera för att definiera hur de ska hanteras.

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

Varning

Vi rekommenderar starkt att du granskar CVE-2020-5234 och tillämpar de rekommenderade korrigeringarna. Du kan till exempel ange MessagePackSecurity.Active statisk egenskap till MessagePackSecurity.UntrustedData. Om du ställer in MessagePackSecurity.Active måste du installera en 1.9.x-version av MessagePackmanuellt. Om du installerar MessagePack 1.9.x uppgraderas den version SignalR använder. MessagePack version 2.x introducerade brytande ändringar och är inte kompatibel med SignalR version 3.1 och tidigare. När MessagePackSecurity.Active inte är inställt på MessagePackSecurity.UntrustedDatakan en skadlig klient orsaka tjänstblockering. Ange MessagePackSecurity.Active i Program.Main, enligt följande kod:

using MessagePack;

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

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

Konfigurera MessagePack på klienten

Obs

JSON är aktiverat som standard för klienter som stöds. Klienter kan bara stödja ett enda protokoll. Om du lägger till MessagePack-stöd ersätts alla tidigare konfigurerade protokoll.

.NET-klient

Om du vill aktivera MessagePack i .NET-klienten installerar du Microsoft.AspNetCore.SignalR.Protocols.MessagePack-paketet och anropar AddMessagePackProtocolHubConnectionBuilder.

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

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

Obs

Det här AddMessagePackProtocol-anropet tar en delegat för att konfigurera alternativen på samma sätt som servern.

JavaScript-klient

MessagePack-stöd för JavaScript-klienten tillhandahålls av @microsoft/signalr-protocol-msgpack npm-paketet. Installera paketet genom att köra följande kommando i ett kommandogränssnitt:

npm install @microsoft/signalr-protocol-msgpack

När du har installerat npm-paketet kan modulen användas direkt via en JavaScript-modulinläsare eller importeras till webbläsaren genom att referera till följande fil:

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

I en webbläsare måste även msgpack5-biblioteket refereras till. Använd en <script> tagg för att skapa en referens. Biblioteket finns på node_modules\msgpack5\dist\msgpack5.js.

Obs

När du använder elementet <script> är ordningen viktig. Om signalr-protocol-msgpack.js refereras före msgpack5.jsuppstår ett fel när du försöker ansluta till MessagePack. signalr.js krävs också innan 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>

Om du lägger till .withHubProtocol(new signalR.protocols.msgpack.MessagePackHubProtocol()) i HubConnectionBuilder konfigureras klienten att använda MessagePack-protokollet vid anslutning till en server.

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

Obs

För närvarande finns det inga konfigurationsalternativ för MessagePack-protokollet på JavaScript-klienten.

Överväganden för MessagePack

Det finns några problem att känna till när du använder MessagePack Hub-protokollet.

MessagePack är skiftlägeskänsligt

Protokollet MessagePack är skiftlägeskänsligt. Tänk till exempel på följande C#-klass:

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

När du skickar från JavaScript-klienten måste du använda PascalCased egenskapsnamn, eftersom höljet måste matcha C#-klassen exakt. Till exempel:

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

Att använda camelCased-identifierare binder inte korrekt till C#-klassen. Du kan kringgå detta med hjälp av attributet Key för att ange ett annat namn för egenskapen MessagePack. Mer information finns i MessagePack-CSharp dokumentationen.

DateTime.Kind bevaras inte vid serialisering/deserialisering

MessagePack-protokollet ger inte något sätt att koda Kind värdet för en DateTime. Därför förutsätter MessagePack Hub-protokollet att det inkommande datumet är i UTC-format när ett datum deserialiseras. Om du arbetar med DateTime värden i lokal tid rekommenderar vi att du konverterar till UTC innan du skickar dem. Konvertera dem från UTC till lokal tid när du tar emot dem.

Mer information om den här begränsningen finns i GitHub-problem aspnet/SignalR#2632.

DateTime.MinValue stöds inte av MessagePack i JavaScript

msgpack5-biblioteket som används av SignalR JavaScript-klienten stöder inte timestamp96 typen i MessagePack. Den här typen används för att koda mycket stora datumvärden (antingen mycket tidigt i det förflutna eller mycket långt i framtiden). Värdet för DateTime.MinValue är January 1, 0001, som måste kodas i ett timestamp96 värde. Därför stöds inte sändning av DateTime.MinValue till en JavaScript-klient. När DateTime.MinValue tas emot av JavaScript-klienten utlöses följande fel:

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

Vanligtvis används DateTime.MinValue för att koda ett värde som "saknas" eller null. Om du behöver koda det värdet i MessagePack använder du ett nullbart DateTime värde (DateTime?) eller kodar ett separat bool värde som anger om datumet finns.

Mer information om den här begränsningen finns i GitHub-problem aspnet/SignalR#2228.

MessagePack-stöd i förhandskompileringens miljö

MessagePack-CSharp--biblioteket som används av .NET-klienten och -servern använder kodgenerering för att optimera serialiseringen. Därför stöds det inte som standard på miljöer som använder kompilering i förväg, till exempel NET Multi-platform App UI (.NET MAUI) eller Unity. Det är möjligt att använda MessagePack i dessa miljöer genom att "förgenerera" serialiseraren/deserialiserarkoden. Mer information finns i MessagePack-CSharp dokumentationen. När du har genererat serialiserarna i förväg kan du registrera dem med hjälp av konfigurationsdelegaten som skickas till AddMessagePackProtocol:

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

Typkontroller är striktare i MessagePack

JSON Hub Protocol utför typkonverteringar under deserialiseringen. Om det inkommande objektet till exempel har ett egenskapsvärde som är ett tal ({ foo: 42 }) men egenskapen för .NET-klassen är av typen stringkonverteras värdet. MessagePack utför dock inte den här konverteringen och utlöser ett undantag som kan visas i loggar på serversidan (och i konsolen):

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

Mer information om den här begränsningen finns i GitHub-problem aspnet/SignalR#2937.

Ytterligare resurser

Den här artikeln förutsätter att läsaren är bekant med de ämnen som beskrivs i Komma igång med ASP.NET Core SignalR.

Vad är MessagePack?

MessagePack är ett snabbt och kompakt binärt serialiseringsformat. Det är användbart när prestanda och bandbredd är ett problem eftersom det skapar mindre meddelanden jämfört med JSON-. Binärmeddelandena kan inte läsas när du tittar på nätverksspårningar och loggar om inte byte skickas via en MessagePack-parser. SignalR har inbyggt stöd för MessagePack-formatet och tillhandahåller API:er som klienten och servern kan använda.

Konfigurera MessagePack på servern

Om du vill aktivera MessagePack Hub-protokollet på servern installerar du Microsoft.AspNetCore.SignalR.Protocols.MessagePack-paketet i din app. I metoden Startup.ConfigureServices lägger du till AddMessagePackProtocol i AddSignalR-anropet för att aktivera MessagePack-stöd på servern.

Obs

JSON är aktiverat som standard. Genom att lägga till MessagePack får du stöd för både JSON- och MessagePack-klienter.

services.AddSignalR()
    .AddMessagePackProtocol();

För att anpassa hur MessagePack ska formatera dina data, tar AddMessagePackProtocol en delegering för att konfigurera alternativ. I den delegeringen kan egenskapen FormatterResolvers användas för att konfigurera serialiseringsalternativ för MessagePack. För mer information om hur lösare fungerar, besök MessagePack-biblioteket på MessagePack-CSharp. Attribut kan användas på de objekt som du vill serialisera för att definiera hur de ska hanteras.

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

Varning

Vi rekommenderar starkt att du granskar CVE-2020-5234 och tillämpar de rekommenderade korrigeringarna. Du kan till exempel ange MessagePackSecurity.Active statisk egenskap till MessagePackSecurity.UntrustedData. Om du ställer in MessagePackSecurity.Active måste du installera en 1.9.x-version av MessagePackmanuellt. Om du installerar MessagePack 1.9.x uppgraderas den version SignalR använder. När MessagePackSecurity.Active inte är inställt på MessagePackSecurity.UntrustedData, kan en skadlig klient orsaka ett tjänstestopp. Ange MessagePackSecurity.Active i Program.Main, enligt följande kod:

using MessagePack;

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

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

Konfigurera MessagePack på klienten

Obs

JSON är aktiverat som standard för klienter som stöds. Klienter kan bara stödja ett enda protokoll. Om du lägger till MessagePack-stöd ersätts alla tidigare konfigurerade protokoll.

.NET-klient

Om du vill aktivera MessagePack i .NET-klienten installerar du Microsoft.AspNetCore.SignalR.Protocols.MessagePack-paketet och anropar AddMessagePackProtocolHubConnectionBuilder.

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

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

Obs

Det här AddMessagePackProtocol-anropet tar en delegat för att konfigurera alternativen på samma sätt som servern.

JavaScript-klient

MessagePack-stöd för JavaScript-klienten tillhandahålls av @aspnet/signalr-protocol-msgpack npm-paketet. Installera paketet genom att köra följande kommando i ett kommandogränssnitt:

npm install @aspnet/signalr-protocol-msgpack

När du har installerat npm-paketet kan modulen användas direkt via en JavaScript-modulinläsare eller importeras till webbläsaren genom att referera till följande fil:

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

I en webbläsare måste även msgpack5-biblioteket refereras till. Använd en <script> tagg för att skapa en referens. Biblioteket finns på node_modules\msgpack5\dist\msgpack5.js.

Obs

När du använder elementet <script> är ordningen viktig. Om signalr-protocol-msgpack.js refereras före msgpack5.jsuppstår ett fel när du försöker ansluta till MessagePack. signalr.js krävs också innan 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>

Om du lägger till .withHubProtocol(new signalR.protocols.msgpack.MessagePackHubProtocol()) i HubConnectionBuilder konfigureras klienten att använda MessagePack-protokollet vid anslutning till en server.

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

Obs

För närvarande finns det inga konfigurationsalternativ för MessagePack-protokollet på JavaScript-klienten.

Överväganden för MessagePack

Det finns några problem att känna till när du använder MessagePack Hub-protokollet.

MessagePack är skiftlägeskänsligt

Protokollet MessagePack är skiftlägeskänsligt. Tänk till exempel på följande C#-klass:

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

När du skickar från JavaScript-klienten måste du använda PascalCased egenskapsnamn, eftersom höljet måste matcha C#-klassen exakt. Till exempel:

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

Att använda camelCased-identifierare binder inte korrekt till C#-klassen. Du kan kringgå detta med hjälp av attributet Key för att ange ett annat namn för egenskapen MessagePack. Mer information finns i MessagePack-CSharp dokumentationen.

DateTime.Kind bevaras inte vid serialisering/deserialisering

MessagePack-protokollet ger inte något sätt att koda Kind värdet för en DateTime. Därför förutsätter MessagePack Hub-protokollet att det inkommande datumet är i UTC-format när ett datum deserialiseras. Om du arbetar med DateTime värden i lokal tid rekommenderar vi att du konverterar till UTC innan du skickar dem. Konvertera dem från UTC till lokal tid när du tar emot dem.

Mer information om den här begränsningen finns i GitHub-problem aspnet/SignalR#2632.

DateTime.MinValue stöds inte av MessagePack i JavaScript

msgpack5-biblioteket som används av SignalR JavaScript-klienten stöder inte timestamp96 typen i MessagePack. Den här typen används för att koda mycket stora datumvärden (antingen mycket tidigt i det förflutna eller mycket långt i framtiden). Värdet för DateTime.MinValue är January 1, 0001 som måste kodas i ett timestamp96 värde. Därför stöds inte sändning av DateTime.MinValue till en JavaScript-klient. När DateTime.MinValue tas emot av JavaScript-klienten utlöses följande fel:

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

Vanligtvis används DateTime.MinValue för att koda ett värde som "saknas" eller null. Om du behöver koda det värdet i MessagePack använder du ett nullbart DateTime värde (DateTime?) eller kodar ett separat bool värde som anger om datumet finns.

Mer information om den här begränsningen finns i GitHub-problem aspnet/SignalR#2228.

MessagePack-stöd i förhandskompileringens miljö

MessagePack-CSharp--biblioteket som används av .NET-klienten och -servern använder kodgenerering för att optimera serialiseringen. Därför stöds det inte som standard på miljöer som använder kompilering i förväg, till exempel NET Multi-platform App UI (.NET MAUI) eller Unity. Det är möjligt att använda MessagePack i dessa miljöer genom att "förgenerera" serialiseraren/deserialiserarkoden. Mer information finns i MessagePack-CSharp dokumentationen. När du har genererat serialiserarna i förväg kan du registrera dem med hjälp av konfigurationsdelegaten som skickas till AddMessagePackProtocol:

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

Typkontroller är striktare i MessagePack

JSON Hub Protocol utför typkonverteringar under deserialiseringen. Om det inkommande objektet till exempel har ett egenskapsvärde som är ett tal ({ foo: 42 }) men egenskapen för .NET-klassen är av typen stringkonverteras värdet. MessagePack utför dock inte den här konverteringen och utlöser ett undantag som kan visas i loggar på serversidan (och i konsolen):

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

Mer information om den här begränsningen finns i GitHub-problem aspnet/SignalR#2937.

Ytterligare resurser