Skip to main content

MessagePack | Custom Protocol | WebSocket | SignalR | CSharp

  • Protocolo binário oficial para alta performance

O que muda ao usar MessagePack

AspectoJSONMessagePack
FormatoTextoBinário
TamanhoMaiorMenor
PerformanceMédiaAlta
LegibilidadeAltaNenhuma
CompatibilidadeAltaMais restrita

👉 MessagePack reduz payload e CPU de serialização.


1. Pacotes necessários

Servidor:

dotnet add package Microsoft.AspNetCore.SignalR.Protocols.MessagePack

Cliente:

dotnet add package Microsoft.AspNetCore.SignalR.Client
dotnet add package Microsoft.AspNetCore.SignalR.Protocols.MessagePack

2. Configuração no servidor

var builder = WebApplication.CreateBuilder(args);

builder.Services
.AddSignalR()
.AddMessagePackProtocol(options =>
{
// opcional: customizações
});

var app = builder.Build();

app.MapHub<ComandoHub>("/hub/comandos");

app.Run();

3. Hub de exemplo

using Microsoft.AspNetCore.SignalR;

public sealed class ComandoHub : Hub
{
public async Task EnviarComando(string comando)
{
await Clients.Caller.SendAsync("ReceberComando", comando);
}
}

4. Cliente .NET com MessagePack

using Microsoft.AspNetCore.SignalR.Client;

var connection = new HubConnectionBuilder()
.WithUrl("https://localhost:5001/hub/comandos")
.AddMessagePackProtocol()
.Build();

connection.On<string>("ReceberComando", mensagem =>
{
Console.WriteLine($"Recebido: {mensagem}");
});

await connection.StartAsync();

await connection.InvokeAsync("EnviarComando", "SELECT * FROM PRODUTOS");

Console.ReadLine();

5. Usando DTOs (muito importante)

MessagePack funciona melhor com objetos estruturados.


DTO simples

public class ComandoDto
{
public string Sql { get; set; } = default!;
public Guid RequestId { get; set; }
}

Hub

public async Task EnviarComando(ComandoDto dto)
{
await Clients.Caller.SendAsync("ReceberComando", dto);
}

Cliente

connection.On<ComandoDto>("ReceberComando", dto =>
{
Console.WriteLine(dto.Sql);
});

6. Versão otimizada (recomendada)

Para máxima performance, use atributos do MessagePack:

dotnet add package MessagePack

DTO otimizado

using MessagePack;

[MessagePackObject]
public class ComandoDto
{
[Key(0)]
public string Sql { get; set; } = default!;

[Key(1)]
public Guid RequestId { get; set; }
}

Por que isso é melhor

  • Evita reflection
  • Serialização mais rápida
  • Payload menor
  • Controle total da ordem dos campos

7. Configuração avançada

builder.Services
.AddSignalR()
.AddMessagePackProtocol(options =>
{
options.SerializerOptions = MessagePack.MessagePackSerializerOptions.Standard
.WithCompression(MessagePack.MessagePackCompression.Lz4BlockArray);
});

8. Problemas comuns (importante)

❌ Problema 1 — Case sensitivity

public string Nome { get; set; }

Se o cliente tiver:

public string nome { get; set; }

👉 Vai falhar (diferente do JSON)


❌ Problema 2 — Versionamento

[Key(0)] string Sql
[Key(1)] Guid RequestId

Se você mudar ordem ou remover:

👉 Quebra compatibilidade


✔ Regra

  • Nunca mudar os Key
  • Apenas adicionar novos com índices novos

❌ Problema 3 — Tipos não suportados

Alguns tipos complexos exigem resolver manualmente:

  • interfaces
  • tipos abstratos
  • objetos dinâmicos

9. Comparação prática

Payload JSON:

{
"sql": "SELECT *",
"requestId": "guid"
}

Payload MessagePack:

(binary compactado, ~40-60% menor)

10. Quando usar (seu caso)

Pelo seu cenário (SignalR + alto volume + muitos clientes):

👉 Use MessagePack quando:

  • 1000+ conexões
  • payload frequente
  • baixa latência é importante
  • tráfego alto

👉 NÃO use quando:

  • precisa debugar tráfego facilmente
  • integra com clientes não .NET
  • precisa de flexibilidade extrema

Regra final

  • JSON → simplicidade
  • MessagePack → performance
  • Custom Protocol → raríssimo