How to deserialize SignalR messages from Redis backplane

247 Views Asked by At

I need to read published messages by SignalR from Redis backplane. But they have strange format for me. Example:

"\x92\x90\x81\xa4json\xc4\x83{\"type\":1,\"target\":\"ReceiveGroupMessage\",\"arguments\":[{\"senderId\":null,\"message\":\"hello\",\"sentAt\":\"2023-07-22T16:48:08.7001126Z\"}]}\x1e"

Most of content is JSON, but what about start and the end? What is this, what it means and how can I deserialize it?

I tried:

var result = MessagePackSerializer.Deserialize<object>(value);

where value is RedisValue from subscription callback. But it results with:result

so I don't know how can I extract the value from json key.

That's whole code:

public class RedisSaveMessageBackgroundService : BackgroundService
{
    private readonly IConfiguration _configuration;
    private readonly IConnectionMultiplexer _connectionMultiplexer;

    public RedisSaveMessageBackgroundService(IConfiguration configuration,
        IConnectionMultiplexer connectionMultiplexer)
    {
        _configuration = configuration;
        _connectionMultiplexer = connectionMultiplexer;
    }

    protected override async Task ExecuteAsync(CancellationToken stoppingToken)
    {
        using (var connection = new NpgsqlConnection(_configuration.GetConnectionString("YugabyteDB")))
        {
            connection.Open();

            static async void Handler(RedisChannel channel, RedisValue value)
            {
                if (value == default)
                    return;

                var message = ReadMessage(value);
                await connection.ExecuteAsync(SQL_INSERT); // details omitted
            }

            var subscriber = _connectionMultiplexer.GetSubscriber();
            await subscriber.SubscribeAsync(new RedisChannel("*SignalRHub.MessagingHub:user:*", RedisChannel.PatternMode.Pattern), Handler);
            await subscriber.SubscribeAsync(new RedisChannel("*SignalRHub.MessagingHub:group:*", RedisChannel.PatternMode.Pattern), Handler);
        }

        await Task.Delay(Timeout.Infinite, stoppingToken);
    }

    private static Message ReadMessage(RedisValue value)
    {
        // What here
        throw new NotImplementedException();
    }
}
2

There are 2 best solutions below

5
Jason Pan On BEST ANSWER

Please try to use below code.

    public IActionResult testmsg()
    {
        string input = "\x92\x90\x81\xa4json\xc4\x83{\"type\":1,\"target\":\"ReceiveGroupMessage\",\"arguments\":[{\"senderId\":null,\"message\":\"hello\",\"sentAt\":\"2023-07-22T16:48:08.7001126Z\"}]}\x1e";

        // Step 1: Remove the unwanted characters
        int startIndex = input.IndexOf('{'); // Find the starting index of the JSON part
        int endIndex = input.LastIndexOf('}'); // Find the ending index of the JSON part
        string jsonPart = input.Substring(startIndex, endIndex - startIndex + 1); // Extract the JSON part

        // Step 2: Convert the JSON to a C# object
        var result = JsonConvert.DeserializeObject<CustomMessage>(jsonPart);

        return Ok(result);
    }
    private class CustomMessage
    {
        public int type { get; set; }
        public string target { get; set; }
        public List<RedisMessage> arguments { get; set; }
    }
    private class RedisMessage
    {
        public string senderId { get; set; }
        public string message { get; set; }
        public DateTime sentAt { get; set; }
    }
1
Elham Beydaghi On

The message is a MessagePack-encoded binary message that contains a JSON payload. The "\x92" and "\x90" bytes at the beginning of the message are part of the MessagePack header and indicate that the message is an array with two elements. The "\x81" byte indicates that the first element of the array is a map with one key-value pair. The key is the string "json" and the value is a MessagePack-encoded string that contains the JSON payload. The "\xc4\x83" bytes indicate that the string is 3 bytes long. for using it , you can install NuGet package MessagePack and then use MessagePackSerializer class like this :

var dictionary = MessagePackSerializer.Deserialize<Dictionary<object, object>>(yourInput);