A C# Programmer's Guide to Installing, Running and Messaging with RabbitMQ
Tags: csharp, messagequeue, rabbitmq
Published: 2019-11-27 08:11:13

If you're looking at message brokers, most of the big cloud providers have an offering: Microsoft, Google, AWS, I assume even Oracle and IBM!  However, if you want, or need to host something locally then your choice is still pretty limited.

I have previously done some research on <a href="http://thelongwalk.tech/2016/09/29/a-c-programmers-guide-to-installing-running-and-messaging-with-activemq/">Active MQ</a>, this post looks at RabbitMQ, and how you might set that up, and add or read a message from the queue.

Install from <a href="https://www.rabbitmq.com/install-windows.html">here</a>.

You also need to install <a href="http://www.erlang.org/downloads">Erlang</a>.

After the install... nothing happens.  No matter how long you wait, assuming it's just your slow laptop (don't want to talk about that anymore).  Navigate to:

<a href="http://pmichaels.net/wp-content/uploads/2016/10/rabbitmq1.png"><img src="http://pmichaels.net/wp-content/uploads/2016/10/rabbitmq1-300x121.png" alt="rabbitmq1" width="300" height="121" class="alignnone size-medium wp-image-1502" /></a>

```
C:\Program Files\RabbitMQ Server\rabbitmq_server-3.6.0\sbin
```

In a DOS prompt, type:

```
rabbitmq-plugins enable rabbitmq_management
```

<a href="http://pmichaels.net/wp-content/uploads/2016/10/rabbitmq2.png"><img src="http://pmichaels.net/wp-content/uploads/2016/10/rabbitmq2-300x197.png" alt="rabbitmq2" width="300" height="197" class="alignnone size-medium wp-image-1501" /></a>

Rabbit will now run as a service, which also feels much cleaner that ActiveMQs console app style interface.

Now, log-in to <a href="http://localhost:15672/">http://localhost:15672/</a>, and log-in as guest/guest:


<a href="http://pmichaels.net/wp-content/uploads/2016/10/rabbitmq3.png"><img src="http://pmichaels.net/wp-content/uploads/2016/10/rabbitmq3-300x151.png" alt="rabbitmq3" width="300" height="151" class="alignnone size-medium wp-image-1500" /></a>


<h1>Code</h1>

Just like with ActiveMQ, there is a NuGet package that you can use for interacting with the exchange:

<a href="https://www.nuget.org/packages/RabbitMQ.Client">https://www.nuget.org/packages/RabbitMQ.Client</a>.  Your project needs to be .Net Core, or Framework .Net 4.5.1 or higher; otherwise, you'll see this:

<a href="http://pmichaels.net/wp-content/uploads/2016/10/rabbitmq4.png"><img src="http://pmichaels.net/wp-content/uploads/2016/10/rabbitmq4-300x27.png" alt="rabbitmq4" width="300" height="27" class="alignnone size-medium wp-image-1499" /></a>

If it's not, upgrade your project to 4.5.1:

<a href="http://pmichaels.net/wp-content/uploads/2016/10/rabbitmq5.png"><img src="http://pmichaels.net/wp-content/uploads/2016/10/rabbitmq5-300x114.png" alt="rabbitmq5" width="300" height="114" class="alignnone size-medium wp-image-1498" /></a>


Okay, so now we're up and running, here's the code for the send:

```csharp
static void Main(string[] args)
{            
    while (true)
    {
        string msg = Console.ReadLine();
        if (string.IsNullOrWhiteSpace(msg))
        {
            break;
        }
 
        SendNewMessage(msg);
    } 
    
}
private static void SendNewMessage(string message)
{
    var factory = new ConnectionFactory() { HostName = "localhost" };
    using (var connection = factory.CreateConnection())
    using (var channel = connection.CreateModel())
    {
        var result = channel.QueueDeclare("NewQueue", true, false, false, null);
        Console.WriteLine(result);
 
        channel.BasicPublish("", "NewQueue", null, Encoding.UTF8.GetBytes(message));                
 
    }
}
```

Just like with ActiveMQ, you can now just look at the queue:

<a href="http://pmichaels.net/wp-content/uploads/2016/10/rabbitmq6.png"><img src="http://pmichaels.net/wp-content/uploads/2016/10/rabbitmq6-300x176.png" alt="rabbitmq6" width="300" height="176" class="alignnone size-medium wp-image-1497" /></a>

A quick caveat here:

```csharp

var result = channel.QueueDeclare("NewQueue");
```

<a href="http://stackoverflow.com/questions/10067454/rabbitmq-message-is-not-appearing-in-the-queue-from-c-sharp">Doesn't work</a> because exclusive defaults to 'true', meaning that only your session can see it.


<h1>Receiving a Message</h1>


```csharp

static void Main(string[] args)
{
    while (true)
    {
        ReceiveNextMessage();
 
        string exit = Console.ReadLine();
        if (!string.IsNullOrWhiteSpace(exit)) break;
    }
 
}
 
private static void ReceiveNextMessage()
{
    var factory = new ConnectionFactory() { HostName = "localhost" };
    using (var connection = factory.CreateConnection())
    using (var channel = connection.CreateModel())
    {
        var result = channel.QueueDeclare("NewQueue", true, false, false, null);
        Console.WriteLine(result);
 
        EventingBasicConsumer consumer = new EventingBasicConsumer(channel);
        consumer.Received += Consumer_Received;
 
        channel.BasicConsume("NewQueue", true, consumer);
 
        System.Threading.Thread.Sleep(1000);
 
    }
}
 
private static void Consumer_Received(object sender, BasicDeliverEventArgs e)
{
    var body = e.Body;
    var message = Encoding.UTF8.GetString(body);
    Console.WriteLine(message);
}
```

<a href="http://pmichaels.net/wp-content/uploads/2016/10/rabbitmq7.png"><img src="http://pmichaels.net/wp-content/uploads/2016/10/rabbitmq7-300x212.png" alt="rabbitmq7" width="300" height="212" class="alignnone size-medium wp-image-1496" /></a>


Why the Thread.Sleep?  The reason is that, because the message consumer is event based, you need to stop tidying up the objects until you're done.  Obviously, sleeping for 1 second has its issues.  I suspect this could be better achieved using a <a href="http://thelongwalk.tech/2016/06/01/taskcompletionsource/">TaskCompletionSource</a>, of even just a Console.ReadLine(), but for the purposes of this post, it suffices.

<h1>Topics</h1>

The concept of topics seems to be the same as ActiveMQ; however, the implementation is different, and there were a few dead-ends to go down first.

The following code, for example:

```csharp

var factory = new ConnectionFactory() { HostName = "localhost" };
using (var connection = factory.CreateConnection())
using (var channel = connection.CreateModel())
{
    channel.ExchangeDeclare("NewTopic", "testTopic");
    
    channel.BasicPublish("NewTopic", "test", null, Encoding.UTF8.GetBytes(message));
 
}
```

Gives the error: COMMAND_INVALID - unknown exchange type 'testTopic'

<a href="http://pmichaels.net/wp-content/uploads/2016/10/rabbitmq8.png"><img src="http://pmichaels.net/wp-content/uploads/2016/10/rabbitmq8-300x78.png" alt="rabbitmq8" width="300" height="78" class="alignnone size-medium wp-image-1495" /></a>


RabbitMQ seems to have some magic strings that determine the message type.  This works:

```csharp
 
private static void SendNewTopic(string message)
{
var factory = new ConnectionFactory() { HostName = "localhost" };
using (var connection = factory.CreateConnection())
using (var channel = connection.CreateModel())
{
    channel.ExchangeDeclare("NewTopic", "topic"); // topic is a magic string
    
    channel.BasicPublish("NewTopic", "test", null, Encoding.UTF8.GetBytes(message));
 
}
```

The "test" is a routing code.  These seem to be quite an involved system; however, it basically tells the exchange where the message is going.

<a href="http://pmichaels.net/wp-content/uploads/2016/10/rabbitmq9.png"><img src="http://pmichaels.net/wp-content/uploads/2016/10/rabbitmq9-300x218.png" alt="rabbitmq9" width="300" height="218" class="alignnone size-medium wp-image-1494" /></a>


<h1>Receive</h1>

```csharp

private static void ReceiveNextTopic()
{
    var factory = new ConnectionFactory() { HostName = "localhost" };
    using (var connection = factory.CreateConnection())
    using (var channel = connection.CreateModel())
    {
        channel.ExchangeDeclare("NewTopic", "topic");
        var queueName = channel.QueueDeclare().QueueName;
 
        channel.QueueBind(queue: queueName,
                        exchange: "NewTopic",
                        routingKey: "test");
 
        EventingBasicConsumer consumer = new EventingBasicConsumer(channel);
        consumer.Received += Consumer_Received;
 
        channel.BasicConsume(queueName, true, consumer);
 
        Console.ReadLine();
    }
}

private static void Consumer_Received(object sender, BasicDeliverEventArgs e)
{
    var body = e.Body;
    var message = Encoding.UTF8.GetString(body);
    Console.WriteLine(message);
}
```


Notice the routing key; this (broadly speaking) needs to match the sender's routing key.  The purpose seems to be to allow a complex mapping between publisher and subscriber.

<strong>Conclusion</strong>

In comparison to ActiveMQ, RabbitMQ seems to be a more actively maintained code base; a quick comparison of the GitHub repo of each reveals more activity in Rabbit.  Rabbit also seems a little cleaner in the way it's run and installed; however, it also seems to have more moving parts.

There are a number of companies that <a href="https://www.rabbitmq.com/services.html">offer support for ActiveMQ commercially</a>; however, the company that wrote RabbitMQ offer commercial support, should you need it.


<h1>Can you run Active and RabbitMQ together?</h1>

No.  No, you can't.  They both seem to want to use the same resources, and so if you want to use them both on the same machine, you can, but only one at a time.


<h1>Acknowledgements</h1>

I used the following websites extensively in this article:

<a href="http://arcware.net/installing-rabbitmq-on-windows/">http://arcware.net/installing-rabbitmq-on-windows/<a>

<a href="https://www.rabbitmq.com/tutorials/tutorial-one-dotnet.html">https://www.rabbitmq.com/tutorials/tutorial-one-dotnet.html</a>


This article was originally posted <a href="https://www.pmichaels.net/2016/10/07/a-c-programmers-guide-to-installing-running-and-messaging-with-rabbitmq/">here</a>