I ran into a strange issue today with RabbitMQ. When adding custom headers, I found that things like integers would get through to the other end just fine. But when it came to strings, they ended up as byte arrays in the receiving end.
To illustrate this issue, I’ve written a very simple example. The publisher, below, sets two custom headers: a string and an integer:
static void Main(string[] args) { Console.Title = "Publisher"; var factory = new ConnectionFactory(); using (var connection = factory.CreateConnection()) { using (var channel = connection.CreateModel()) { // prepare payload and headers var body = Encoding.UTF8.GetBytes("Hello"); var props = channel.CreateBasicProperties(); props.Headers = new Dictionary<string, object>(); props.Headers["Name"] = "Bob"; props.Headers["Age"] = 21; // set up queue and exchange channel.QueueDeclare("testqueue", true, false, false, null); channel.ExchangeDeclare("testexchange", "direct"); channel.QueueBind("testqueue", "testexchange", ""); // publish message channel.BasicPublish("testexchange", "", props, body); Console.ReadLine(); } } }
As you can see, this is set correctly in the Headers
collection:
Now that we’ve published a message, we can consume it using the following code (practically the same as that in “Getting Started with RabbitMQ with .NET“, except that it also writes out the two custom headers):
static void Main(string[] args) { Console.Title = "Consumer"; var factory = new ConnectionFactory(); using (var connection = factory.CreateConnection()) { using (var channel = connection.CreateModel()) { channel.QueueDeclare("testqueue", true, false, false, null); var consumer = new EventingBasicConsumer(channel); consumer.Received += Consumer_Received; channel.BasicConsume("testqueue", true, consumer); Console.ReadLine(); } } } private static void Consumer_Received(object sender, BasicDeliverEventArgs e) { var body = e.Body; var content = Encoding.UTF8.GetString(body); var name = e.BasicProperties.Headers["Name"]; var age = e.BasicProperties.Headers["Age"]; Console.WriteLine("{0} {1} {2}", name, age, content); }
The output, however, is not quite what one would expect:
In fact, what we received in the consumer is not a string but a byte array, even if the bytes correspond to what we actually sent:
The integer header, however, did not have this problem.
A quick search showed that I’m not the first person to encounter this, as someone pointed out this odd behaviour back in 2012, and it appears there’s a similar issue in the Python implementation.
All I can suggest based on these two links is: if you have a header which you know is a string, just do the byte-to-string conversion yourself:
private static void Consumer_Received(object sender, BasicDeliverEventArgs e) { var body = e.Body; var content = Encoding.UTF8.GetString(body); var nameBytes = (byte[]) e.BasicProperties.Headers["Name"]; var name = Encoding.UTF8.GetString(nameBytes); var age = e.BasicProperties.Headers["Age"]; Console.WriteLine("{0} {1} {2}", name, age, content); }
As you would expect, this sorts out the problem: