Usar o protocolo MessagePack Hub no SignalR para ASP.NET Core
Este artigo pressupõe que o leitor esteja familiarizado com os tópicos abordados em Introdução ao ASP.NET Core SignalR.
O que é MessagePack?
MessagePack é um formato de serialização binária rápido e compacto. É útil quando o desempenho e a largura de banda são uma preocupação porque cria mensagens menores do que JSON. As mensagens binárias são ilegíveis ao examinar rastreamentos de rede e logs, a menos que os bytes sejam passados por um analisador MessagePack. SignalR tem suporte interno para o formato MessagePack e fornece APIs para o cliente e o servidor usarem.
Configurar o MessagePack no servidor
Para habilitar o MessagePack Hub Protocol no servidor, instale o pacote Microsoft.AspNetCore.SignalR.Protocols.MessagePack
em seu aplicativo. No método Startup.ConfigureServices
, adicione AddMessagePackProtocol
à chamada AddSignalR
para habilitar o suporte ao MessagePack no servidor.
services.AddSignalR()
.AddMessagePackProtocol();
Observação
JSON está habilitado por padrão. Adicionar o MessagePack permite o suporte para clientes JSON e MessagePack.
Para personalizar como o MessagePack formata dados, AddMessagePackProtocol
aceita uma função delegada para definir opções. Nesse delegado, a propriedade SerializerOptions
é usada para configurar as opções de serialização do MessagePack. Para obter mais informações sobre como os resolvedores funcionam, visite a biblioteca MessagePack em MessagePack-CSharp. Os atributos podem ser usados nos objetos que você deseja serializar para definir como eles devem ser manipulados.
services.AddSignalR()
.AddMessagePackProtocol(options =>
{
options.SerializerOptions = MessagePackSerializerOptions.Standard
.WithResolver(new CustomResolver())
.WithSecurity(MessagePackSecurity.UntrustedData);
});
Advertência
É altamente recomendável revisar CVE-2020-5234 e aplicar os patches recomendados. Por exemplo, chamar .WithSecurity(MessagePackSecurity.UntrustedData)
ao substituir o SerializerOptions
.
Configurar o MessagePack no cliente
Observação
JSON é habilitado por padrão para os clientes suportados. Os clientes só podem suportar um único protocolo. Adicionar suporte ao MessagePack substitui todos os protocolos configurados anteriormente.
Cliente .NET
Para habilitar o MessagePack no cliente .NET, instale o pacote Microsoft.AspNetCore.SignalR.Protocols.MessagePack
e chame AddMessagePackProtocol
no HubConnectionBuilder
.
using Microsoft.AspNetCore.SignalR.Client;
using Microsoft.Extensions.DependencyInjection;
var hubConnection = new HubConnectionBuilder()
.WithUrl("/chathub")
.AddMessagePackProtocol()
.Build();
Observação
Esta chamada AddMessagePackProtocol
recebe um delegado para configurar opções de forma semelhante ao servidor.
Cliente JavaScript
O suporte do MessagePack para o cliente JavaScript é fornecido pelo pacote @microsoft/signalr-protocol-msgpack npm. Instale o pacote executando o seguinte comando em um shell de comando:
npm install @microsoft/signalr-protocol-msgpack
Depois de instalar o pacote npm, o módulo pode ser usado diretamente através de um carregador de módulos JavaScript ou importado para o navegador fazendo referência ao seguinte arquivo:
node_modules\@microsoft\signalr-protocol-msgpack\dist\browser\signalr-protocol-msgpack.js
Os seguintes arquivos javaScript necessários devem ser referenciados na ordem mostrada abaixo:
<script src="~/lib/signalr/signalr.js"></script>
<script src="~/lib/signalr/signalr-protocol-msgpack.js"></script>
Adicionar .withHubProtocol(new signalR.protocols.msgpack.MessagePackHubProtocol())
ao HubConnectionBuilder
configura o cliente para usar o protocolo MessagePack ao se conectar a um servidor.
const connection = new signalR.HubConnectionBuilder()
.withUrl("/chathub")
.withHubProtocol(new signalR.protocols.msgpack.MessagePackHubProtocol())
.build();
No momento, não há opções de configuração para o protocolo MessagePack no cliente JavaScript.
Cliente Java
Para habilitar o MessagePack com Java, instale o pacote com.microsoft.signalr.messagepack
. Ao usar o Gradle, adicione a seguinte linha à seção
implementation 'com.microsoft.signalr.messagepack:signalr-messagepack:5.0.0'
Ao usar o Maven, adicione as seguintes linhas dentro do elemento <dependencies>
do arquivo pom.xml
:
<dependency>
<groupId>com.microsoft.signalr.messagepack</groupId>
<artifactId>signalr</artifactId>
<version>5.0.0</version>
</dependency>
Ligue para withHubProtocol(new MessagePackHubProtocol())
em HubConnectionBuilder
.
HubConnection messagePackConnection = HubConnectionBuilder.create("YOUR HUB URL HERE")
.withHubProtocol(new MessagePackHubProtocol())
.build();
Considerações sobre o MessagePack
Há alguns problemas a serem observados ao usar o MessagePack Hub Protocol.
O MessagePack diferencia maiúsculas de minúsculas
O protocolo MessagePack diferencia maiúsculas de minúsculas. Por exemplo, considere a seguinte classe C#:
public class ChatMessage
{
public string Sender { get; }
public string Message { get; }
}
Ao enviar a partir do cliente JavaScript, deves usar os nomes de propriedade PascalCased
, já que a capitalização deve corresponder exatamente à classe C#. Por exemplo:
connection.invoke("SomeMethod", { Sender: "Sally", Message: "Hello!" });
O uso de nomes camelCased
não se vinculará corretamente à classe C#. Você pode contornar isso usando o atributo Key
para especificar um nome diferente para a propriedade MessagePack. Para obter mais informações, consulte a documentação MessagePack-CSharp.
DateTime.Kind não é preservado ao serializar/desserializar
O protocolo MessagePack não fornece uma maneira de codificar o valor Kind
de um DateTime
. Como resultado, ao desserializar uma data, o protocolo MessagePack Hub converte-la-á para o formato UTC se o DateTime.Kind
for DateTimeKind.Local
; caso contrário, não alterará a hora e passá-la-á como está. Se você estiver trabalhando com valores DateTime
, recomendamos converter para UTC antes de enviá-los. Converta-os de UTC para a hora local quando os receber.
Suporte ao MessagePack em ambiente de compilação antecipada
A biblioteca MessagePack-CSharp, utilizada pelo cliente e servidor .NET, emprega a geração de código para otimizar a serialização. Como resultado, ele não é suportado por padrão em ambientes que usam compilação "antecipada", como NET Multi-platform App UI (.NET MAUI) ou Unity. É possível usar o MessagePack nesses ambientes "pré-gerando" o código do serializador/desserializador. Para obter mais informações, consulte a documentação MessagePack-CSharp. Depois de pré-gerar os serializadores, você pode registrá-los usando o delegado de configuração passado para 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);
});
As verificações de tipo são mais rigorosas no MessagePack
O protocolo JSON Hub executará conversões de tipo durante a desserialização. Por exemplo, se o objeto de entrada tiver um valor de propriedade que seja um número ({ foo: 42 }
), mas a propriedade na classe .NET for do tipo string
, o valor será convertido. No entanto, o MessagePack não executa essa conversão e lançará uma exceção que pode ser vista nos logs do lado do servidor (e no console):
InvalidDataException: Error binding arguments. Make sure that the types of the provided values match the types of the hub method being invoked.
Para obter mais informações sobre essa limitação, consulte Problema do GitHub aspnet/SignalR#2937.
Caracteres e strings em Java
No cliente Java, os objetos char
serão serializados como objetos String
de um único caractere. Isso contrasta com o cliente C# e JavaScript, que os serializam como objetos short
. A especificação do MessagePack em si não define o comportamento para char
objetos, portanto, cabe ao autor da biblioteca determinar como serializá-los. A diferença de comportamento entre os nossos clientes é resultado das bibliotecas que usamos para as nossas implementações.
Recursos adicionais
Este artigo pressupõe que o leitor esteja familiarizado com os tópicos abordados em Introdução ao ASP.NET Core SignalR.
O que é MessagePack?
MessagePack é um formato de serialização binária rápido e compacto. É útil quando o desempenho e a largura de banda são uma preocupação porque cria mensagens menores em comparação com JSON. As mensagens binárias são ilegíveis ao examinar rastreamentos de rede e logs, a menos que os bytes sejam passados por um analisador MessagePack. SignalR tem suporte interno para o formato MessagePack e fornece APIs para o cliente e o servidor usarem.
Configurar o MessagePack no servidor
Para habilitar o MessagePack Hub Protocol no servidor, instale o pacote Microsoft.AspNetCore.SignalR.Protocols.MessagePack
em seu aplicativo. No método Startup.ConfigureServices
, adicione AddMessagePackProtocol
à chamada AddSignalR
para habilitar o suporte ao MessagePack no servidor.
Observação
JSON está habilitado por padrão. Adicionar o MessagePack permite o suporte para clientes JSON e MessagePack.
services.AddSignalR()
.AddMessagePackProtocol();
Para personalizar como o MessagePack formatará os seus dados, o AddMessagePackProtocol
aceita um delegado para configurar as opções. Nesse delegado, a propriedade SerializerOptions
pode ser usada para configurar as opções de serialização do MessagePack. Para obter mais informações sobre como os resolvedores funcionam, visite a biblioteca MessagePack em MessagePack-CSharp. Os atributos podem ser usados nos objetos que você deseja serializar para definir como eles devem ser manipulados.
services.AddSignalR()
.AddMessagePackProtocol(options =>
{
options.SerializerOptions = MessagePackSerializerOptions.Standard
.WithResolver(new CustomResolver())
.WithSecurity(MessagePackSecurity.UntrustedData);
});
Advertência
É altamente recomendável revisar CVE-2020-5234 e aplicar os patches recomendados. Por exemplo, chamar .WithSecurity(MessagePackSecurity.UntrustedData)
ao substituir o SerializerOptions
.
Configurar o MessagePack no cliente
Observação
JSON é habilitado por padrão para os clientes suportados. Os clientes só podem suportar um único protocolo. Adicionar suporte ao MessagePack substituirá todos os protocolos configurados anteriormente.
Cliente .NET
Para habilitar o MessagePack no cliente .NET, instale o pacote Microsoft.AspNetCore.SignalR.Protocols.MessagePack
e chame AddMessagePackProtocol
no HubConnectionBuilder
.
using Microsoft.AspNetCore.SignalR.Client;
using Microsoft.Extensions.DependencyInjection;
var hubConnection = new HubConnectionBuilder()
.WithUrl("/chathub")
.AddMessagePackProtocol()
.Build();
Observação
Esta chamada AddMessagePackProtocol
recebe um delegado para configurar opções de forma semelhante ao servidor.
Cliente JavaScript
O suporte do MessagePack para o cliente JavaScript é fornecido pelo pacote @microsoft/signalr-protocol-msgpack npm. Instale o pacote executando o seguinte comando em um shell de comando:
npm install @microsoft/signalr-protocol-msgpack
Depois de instalar o pacote npm, o módulo pode ser usado diretamente através de um carregador de módulos JavaScript ou importado para o navegador fazendo referência ao seguinte arquivo:
node_modules\@microsoft\signalr-protocol-msgpack\dist\browser\signalr-protocol-msgpack.js
Em um navegador, a biblioteca msgpack5
também deve ser referenciada. Use uma tag <script>
para criar uma referência. A biblioteca pode ser encontrada em node_modules\msgpack5\dist\msgpack5.js.
Observação
Ao usar o elemento <script>
, a ordem é importante. Se signalr-protocol-msgpack.js
for referenciado antes msgpack5.js
, ocorrerá um erro ao tentar se conectar com o MessagePack.
signalr.js
também é necessário antes 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>
Adicionar .withHubProtocol(new signalR.protocols.msgpack.MessagePackHubProtocol())
ao HubConnectionBuilder
configurará o cliente para usar o protocolo MessagePack ao se conectar a um servidor.
const connection = new signalR.HubConnectionBuilder()
.withUrl("/chathub")
.withHubProtocol(new signalR.protocols.msgpack.MessagePackHubProtocol())
.build();
Observação
No momento, não há opções de configuração para o protocolo MessagePack no cliente JavaScript.
Cliente Java
Para habilitar o MessagePack com Java, instale o pacote com.microsoft.signalr.messagepack
. Ao usar o Gradle, adicione a seguinte linha à seção
implementation 'com.microsoft.signalr.messagepack:signalr-messagepack:5.0.0'
Ao usar o Maven, adicione as seguintes linhas dentro do elemento <dependencies>
do arquivo pom.xml
:
<dependency>
<groupId>com.microsoft.signalr.messagepack</groupId>
<artifactId>signalr</artifactId>
<version>5.0.0</version>
</dependency>
Ligue para withHubProtocol(new MessagePackHubProtocol())
em HubConnectionBuilder
.
HubConnection messagePackConnection = HubConnectionBuilder.create("YOUR HUB URL HERE")
.withHubProtocol(new MessagePackHubProtocol())
.build();
Considerações sobre o MessagePack
Há alguns problemas a serem observados ao usar o MessagePack Hub Protocol.
O MessagePack diferencia maiúsculas de minúsculas
O protocolo MessagePack diferencia maiúsculas de minúsculas. Por exemplo, considere a seguinte classe C#:
public class ChatMessage
{
public string Sender { get; }
public string Message { get; }
}
Ao enviar a partir do cliente JavaScript, deves usar os nomes de propriedade PascalCased
, já que a capitalização deve corresponder exatamente à classe C#. Por exemplo:
connection.invoke("SomeMethod", { Sender: "Sally", Message: "Hello!" });
O uso de nomes camelCased
não se vinculará corretamente à classe C#. Você pode contornar isso usando o atributo Key
para especificar um nome diferente para a propriedade MessagePack. Para obter mais informações, consulte a documentação MessagePack-CSharp.
DateTime.Kind não é preservado ao serializar/desserializar
O protocolo MessagePack não fornece uma maneira de codificar o valor Kind
de um DateTime
. Como resultado, ao desserializar uma data, o protocolo MessagePack Hub converte-la-á para o formato UTC se o DateTime.Kind
for DateTimeKind.Local
; caso contrário, não alterará a hora e passá-la-á como está. Se você estiver trabalhando com valores DateTime
, recomendamos converter para UTC antes de enviá-los. Converta-os de UTC para a hora local quando os receber.
DateTime.MinValue não é suportado pelo MessagePack em JavaScript
A biblioteca msgpack5 usada pelo cliente JavaScript SignalR não suporta o tipo timestamp96
no MessagePack. Este tipo é usado para codificar valores de data muito grandes (muito cedo no passado ou muito longe no futuro). O valor de DateTime.MinValue
é January 1, 0001
, que deve ser codificado em um valor timestamp96
. Por isso, o envio de DateTime.MinValue
para um cliente JavaScript não é suportado. Quando DateTime.MinValue
é recebido pelo cliente JavaScript, o seguinte erro é gerado:
Uncaught Error: unable to find ext type 255 at decoder.js:427
Normalmente, DateTime.MinValue
é usado para codificar um valor "ausente" ou null
. Se você precisar codificar esse valor em MessagePack, use um valor de DateTime
anulável (DateTime?
) ou codifique um valor de bool
separado indicando se a data está presente.
Para obter mais informações sobre essa limitação, consulte Problema do GitHub aspnet/SignalR#2228.
Suporte ao MessagePack em ambiente de compilação antecipada
A biblioteca MessagePack-CSharp, utilizada pelo cliente e servidor .NET, emprega a geração de código para otimizar a serialização. Como resultado, ele não é suportado por padrão em ambientes que usam compilação "antecipada", como NET Multi-platform App UI (.NET MAUI) ou Unity. É possível usar o MessagePack nesses ambientes "pré-gerando" o código do serializador/desserializador. Para obter mais informações, consulte a documentação MessagePack-CSharp. Depois de pré-gerar os serializadores, você pode registrá-los usando o delegado de configuração passado para 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);
});
As verificações de tipo são mais rigorosas no MessagePack
O protocolo JSON Hub executará conversões de tipo durante a desserialização. Por exemplo, se o objeto de entrada tiver um valor de propriedade que seja um número ({ foo: 42 }
), mas a propriedade na classe .NET for do tipo string
, o valor será convertido. No entanto, o MessagePack não executa essa conversão e lançará uma exceção que pode ser vista nos logs do lado do servidor (e no console):
InvalidDataException: Error binding arguments. Make sure that the types of the provided values match the types of the hub method being invoked.
Para obter mais informações sobre essa limitação, consulte Problema do GitHub aspnet/SignalR#2937.
Caracteres e strings em Java
No cliente Java, os objetos char
serão serializados como objetos String
de um único caractere. Isso contrasta com o cliente C# e JavaScript, que os serializam como objetos short
. A especificação do MessagePack em si não define o comportamento para char
objetos, portanto, cabe ao autor da biblioteca determinar como serializá-los. A diferença de comportamento entre os nossos clientes é resultado das bibliotecas que usamos para as nossas implementações.
Recursos adicionais
Este artigo pressupõe que o leitor esteja familiarizado com os tópicos abordados em Introdução ao ASP.NET Core SignalR.
O que é MessagePack?
MessagePack é um formato de serialização binária rápido e compacto. É útil quando o desempenho e a largura de banda são uma preocupação porque cria mensagens menores em comparação com JSON. As mensagens binárias são ilegíveis ao examinar rastreamentos de rede e logs, a menos que os bytes sejam passados por um analisador MessagePack. SignalR tem suporte interno para o formato MessagePack e fornece APIs para o cliente e o servidor usarem.
Configurar o MessagePack no servidor
Para habilitar o MessagePack Hub Protocol no servidor, instale o pacote Microsoft.AspNetCore.SignalR.Protocols.MessagePack
em seu aplicativo. No método Startup.ConfigureServices
, adicione AddMessagePackProtocol
à chamada AddSignalR
para habilitar o suporte ao MessagePack no servidor.
Observação
JSON está habilitado por padrão. Adicionar o MessagePack permite o suporte para clientes JSON e MessagePack.
services.AddSignalR()
.AddMessagePackProtocol();
Para personalizar como o MessagePack formatará os seus dados, o AddMessagePackProtocol
aceita um delegado para configurar as opções. Nesse delegado, a propriedade FormatterResolvers
pode ser usada para configurar as opções de serialização do MessagePack. Para obter mais informações sobre como os resolvedores funcionam, visite a biblioteca MessagePack em MessagePack-CSharp. Os atributos podem ser usados nos objetos que você deseja serializar para definir como eles devem ser manipulados.
services.AddSignalR()
.AddMessagePackProtocol(options =>
{
options.FormatterResolvers = new List<MessagePack.IFormatterResolver>()
{
MessagePack.Resolvers.StandardResolver.Instance
};
});
Advertência
É altamente recomendável revisar CVE-2020-5234 e aplicar os patches recomendados. Por exemplo, definir a propriedade MessagePackSecurity.Active
static como MessagePackSecurity.UntrustedData
. A configuração do MessagePackSecurity.Active
requer a instalação manual de uma versão 1.9.x do MessagePack. A instalação do MessagePack
1.9.x atualiza a versão que SignalR usa.
MessagePack
versão 2.x introduziu alterações significativas e é incompatível com SignalR versões 3.1 e anteriores. Quando MessagePackSecurity.Active
não está definido como MessagePackSecurity.UntrustedData
, um cliente mal-intencionado pode causar uma negação de serviço. Defina MessagePackSecurity.Active
em Program.Main
, conforme mostrado no código a seguir:
using MessagePack;
public static void Main(string[] args)
{
MessagePackSecurity.Active = MessagePackSecurity.UntrustedData;
CreateHostBuilder(args).Build().Run();
}
Configurar o MessagePack no cliente
Observação
JSON é habilitado por padrão para os clientes suportados. Os clientes só podem suportar um único protocolo. Adicionar suporte ao MessagePack substituirá todos os protocolos configurados anteriormente.
Cliente .NET
Para habilitar o MessagePack no cliente .NET, instale o pacote Microsoft.AspNetCore.SignalR.Protocols.MessagePack
e chame AddMessagePackProtocol
no HubConnectionBuilder
.
using Microsoft.AspNetCore.SignalR.Client;
using Microsoft.Extensions.DependencyInjection;
var hubConnection = new HubConnectionBuilder()
.WithUrl("/chathub")
.AddMessagePackProtocol()
.Build();
Observação
Esta chamada AddMessagePackProtocol
recebe um delegado para configurar opções de forma semelhante ao servidor.
Cliente JavaScript
O suporte do MessagePack para o cliente JavaScript é fornecido pelo pacote @microsoft/signalr-protocol-msgpack npm. Instale o pacote executando o seguinte comando em um shell de comando:
npm install @microsoft/signalr-protocol-msgpack
Depois de instalar o pacote npm, o módulo pode ser usado diretamente através de um carregador de módulos JavaScript ou importado para o navegador fazendo referência ao seguinte arquivo:
node_modules\@microsoft\signalr-protocol-msgpack\dist\browser\signalr-protocol-msgpack.js
Em um navegador, a biblioteca msgpack5
também deve ser referenciada. Use uma tag <script>
para criar uma referência. A biblioteca pode ser encontrada em node_modules\msgpack5\dist\msgpack5.js.
Observação
Ao usar o elemento <script>
, a ordem é importante. Se signalr-protocol-msgpack.js
for referenciado antes msgpack5.js
, ocorrerá um erro ao tentar se conectar com o MessagePack.
signalr.js
também é necessário antes 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>
Adicionar .withHubProtocol(new signalR.protocols.msgpack.MessagePackHubProtocol())
ao HubConnectionBuilder
configurará o cliente para usar o protocolo MessagePack ao se conectar a um servidor.
const connection = new signalR.HubConnectionBuilder()
.withUrl("/chathub")
.withHubProtocol(new signalR.protocols.msgpack.MessagePackHubProtocol())
.build();
Observação
No momento, não há opções de configuração para o protocolo MessagePack no cliente JavaScript.
Considerações sobre o MessagePack
Há alguns problemas a serem observados ao usar o MessagePack Hub Protocol.
O MessagePack diferencia maiúsculas de minúsculas
O protocolo MessagePack diferencia maiúsculas de minúsculas. Por exemplo, considere a seguinte classe C#:
public class ChatMessage
{
public string Sender { get; }
public string Message { get; }
}
Ao enviar a partir do cliente JavaScript, deves usar os nomes de propriedade PascalCased
, já que a capitalização deve corresponder exatamente à classe C#. Por exemplo:
connection.invoke("SomeMethod", { Sender: "Sally", Message: "Hello!" });
O uso de nomes camelCased
não se vinculará corretamente à classe C#. Você pode contornar isso usando o atributo Key
para especificar um nome diferente para a propriedade MessagePack. Para obter mais informações, consulte a documentação MessagePack-CSharp.
DateTime.Kind não é preservado ao serializar/desserializar
O protocolo MessagePack não fornece uma maneira de codificar o valor Kind
de um DateTime
. Como resultado, ao desserializar uma data, o MessagePack Hub Protocol assume que a data de entrada está no formato UTC. Se estiver a trabalhar com valores de DateTime
na hora local, recomendamos converter para UTC antes de os enviar. Converta-os de UTC para a hora local quando os receber.
Para obter mais informações sobre essa limitação, consulte Problema do GitHub aspnet/SignalR#2632.
DateTime.MinValue não é suportado pelo MessagePack em JavaScript
A biblioteca msgpack5 usada pelo cliente JavaScript SignalR não suporta o tipo timestamp96
no MessagePack. Este tipo é usado para codificar valores de data muito grandes (muito cedo no passado ou muito longe no futuro). O valor de DateTime.MinValue
é January 1, 0001
, que deve ser codificado em um valor timestamp96
. Por isso, o envio de DateTime.MinValue
para um cliente JavaScript não é suportado. Quando DateTime.MinValue
é recebido pelo cliente JavaScript, o seguinte erro é gerado:
Uncaught Error: unable to find ext type 255 at decoder.js:427
Normalmente, DateTime.MinValue
é usado para codificar um valor "ausente" ou null
. Se você precisar codificar esse valor em MessagePack, use um valor de DateTime
anulável (DateTime?
) ou codifique um valor de bool
separado indicando se a data está presente.
Para obter mais informações sobre essa limitação, consulte Problema do GitHub aspnet/SignalR#2228.
Suporte ao MessagePack em ambiente de compilação antecipada
A biblioteca MessagePack-CSharp, utilizada pelo cliente e servidor .NET, emprega a geração de código para otimizar a serialização. Como resultado, ele não é suportado por padrão em ambientes que usam compilação "antecipada", como NET Multi-platform App UI (.NET MAUI) ou Unity. É possível usar o MessagePack nesses ambientes "pré-gerando" o código do serializador/desserializador. Para obter mais informações, consulte a documentação MessagePack-CSharp. Depois de pré-gerar os serializadores, você pode registrá-los usando o delegado de configuração passado para AddMessagePackProtocol
:
services.AddSignalR()
.AddMessagePackProtocol(options =>
{
options.FormatterResolvers = new List<MessagePack.IFormatterResolver>()
{
MessagePack.Resolvers.GeneratedResolver.Instance,
MessagePack.Resolvers.StandardResolver.Instance
};
});
As verificações de tipo são mais rigorosas no MessagePack
O protocolo JSON Hub executará conversões de tipo durante a desserialização. Por exemplo, se o objeto de entrada tiver um valor de propriedade que seja um número ({ foo: 42 }
), mas a propriedade na classe .NET for do tipo string
, o valor será convertido. No entanto, o MessagePack não executa essa conversão e lançará uma exceção que pode ser vista nos logs do lado do servidor (e no console):
InvalidDataException: Error binding arguments. Make sure that the types of the provided values match the types of the hub method being invoked.
Para obter mais informações sobre essa limitação, consulte Problema do GitHub aspnet/SignalR#2937.
Recursos adicionais
Este artigo pressupõe que o leitor esteja familiarizado com os tópicos abordados em Introdução ao ASP.NET Core SignalR.
O que é MessagePack?
MessagePack é um formato de serialização binária rápido e compacto. É útil quando o desempenho e a largura de banda são uma preocupação porque cria mensagens menores em comparação com JSON. As mensagens binárias são ilegíveis ao examinar rastreamentos de rede e logs, a menos que os bytes sejam passados por um analisador MessagePack. SignalR tem suporte interno para o formato MessagePack e fornece APIs para o cliente e o servidor usarem.
Configurar o MessagePack no servidor
Para habilitar o MessagePack Hub Protocol no servidor, instale o pacote Microsoft.AspNetCore.SignalR.Protocols.MessagePack
em seu aplicativo. No método Startup.ConfigureServices
, adicione AddMessagePackProtocol
à chamada AddSignalR
para habilitar o suporte ao MessagePack no servidor.
Observação
JSON está habilitado por padrão. Adicionar o MessagePack permite o suporte para clientes JSON e MessagePack.
services.AddSignalR()
.AddMessagePackProtocol();
Para personalizar como o MessagePack formatará os seus dados, o AddMessagePackProtocol
aceita um delegado para configurar as opções. Nesse delegado, a propriedade FormatterResolvers
pode ser usada para configurar as opções de serialização do MessagePack. Para obter mais informações sobre como os resolvedores funcionam, visite a biblioteca MessagePack em MessagePack-CSharp. Os atributos podem ser usados nos objetos que você deseja serializar para definir como eles devem ser manipulados.
services.AddSignalR()
.AddMessagePackProtocol(options =>
{
options.FormatterResolvers = new List<MessagePack.IFormatterResolver>()
{
MessagePack.Resolvers.StandardResolver.Instance
};
});
Advertência
É altamente recomendável revisar CVE-2020-5234 e aplicar os patches recomendados. Por exemplo, definir a propriedade MessagePackSecurity.Active
static como MessagePackSecurity.UntrustedData
. A configuração do MessagePackSecurity.Active
requer a instalação manual de uma versão 1.9.x do MessagePack. A instalação do MessagePack
1.9.x atualiza a versão que SignalR usa. Quando MessagePackSecurity.Active
não está definido como MessagePackSecurity.UntrustedData
, um cliente mal-intencionado pode causar uma negação de serviço. Defina MessagePackSecurity.Active
em Program.Main
, conforme mostrado no código a seguir:
using MessagePack;
public static void Main(string[] args)
{
MessagePackSecurity.Active = MessagePackSecurity.UntrustedData;
CreateHostBuilder(args).Build().Run();
}
Configurar o MessagePack no cliente
Observação
JSON é habilitado por padrão para os clientes suportados. Os clientes só podem suportar um único protocolo. Adicionar suporte ao MessagePack substituirá todos os protocolos configurados anteriormente.
Cliente .NET
Para habilitar o MessagePack no cliente .NET, instale o pacote Microsoft.AspNetCore.SignalR.Protocols.MessagePack
e chame AddMessagePackProtocol
no HubConnectionBuilder
.
using Microsoft.AspNetCore.SignalR.Client;
using Microsoft.Extensions.DependencyInjection;
var hubConnection = new HubConnectionBuilder()
.WithUrl("/chathub")
.AddMessagePackProtocol()
.Build();
Observação
Esta chamada AddMessagePackProtocol
recebe um delegado para configurar opções de forma semelhante ao servidor.
Cliente JavaScript
O suporte do MessagePack para o cliente JavaScript é fornecido pelo pacote @aspnet/signalr-protocol-msgpack npm. Instale o pacote executando o seguinte comando em um shell de comando:
npm install @aspnet/signalr-protocol-msgpack
Depois de instalar o pacote npm, o módulo pode ser usado diretamente através de um carregador de módulos JavaScript ou importado para o navegador fazendo referência ao seguinte arquivo:
node_modules\@aspnet\signalr-protocol-msgpack\dist\browser\signalr-protocol-msgpack.js
Em um navegador, a biblioteca msgpack5
também deve ser referenciada. Use uma tag <script>
para criar uma referência. A biblioteca pode ser encontrada em node_modules\msgpack5\dist\msgpack5.js.
Observação
Ao usar o elemento <script>
, a ordem é importante. Se signalr-protocol-msgpack.js
for referenciado antes msgpack5.js
, ocorrerá um erro ao tentar se conectar com o MessagePack.
signalr.js
também é necessário antes 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>
Adicionar .withHubProtocol(new signalR.protocols.msgpack.MessagePackHubProtocol())
ao HubConnectionBuilder
configurará o cliente para usar o protocolo MessagePack ao se conectar a um servidor.
const connection = new signalR.HubConnectionBuilder()
.withUrl("/chathub")
.withHubProtocol(new signalR.protocols.msgpack.MessagePackHubProtocol())
.build();
Observação
No momento, não há opções de configuração para o protocolo MessagePack no cliente JavaScript.
Considerações sobre o MessagePack
Há alguns problemas a serem observados ao usar o MessagePack Hub Protocol.
O MessagePack diferencia maiúsculas de minúsculas
O protocolo MessagePack diferencia maiúsculas de minúsculas. Por exemplo, considere a seguinte classe C#:
public class ChatMessage
{
public string Sender { get; }
public string Message { get; }
}
Ao enviar a partir do cliente JavaScript, deves usar os nomes de propriedade PascalCased
, já que a capitalização deve corresponder exatamente à classe C#. Por exemplo:
connection.invoke("SomeMethod", { Sender: "Sally", Message: "Hello!" });
O uso de nomes camelCased
não se vinculará corretamente à classe C#. Você pode contornar isso usando o atributo Key
para especificar um nome diferente para a propriedade MessagePack. Para obter mais informações, consulte a documentação MessagePack-CSharp.
DateTime.Kind não é preservado ao serializar/desserializar
O protocolo MessagePack não fornece uma maneira de codificar o valor Kind
de um DateTime
. Como resultado, ao desserializar uma data, o MessagePack Hub Protocol assume que a data de entrada está no formato UTC. Se estiver a trabalhar com valores de DateTime
na hora local, recomendamos converter para UTC antes de os enviar. Converta-os de UTC para a hora local quando os receber.
Para obter mais informações sobre essa limitação, consulte Problema do GitHub aspnet/SignalR#2632.
DateTime.MinValue não é suportado pelo MessagePack em JavaScript
A biblioteca msgpack5 usada pelo cliente JavaScript SignalR não suporta o tipo timestamp96
no MessagePack. Este tipo é usado para codificar valores de data muito grandes (muito cedo no passado ou muito longe no futuro). O valor de DateTime.MinValue
é January 1, 0001
, que deve ser codificado em um valor de timestamp96
. Por isso, o envio de DateTime.MinValue
para um cliente JavaScript não é suportado. Quando DateTime.MinValue
é recebido pelo cliente JavaScript, o seguinte erro é gerado:
Uncaught Error: unable to find ext type 255 at decoder.js:427
Normalmente, DateTime.MinValue
é usado para codificar um valor "ausente" ou null
. Se você precisar codificar esse valor em MessagePack, use um valor de DateTime
anulável (DateTime?
) ou codifique um valor de bool
separado indicando se a data está presente.
Para obter mais informações sobre essa limitação, consulte Problema do GitHub aspnet/SignalR#2228.
Suporte ao MessagePack em ambiente de compilação antecipada
A biblioteca MessagePack-CSharp, utilizada pelo cliente e servidor .NET, emprega a geração de código para otimizar a serialização. Como resultado, ele não é suportado por padrão em ambientes que usam compilação "antecipada", como NET Multi-platform App UI (.NET MAUI) ou Unity. É possível usar o MessagePack nesses ambientes "pré-gerando" o código do serializador/desserializador. Para obter mais informações, consulte a documentação MessagePack-CSharp. Depois de pré-gerar os serializadores, você pode registrá-los usando o delegado de configuração passado para AddMessagePackProtocol
:
services.AddSignalR()
.AddMessagePackProtocol(options =>
{
options.FormatterResolvers = new List<MessagePack.IFormatterResolver>()
{
MessagePack.Resolvers.GeneratedResolver.Instance,
MessagePack.Resolvers.StandardResolver.Instance
};
});
As verificações de tipo são mais rigorosas no MessagePack
O protocolo JSON Hub executará conversões de tipo durante a desserialização. Por exemplo, se o objeto de entrada tiver um valor de propriedade que seja um número ({ foo: 42 }
), mas a propriedade na classe .NET for do tipo string
, o valor será convertido. No entanto, o MessagePack não executa essa conversão e lançará uma exceção que pode ser vista nos logs do lado do servidor (e no console):
InvalidDataException: Error binding arguments. Make sure that the types of the provided values match the types of the hub method being invoked.
Para obter mais informações sobre essa limitação, consulte Problema do GitHub aspnet/SignalR#2937.