Verwenden von MessagePack Hub Protocol in SignalR für ASP.NET Core

In diesem Artikel wird davon ausgegangen, dass der Leser mit den Themen vertraut ist, die unter Erste Schritte mit ASP.NET Core SignalRbehandelt werden.

Was ist MessagePack?

MessagePack ist ein schnelles und kompaktes binäres Serialisierungsformat. Dieses Format ist nützlich, wenn Leistung und Bandbreite eine Rolle spielen, da in ihm kleinere Nachrichten als in JSON erstellt werden. Die binären Nachrichten sind beim Untersuchen von Netzwerkablaufverfolgungen und Protokollen nicht lesbar, es sei denn, die Bytes werden über einen MessagePack-Parser übergeben. SignalR verfügt über integrierte Unterstützung für das MessagePack-Format und stellt APIs bereit, die vom Client und Server verwendet werden können.

Konfigurieren von MessagePack auf dem Server

Installieren Sie das Microsoft.AspNetCore.SignalR.Protocols.MessagePack-Paket in Ihrer App, um das MessagePack Hub Protocol auf dem Server zu aktivieren. Fügen Sie in der Startup.ConfigureServices-Methode dem AddSignalR-Aufruf AddMessagePackProtocol hinzu, um MessagePack-Unterstützung auf dem Server zu aktivieren.

services.AddSignalR()
    .AddMessagePackProtocol();

Hinweis

JSON ist standardmäßig aktiviert. Durch das Hinzufügen von MessagePack werden sowohl JSON- als auch MessagePack-Clients unterstützt.

Um anzupassen, wie MessagePack Daten formatiert, nimmt AddMessagePackProtocol einen Delegaten zum Konfigurieren von Optionen an. In diesem Delegaten wird die SerializerOptions-Eigenschaft verwendet, um MessagePack-Serialisierungsoptionen zu konfigurieren. Weitere Informationen zur Funktionsweise der Resolver finden Sie in der MessagePack-Bibliothek unter MessagePack-CSharp. Attribute können für die Objekte verwendet werden, die Sie serialisieren möchten, um zu definieren, wie sie behandelt werden sollen.

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

Warnung

Es wird dringend empfohlen, CVE-2020-5234 zu lesen und die empfohlenen Patches anzuwenden. Beispielsweise Aufrufen von .WithSecurity(MessagePackSecurity.UntrustedData), wenn SerializerOptions ersetzt wird.

Konfigurieren von MessagePack auf dem Client

Hinweis

JSON ist für die unterstützten Clients standardmäßig aktiviert. Clients können nur ein einziges Protokoll unterstützen. Das Hinzufügen von MessagePack-Unterstützung ersetzt alle zuvor konfigurierten Protokolle.

.NET-Client

Um MessagePack im .NET-Client zu aktivieren, installieren Sie das Microsoft.AspNetCore.SignalR.Protocols.MessagePack-Paket und rufen AddMessagePackProtocol für HubConnectionBuilder auf.

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

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

Hinweis

Dieser AddMessagePackProtocol-Aufruf nimmt einen Delegaten zum Konfigurieren von Optionen an, genau wie der Server.

JavaScript-Client

MessagePack-Unterstützung für den JavaScript-Client wird vom npm-Paket @microsoft/signalr-protocol-msgpack bereitgestellt. Installieren Sie das Paket, indem Sie den folgenden Befehl in einer Befehlsshell ausführen:

npm install @microsoft/signalr-protocol-msgpack

Nach der Installation des npm-Pakets kann das Modul direkt über einen JavaScript-Modulladeprogramm verwendet oder in den Browser importiert werden, indem auf die folgende Datei verwiesen wird:

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

Auf die folgenden erforderlichen JavaScript-Dateien muss in der unten gezeigten Reihenfolge verwiesen werden:

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

Wenn Sie .withHubProtocol(new signalR.protocols.msgpack.MessagePackHubProtocol()) zu HubConnectionBuilder hinzufügen, wird der Client für die Verwendung des MessagePack-Protokolls konfiguriert, wenn eine Verbindung mit einem Server hergestellt wird.

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

Derzeit gibt es keine Konfigurationsoptionen für das MessagePack-Protokoll auf dem JavaScript-Client.

Java-Client

Um MessagePack mit Java zu aktivieren, installieren Sie das com.microsoft.signalr.messagepack-Paket. Wenn Sie Gradle verwenden, fügen Sie dem Abschnitt dependencies der Datei build.gradle die folgende Zeile hinzu:

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

Wenn Sie Maven verwenden, fügen Sie die folgenden Zeilen innerhalb des <dependencies>-Elements der Datei pom.xml hinzu:

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

Rufen Sie withHubProtocol(new MessagePackHubProtocol()) für HubConnectionBuilder auf.

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

MessagePack-Überlegungen

Bei Verwendung von MessagePack Hub Protocol gibt es einige Punkte zu beachten.

Bei MessagePack wird zwischen Groß-und Kleinschreibung unterschieden.

Beim MessagePack-Protokoll wird zwischen Groß-und Kleinschreibung unterschieden. Betrachten Sie beispielsweise die folgende C#-Klasse:

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

Beim Senden vom JavaScript-Client müssen Sie PascalCased-Eigenschaftennamen verwenden, da die Groß- und Kleinschreibung genau mit der C#-Klasse übereinstimmen muss. Beispiel:

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

Bei Verwendung von camelCased-Namen wird nicht ordnungsgemäß an die C#-Klasse gebunden. Sie können dieses Problem umgehen, indem Sie das Key-Attribut verwenden, um einen anderen Namen für die MessagePack-Eigenschaft anzugeben. Weitere Informationen finden Sie in der Dokumentation zu MessagePack-CSharp.

DateTime.Kind wird beim Serialisieren/Deserialisieren nicht beibehalten.

Das MessagePack-Protokoll bietet keine Möglichkeit, den Kind-Wert eines DateTime-Elements zu codieren. Daher wird MessagePack Hub Protocol beim Deserialisieren eines Datums in das UTC-Format konvertiert, wenn DateTime.KindDateTimeKind.Local ist. Andernfalls wird die Uhrzeit nicht verändert und unverändert übergeben. Wenn Sie mit DateTime-Werten arbeiten, empfiehlt es sich, diese vor dem Senden in UTC zu konvertieren. Konvertieren Sie sie aus UTC in Ortszeit, wenn Sie sie empfangen.

MessagePack-Unterstützung in einer Vorabkompilierungsumgebung

Die MessagePack-CSharp-Bibliothek, die vom .NET-Client und -Server verwendet wird, verwendet Codegenerierung, um die Serialisierung zu optimieren. Daher wird sie in Umgebungen, in denen Vorabkompilierung verwendet wird (z. B. Xamarin iOS oder Unity), standardmäßig nicht unterstützt. Es ist möglich, MessagePack in diesen Umgebungen zu verwenden, indem der Serialisierungs-/Deserialisierungscode „vorab generiert“ wird. Weitere Informationen finden Sie in der Dokumentation zu MessagePack-CSharp. Nachdem Sie die Serialisierungsmodule vorab generiert haben, können Sie sie mithilfe des Konfigurationsdelegaten registrieren, der an AddMessagePackProtocol übergeben wird:

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);
    });

Typüberprüfungen sind in MessagePack strenger

Das JSON Hub-Protokoll führt während der Deserialisierung Typkonvertierungen durch. Wenn das eingehende Objekt beispielsweise über einen Eigenschaftswert verfügt, der eine Zahl ({ foo: 42 }) ist, die Eigenschaft der .NET-Klasse aber vom Typ string ist, wird der Wert konvertiert. MessagePack führt diese Konvertierung jedoch nicht durch und löst eine Ausnahme aus, die in serverseitigen Protokollen (und in der Konsole) angezeigt wird:

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

Weitere Informationen zu dieser Einschränkung finden Sie unter im GitHub-Issue aspnet/SignalR#2937.

Zeichen und Zeichenfolgen in Java

Im Java-Client werden char-Objekte als String-Objekte mit einem Zeichen serialisiert. Dies steht im Gegensatz zum C#- oder JavaScript-Client, der sie als short-Objekte serialisiert. Die MessagePack-Spezifikation selbst definiert das Verhalten für char-Objekte nicht, daher liegt es beim Autor der Bibliothek, festzulegen, wie diese serialisiert werden sollen. Der Unterschied im Verhalten zwischen unseren Clients ist ein Ergebnis der Bibliotheken, die wir für unsere Implementierungen verwendet haben.

Zusätzliche Ressourcen

In diesem Artikel wird davon ausgegangen, dass der Leser mit den Themen vertraut ist, die unter Erste Schritte mit ASP.NET Core SignalRbehandelt werden.

Was ist MessagePack?

MessagePack ist ein schnelles und kompaktes binäres Serialisierungsformat. Dieses Format ist nützlich, wenn Leistung und Bandbreite eine Rolle spielen, da in ihm kleinere Nachrichten im Vergleich zu JSON erstellt werden. Die binären Nachrichten sind beim Untersuchen von Netzwerkablaufverfolgungen und Protokollen nicht lesbar, es sei denn, die Bytes werden über einen MessagePack-Parser übergeben. SignalR verfügt über integrierte Unterstützung für das MessagePack-Format und stellt APIs bereit, die vom Client und Server verwendet werden können.

Konfigurieren von MessagePack auf dem Server

Installieren Sie das Microsoft.AspNetCore.SignalR.Protocols.MessagePack-Paket in Ihrer App, um das MessagePack Hub Protocol auf dem Server zu aktivieren. Fügen Sie in der Startup.ConfigureServices-Methode dem AddSignalR-Aufruf AddMessagePackProtocol hinzu, um MessagePack-Unterstützung auf dem Server zu aktivieren.

Hinweis

JSON ist standardmäßig aktiviert. Durch das Hinzufügen von MessagePack werden sowohl JSON- als auch MessagePack-Clients unterstützt.

services.AddSignalR()
    .AddMessagePackProtocol();

Um anzupassen, wie MessagePack Daten formatiert, nimmt AddMessagePackProtocol einen Delegaten zum Konfigurieren von Optionen an. In diesem Delegaten kann die SerializerOptions-Eigenschaft verwendet werden, um MessagePack-Serialisierungsoptionen zu konfigurieren. Weitere Informationen zur Funktionsweise der Resolver finden Sie in der MessagePack-Bibliothek unter MessagePack-CSharp. Attribute können für die Objekte verwendet werden, die Sie serialisieren möchten, um zu definieren, wie sie behandelt werden sollen.

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

Warnung

Es wird dringend empfohlen, CVE-2020-5234 zu lesen und die empfohlenen Patches anzuwenden. Beispielsweise Aufrufen von .WithSecurity(MessagePackSecurity.UntrustedData), wenn SerializerOptions ersetzt wird.

Konfigurieren von MessagePack auf dem Client

Hinweis

JSON ist für die unterstützten Clients standardmäßig aktiviert. Clients können nur ein einziges Protokoll unterstützen. Das Hinzufügen von MessagePack-Unterstützung ersetzt alle zuvor konfigurierten Protokolle.

.NET-Client

Um MessagePack im .NET-Client zu aktivieren, installieren Sie das Microsoft.AspNetCore.SignalR.Protocols.MessagePack-Paket und rufen AddMessagePackProtocol für HubConnectionBuilder auf.

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

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

Hinweis

Dieser AddMessagePackProtocol-Aufruf nimmt einen Delegaten zum Konfigurieren von Optionen an, genau wie der Server.

JavaScript-Client

MessagePack-Unterstützung für den JavaScript-Client wird vom npm-Paket @microsoft/signalr-protocol-msgpack bereitgestellt. Installieren Sie das Paket, indem Sie den folgenden Befehl in einer Befehlsshell ausführen:

npm install @microsoft/signalr-protocol-msgpack

Nach der Installation des npm-Pakets kann das Modul direkt über einen JavaScript-Modulladeprogramm verwendet oder in den Browser importiert werden, indem auf die folgende Datei verwiesen wird:

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

In einem Browser muss auch auf die msgpack5-Bibliothek verwiesen werden. Verwenden Sie ein <script>-Tag, um einen Verweis zu erstellen. Die Bibliothek finden Sie unter node_modules\msgpack5\dist\msgpack5.js.

Hinweis

Bei Verwendung des <script>-Elements ist die Reihenfolge wichtig. Wenn signalr-protocol-msgpack.js vor msgpack5.js referenziert wird, tritt beim Versuch, eine Verbindung mit MessagePack herzustellen, ein Fehler auf. signalr.js muss auch vor signalr-protocol-msgpack.js vorhanden sein.

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

Wenn Sie .withHubProtocol(new signalR.protocols.msgpack.MessagePackHubProtocol()) zu HubConnectionBuilder hinzufügen, wird der Client für die Verwendung des MessagePack-Protokolls konfiguriert, wenn eine Verbindung mit einem Server hergestellt wird.

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

Hinweis

Derzeit gibt es keine Konfigurationsoptionen für das MessagePack-Protokoll auf dem JavaScript-Client.

Java-Client

Um MessagePack mit Java zu aktivieren, installieren Sie das com.microsoft.signalr.messagepack-Paket. Wenn Sie Gradle verwenden, fügen Sie dem Abschnitt dependencies der Datei build.gradle die folgende Zeile hinzu:

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

Wenn Sie Maven verwenden, fügen Sie die folgenden Zeilen innerhalb des <dependencies>-Elements der Datei pom.xml hinzu:

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

Rufen Sie withHubProtocol(new MessagePackHubProtocol()) für HubConnectionBuilder auf.

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

MessagePack-Überlegungen

Bei Verwendung von MessagePack Hub Protocol gibt es einige Punkte zu beachten.

Bei MessagePack wird zwischen Groß-und Kleinschreibung unterschieden.

Beim MessagePack-Protokoll wird zwischen Groß-und Kleinschreibung unterschieden. Betrachten Sie beispielsweise die folgende C#-Klasse:

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

Beim Senden vom JavaScript-Client müssen Sie PascalCased-Eigenschaftennamen verwenden, da die Groß- und Kleinschreibung genau mit der C#-Klasse übereinstimmen muss. Beispiel:

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

Bei Verwendung von camelCased-Namen wird nicht ordnungsgemäß an die C#-Klasse gebunden. Sie können dieses Problem umgehen, indem Sie das Key-Attribut verwenden, um einen anderen Namen für die MessagePack-Eigenschaft anzugeben. Weitere Informationen finden Sie in der Dokumentation zu MessagePack-CSharp.

DateTime.Kind wird beim Serialisieren/Deserialisieren nicht beibehalten.

Das MessagePack-Protokoll bietet keine Möglichkeit, den Kind-Wert eines DateTime-Elements zu codieren. Daher wird MessagePack Hub Protocol beim Deserialisieren eines Datums in das UTC-Format konvertiert, wenn DateTime.KindDateTimeKind.Local ist. Andernfalls wird die Uhrzeit nicht verändert und unverändert übergeben. Wenn Sie mit DateTime-Werten arbeiten, empfiehlt es sich, diese vor dem Senden in UTC zu konvertieren. Konvertieren Sie sie aus UTC in Ortszeit, wenn Sie sie empfangen.

DateTime.MinValue wird von MessagePack in JavaScript nicht unterstützt.

Die vom SignalR-JavaScript-Client verwendete msgpack5-Bibliothek unterstützt den timestamp96-Typ in MessagePack nicht. Dieser Typ wird verwendet, um sehr große Datumswerte zu codieren (entweder sehr früh in der Vergangenheit oder sehr weit in der Zukunft). Der Wert von DateTime.MinValue ist January 1, 0001, der in einem timestamp96-Wert codiert werden muss. Aus diesem Grund wird das Senden von DateTime.MinValue an einen JavaScript-Client nicht unterstützt. Wenn DateTime.MinValue vom JavaScript-Client empfangen wird, wird der folgende Fehler ausgelöst:

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

In der Regel wird DateTime.MinValue verwendet, um einen „fehlenden“ oder null-Wert zu codieren. Wenn Sie diesen Wert in MessagePack codieren müssen, verwenden Sie einen Nullable-DateTime-Wert (DateTime?), oder codieren Sie einen separaten bool-Wert, der angibt, ob das Datum vorhanden ist.

Weitere Informationen zu dieser Einschränkung finden Sie unter im GitHub-Issue aspnet/SignalR#2228.

MessagePack-Unterstützung in einer Vorabkompilierungsumgebung

Die MessagePack-CSharp-Bibliothek, die vom .NET-Client und -Server verwendet wird, verwendet Codegenerierung, um die Serialisierung zu optimieren. Daher wird sie in Umgebungen, in denen Vorabkompilierung verwendet wird (z. B. Xamarin iOS oder Unity), standardmäßig nicht unterstützt. Es ist möglich, MessagePack in diesen Umgebungen zu verwenden, indem der Serialisierungs-/Deserialisierungscode „vorab generiert“ wird. Weitere Informationen finden Sie in der Dokumentation zu MessagePack-CSharp. Nachdem Sie die Serialisierungsmodule vorab generiert haben, können Sie sie mithilfe des Konfigurationsdelegaten registrieren, der an AddMessagePackProtocol übergeben wird:

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);
    });

Typüberprüfungen sind in MessagePack strenger

Das JSON Hub-Protokoll führt während der Deserialisierung Typkonvertierungen durch. Wenn das eingehende Objekt beispielsweise über einen Eigenschaftswert verfügt, der eine Zahl ({ foo: 42 }) ist, die Eigenschaft der .NET-Klasse aber vom Typ string ist, wird der Wert konvertiert. MessagePack führt diese Konvertierung jedoch nicht durch und löst eine Ausnahme aus, die in serverseitigen Protokollen (und in der Konsole) angezeigt wird:

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

Weitere Informationen zu dieser Einschränkung finden Sie unter im GitHub-Issue aspnet/SignalR#2937.

Zeichen und Zeichenfolgen in Java

Im Java-Client werden char-Objekte als String-Objekte mit einem Zeichen serialisiert. Dies steht im Gegensatz zum C#- oder JavaScript-Client, der sie als short-Objekte serialisiert. Die MessagePack-Spezifikation selbst definiert das Verhalten für char-Objekte nicht, daher liegt es beim Autor der Bibliothek, festzulegen, wie diese serialisiert werden sollen. Der Unterschied im Verhalten zwischen unseren Clients ist ein Ergebnis der Bibliotheken, die wir für unsere Implementierungen verwendet haben.

Zusätzliche Ressourcen

In diesem Artikel wird davon ausgegangen, dass der Leser mit den Themen vertraut ist, die unter Erste Schritte mit ASP.NET Core SignalRbehandelt werden.

Was ist MessagePack?

MessagePack ist ein schnelles und kompaktes binäres Serialisierungsformat. Dieses Format ist nützlich, wenn Leistung und Bandbreite eine Rolle spielen, da in ihm kleinere Nachrichten im Vergleich zu JSON erstellt werden. Die binären Nachrichten sind beim Untersuchen von Netzwerkablaufverfolgungen und Protokollen nicht lesbar, es sei denn, die Bytes werden über einen MessagePack-Parser übergeben. SignalR verfügt über integrierte Unterstützung für das MessagePack-Format und stellt APIs bereit, die vom Client und Server verwendet werden können.

Konfigurieren von MessagePack auf dem Server

Installieren Sie das Microsoft.AspNetCore.SignalR.Protocols.MessagePack-Paket in Ihrer App, um das MessagePack Hub Protocol auf dem Server zu aktivieren. Fügen Sie in der Startup.ConfigureServices-Methode dem AddSignalR-Aufruf AddMessagePackProtocol hinzu, um MessagePack-Unterstützung auf dem Server zu aktivieren.

Hinweis

JSON ist standardmäßig aktiviert. Durch das Hinzufügen von MessagePack werden sowohl JSON- als auch MessagePack-Clients unterstützt.

services.AddSignalR()
    .AddMessagePackProtocol();

Um anzupassen, wie MessagePack Daten formatiert, nimmt AddMessagePackProtocol einen Delegaten zum Konfigurieren von Optionen an. In diesem Delegaten kann die FormatterResolvers-Eigenschaft verwendet werden, um MessagePack-Serialisierungsoptionen zu konfigurieren. Weitere Informationen zur Funktionsweise der Resolver finden Sie in der MessagePack-Bibliothek unter MessagePack-CSharp. Attribute können für die Objekte verwendet werden, die Sie serialisieren möchten, um zu definieren, wie sie behandelt werden sollen.

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

Warnung

Es wird dringend empfohlen, CVE-2020-5234 zu lesen und die empfohlenen Patches anzuwenden. Legen Sie z. B. die statische MessagePackSecurity.Active-Eigenschaft auf MessagePackSecurity.UntrustedData fest. Das Festlegen von MessagePackSecurity.Active erfordert die manuelle Installation einer Version 1.9.x von MessagePack. Durch Installieren von MessagePack 1.9.x erfolgt ein Upgrade der Version, die SignalR verwendet. Mit Version 2.x von MessagePack wurden Breaking Changes eingeführt. Sie ist mit Version 3.1 und früher von SignalR nicht kompatibel. Wenn MessagePackSecurity.Active nicht auf MessagePackSecurity.UntrustedDatafestgelegt ist, kann ein böswilliger Client einen Denial-of-Service-Angriff verursachen. Legen Sie MessagePackSecurity.Active wie im folgenden Code gezeigt auf Program.Main fest:

using MessagePack;

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

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

Konfigurieren von MessagePack auf dem Client

Hinweis

JSON ist für die unterstützten Clients standardmäßig aktiviert. Clients können nur ein einziges Protokoll unterstützen. Das Hinzufügen von MessagePack-Unterstützung ersetzt alle zuvor konfigurierten Protokolle.

.NET-Client

Um MessagePack im .NET-Client zu aktivieren, installieren Sie das Microsoft.AspNetCore.SignalR.Protocols.MessagePack-Paket und rufen AddMessagePackProtocol für HubConnectionBuilder auf.

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

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

Hinweis

Dieser AddMessagePackProtocol-Aufruf nimmt einen Delegaten zum Konfigurieren von Optionen an, genau wie der Server.

JavaScript-Client

MessagePack-Unterstützung für den JavaScript-Client wird vom npm-Paket @microsoft/signalr-protocol-msgpack bereitgestellt. Installieren Sie das Paket, indem Sie den folgenden Befehl in einer Befehlsshell ausführen:

npm install @microsoft/signalr-protocol-msgpack

Nach der Installation des npm-Pakets kann das Modul direkt über einen JavaScript-Modulladeprogramm verwendet oder in den Browser importiert werden, indem auf die folgende Datei verwiesen wird:

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

In einem Browser muss auch auf die msgpack5-Bibliothek verwiesen werden. Verwenden Sie ein <script>-Tag, um einen Verweis zu erstellen. Die Bibliothek finden Sie unter node_modules\msgpack5\dist\msgpack5.js.

Hinweis

Bei Verwendung des <script>-Elements ist die Reihenfolge wichtig. Wenn signalr-protocol-msgpack.js vor msgpack5.js referenziert wird, tritt beim Versuch, eine Verbindung mit MessagePack herzustellen, ein Fehler auf. signalr.js muss auch vor signalr-protocol-msgpack.js vorhanden sein.

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

Wenn Sie .withHubProtocol(new signalR.protocols.msgpack.MessagePackHubProtocol()) zu HubConnectionBuilder hinzufügen, wird der Client für die Verwendung des MessagePack-Protokolls konfiguriert, wenn eine Verbindung mit einem Server hergestellt wird.

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

Hinweis

Derzeit gibt es keine Konfigurationsoptionen für das MessagePack-Protokoll auf dem JavaScript-Client.

MessagePack-Überlegungen

Bei Verwendung von MessagePack Hub Protocol gibt es einige Punkte zu beachten.

Bei MessagePack wird zwischen Groß-und Kleinschreibung unterschieden.

Beim MessagePack-Protokoll wird zwischen Groß-und Kleinschreibung unterschieden. Betrachten Sie beispielsweise die folgende C#-Klasse:

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

Beim Senden vom JavaScript-Client müssen Sie PascalCased-Eigenschaftennamen verwenden, da die Groß- und Kleinschreibung genau mit der C#-Klasse übereinstimmen muss. Beispiel:

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

Bei Verwendung von camelCased-Namen wird nicht ordnungsgemäß an die C#-Klasse gebunden. Sie können dieses Problem umgehen, indem Sie das Key-Attribut verwenden, um einen anderen Namen für die MessagePack-Eigenschaft anzugeben. Weitere Informationen finden Sie in der Dokumentation zu MessagePack-CSharp.

DateTime.Kind wird beim Serialisieren/Deserialisieren nicht beibehalten.

Das MessagePack-Protokoll bietet keine Möglichkeit, den Kind-Wert eines DateTime-Elements zu codieren. Daher geht MessagePack Hub Protocol beim Deserialisieren eines Datums davon aus, dass das eingehende Datum im UTC-Format vorliegt. Wenn Sie mit DateTime-Werten in Ortszeit arbeiten, empfiehlt es sich, diese vor dem Senden in UTC zu konvertieren. Konvertieren Sie sie aus UTC in Ortszeit, wenn Sie sie empfangen.

Weitere Informationen zu dieser Einschränkung finden Sie unter im GitHub-Issue aspnet/SignalR#2632.

DateTime.MinValue wird von MessagePack in JavaScript nicht unterstützt.

Die vom SignalR-JavaScript-Client verwendete msgpack5-Bibliothek unterstützt den timestamp96-Typ in MessagePack nicht. Dieser Typ wird verwendet, um sehr große Datumswerte zu codieren (entweder sehr früh in der Vergangenheit oder sehr weit in der Zukunft). Der Wert von DateTime.MinValue ist January 1, 0001, der in einem timestamp96-Wert codiert werden muss. Aus diesem Grund wird das Senden von DateTime.MinValue an einen JavaScript-Client nicht unterstützt. Wenn DateTime.MinValue vom JavaScript-Client empfangen wird, wird der folgende Fehler ausgelöst:

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

In der Regel wird DateTime.MinValue verwendet, um einen „fehlenden“ oder null-Wert zu codieren. Wenn Sie diesen Wert in MessagePack codieren müssen, verwenden Sie einen Nullable-DateTime-Wert (DateTime?), oder codieren Sie einen separaten bool-Wert, der angibt, ob das Datum vorhanden ist.

Weitere Informationen zu dieser Einschränkung finden Sie unter im GitHub-Issue aspnet/SignalR#2228.

MessagePack-Unterstützung in einer Vorabkompilierungsumgebung

Die MessagePack-CSharp-Bibliothek, die vom .NET-Client und -Server verwendet wird, verwendet Codegenerierung, um die Serialisierung zu optimieren. Daher wird sie in Umgebungen, in denen Vorabkompilierung verwendet wird (z. B. Xamarin iOS oder Unity), standardmäßig nicht unterstützt. Es ist möglich, MessagePack in diesen Umgebungen zu verwenden, indem der Serialisierungs-/Deserialisierungscode „vorab generiert“ wird. Weitere Informationen finden Sie in der Dokumentation zu MessagePack-CSharp. Nachdem Sie die Serialisierungsmodule vorab generiert haben, können Sie sie mithilfe des Konfigurationsdelegaten registrieren, der an AddMessagePackProtocol übergeben wird:

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

Typüberprüfungen sind in MessagePack strenger

Das JSON Hub-Protokoll führt während der Deserialisierung Typkonvertierungen durch. Wenn das eingehende Objekt beispielsweise über einen Eigenschaftswert verfügt, der eine Zahl ({ foo: 42 }) ist, die Eigenschaft der .NET-Klasse aber vom Typ string ist, wird der Wert konvertiert. MessagePack führt diese Konvertierung jedoch nicht durch und löst eine Ausnahme aus, die in serverseitigen Protokollen (und in der Konsole) angezeigt wird:

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

Weitere Informationen zu dieser Einschränkung finden Sie unter im GitHub-Issue aspnet/SignalR#2937.

Zusätzliche Ressourcen

In diesem Artikel wird davon ausgegangen, dass der Leser mit den Themen vertraut ist, die unter Erste Schritte mit ASP.NET Core SignalRbehandelt werden.

Was ist MessagePack?

MessagePack ist ein schnelles und kompaktes binäres Serialisierungsformat. Dieses Format ist nützlich, wenn Leistung und Bandbreite eine Rolle spielen, da in ihm kleinere Nachrichten im Vergleich zu JSON erstellt werden. Die binären Nachrichten sind beim Untersuchen von Netzwerkablaufverfolgungen und Protokollen nicht lesbar, es sei denn, die Bytes werden über einen MessagePack-Parser übergeben. SignalR verfügt über integrierte Unterstützung für das MessagePack-Format und stellt APIs bereit, die vom Client und Server verwendet werden können.

Konfigurieren von MessagePack auf dem Server

Installieren Sie das Microsoft.AspNetCore.SignalR.Protocols.MessagePack-Paket in Ihrer App, um das MessagePack Hub Protocol auf dem Server zu aktivieren. Fügen Sie in der Startup.ConfigureServices-Methode dem AddSignalR-Aufruf AddMessagePackProtocol hinzu, um MessagePack-Unterstützung auf dem Server zu aktivieren.

Hinweis

JSON ist standardmäßig aktiviert. Durch das Hinzufügen von MessagePack werden sowohl JSON- als auch MessagePack-Clients unterstützt.

services.AddSignalR()
    .AddMessagePackProtocol();

Um anzupassen, wie MessagePack Daten formatiert, nimmt AddMessagePackProtocol einen Delegaten zum Konfigurieren von Optionen an. In diesem Delegaten kann die FormatterResolvers-Eigenschaft verwendet werden, um MessagePack-Serialisierungsoptionen zu konfigurieren. Weitere Informationen zur Funktionsweise der Resolver finden Sie in der MessagePack-Bibliothek unter MessagePack-CSharp. Attribute können für die Objekte verwendet werden, die Sie serialisieren möchten, um zu definieren, wie sie behandelt werden sollen.

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

Warnung

Es wird dringend empfohlen, CVE-2020-5234 zu lesen und die empfohlenen Patches anzuwenden. Legen Sie z. B. die statische MessagePackSecurity.Active-Eigenschaft auf MessagePackSecurity.UntrustedData fest. Das Festlegen von MessagePackSecurity.Active erfordert die manuelle Installation einer Version 1.9.x von MessagePack. Durch Installieren von MessagePack 1.9.x erfolgt ein Upgrade der Version, die SignalR verwendet. Wenn MessagePackSecurity.Active nicht auf MessagePackSecurity.UntrustedDatafestgelegt ist, kann ein böswilliger Client einen Denial-of-Service-Angriff verursachen. Legen Sie MessagePackSecurity.Active wie im folgenden Code gezeigt auf Program.Main fest:

using MessagePack;

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

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

Konfigurieren von MessagePack auf dem Client

Hinweis

JSON ist für die unterstützten Clients standardmäßig aktiviert. Clients können nur ein einziges Protokoll unterstützen. Das Hinzufügen von MessagePack-Unterstützung ersetzt alle zuvor konfigurierten Protokolle.

.NET-Client

Um MessagePack im .NET-Client zu aktivieren, installieren Sie das Microsoft.AspNetCore.SignalR.Protocols.MessagePack-Paket und rufen AddMessagePackProtocol für HubConnectionBuilder auf.

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

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

Hinweis

Dieser AddMessagePackProtocol-Aufruf nimmt einen Delegaten zum Konfigurieren von Optionen an, genau wie der Server.

JavaScript-Client

MessagePack-Unterstützung für den JavaScript-Client wird vom npm-Paket @aspnet/signalr-protocol-msgpack bereitgestellt. Installieren Sie das Paket, indem Sie den folgenden Befehl in einer Befehlsshell ausführen:

npm install @aspnet/signalr-protocol-msgpack

Nach der Installation des npm-Pakets kann das Modul direkt über einen JavaScript-Modulladeprogramm verwendet oder in den Browser importiert werden, indem auf die folgende Datei verwiesen wird:

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

In einem Browser muss auch auf die msgpack5-Bibliothek verwiesen werden. Verwenden Sie ein <script>-Tag, um einen Verweis zu erstellen. Die Bibliothek finden Sie unter node_modules\msgpack5\dist\msgpack5.js.

Hinweis

Bei Verwendung des <script>-Elements ist die Reihenfolge wichtig. Wenn signalr-protocol-msgpack.js vor msgpack5.js referenziert wird, tritt beim Versuch, eine Verbindung mit MessagePack herzustellen, ein Fehler auf. signalr.js muss auch vor signalr-protocol-msgpack.js vorhanden sein.

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

Wenn Sie .withHubProtocol(new signalR.protocols.msgpack.MessagePackHubProtocol()) zu HubConnectionBuilder hinzufügen, wird der Client für die Verwendung des MessagePack-Protokolls konfiguriert, wenn eine Verbindung mit einem Server hergestellt wird.

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

Hinweis

Derzeit gibt es keine Konfigurationsoptionen für das MessagePack-Protokoll auf dem JavaScript-Client.

MessagePack-Überlegungen

Bei Verwendung von MessagePack Hub Protocol gibt es einige Punkte zu beachten.

Bei MessagePack wird zwischen Groß-und Kleinschreibung unterschieden.

Beim MessagePack-Protokoll wird zwischen Groß-und Kleinschreibung unterschieden. Betrachten Sie beispielsweise die folgende C#-Klasse:

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

Beim Senden vom JavaScript-Client müssen Sie PascalCased-Eigenschaftennamen verwenden, da die Groß- und Kleinschreibung genau mit der C#-Klasse übereinstimmen muss. Beispiel:

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

Bei Verwendung von camelCased-Namen wird nicht ordnungsgemäß an die C#-Klasse gebunden. Sie können dieses Problem umgehen, indem Sie das Key-Attribut verwenden, um einen anderen Namen für die MessagePack-Eigenschaft anzugeben. Weitere Informationen finden Sie in der Dokumentation zu MessagePack-CSharp.

DateTime.Kind wird beim Serialisieren/Deserialisieren nicht beibehalten.

Das MessagePack-Protokoll bietet keine Möglichkeit, den Kind-Wert eines DateTime-Elements zu codieren. Daher geht MessagePack Hub Protocol beim Deserialisieren eines Datums davon aus, dass das eingehende Datum im UTC-Format vorliegt. Wenn Sie mit DateTime-Werten in Ortszeit arbeiten, empfiehlt es sich, diese vor dem Senden in UTC zu konvertieren. Konvertieren Sie sie aus UTC in Ortszeit, wenn Sie sie empfangen.

Weitere Informationen zu dieser Einschränkung finden Sie unter im GitHub-Issue aspnet/SignalR#2632.

DateTime.MinValue wird von MessagePack in JavaScript nicht unterstützt.

Die vom SignalR-JavaScript-Client verwendete msgpack5-Bibliothek unterstützt den timestamp96-Typ in MessagePack nicht. Dieser Typ wird verwendet, um sehr große Datumswerte zu codieren (entweder sehr früh in der Vergangenheit oder sehr weit in der Zukunft). Der Wert von DateTime.MinValue ist January 1, 0001, der in einem timestamp96-Wert codiert werden muss. Aus diesem Grund wird das Senden von DateTime.MinValue an einen JavaScript-Client nicht unterstützt. Wenn DateTime.MinValue vom JavaScript-Client empfangen wird, wird der folgende Fehler ausgelöst:

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

In der Regel wird DateTime.MinValue verwendet, um einen „fehlenden“ oder null-Wert zu codieren. Wenn Sie diesen Wert in MessagePack codieren müssen, verwenden Sie einen Nullable-DateTime-Wert (DateTime?), oder codieren Sie einen separaten bool-Wert, der angibt, ob das Datum vorhanden ist.

Weitere Informationen zu dieser Einschränkung finden Sie unter im GitHub-Issue aspnet/SignalR#2228.

MessagePack-Unterstützung in einer Vorabkompilierungsumgebung

Die MessagePack-CSharp-Bibliothek, die vom .NET-Client und -Server verwendet wird, verwendet Codegenerierung, um die Serialisierung zu optimieren. Daher wird sie in Umgebungen, in denen Vorabkompilierung verwendet wird (z. B. Xamarin iOS oder Unity), standardmäßig nicht unterstützt. Es ist möglich, MessagePack in diesen Umgebungen zu verwenden, indem der Serialisierungs-/Deserialisierungscode „vorab generiert“ wird. Weitere Informationen finden Sie in der Dokumentation zu MessagePack-CSharp. Nachdem Sie die Serialisierungsmodule vorab generiert haben, können Sie sie mithilfe des Konfigurationsdelegaten registrieren, der an AddMessagePackProtocol übergeben wird:

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

Typüberprüfungen sind in MessagePack strenger

Das JSON Hub-Protokoll führt während der Deserialisierung Typkonvertierungen durch. Wenn das eingehende Objekt beispielsweise über einen Eigenschaftswert verfügt, der eine Zahl ({ foo: 42 }) ist, die Eigenschaft der .NET-Klasse aber vom Typ string ist, wird der Wert konvertiert. MessagePack führt diese Konvertierung jedoch nicht durch und löst eine Ausnahme aus, die in serverseitigen Protokollen (und in der Konsole) angezeigt wird:

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

Weitere Informationen zu dieser Einschränkung finden Sie unter im GitHub-Issue aspnet/SignalR#2937.

Zusätzliche Ressourcen