Monday, August 13, 2018

Creating a MassTransit client/server application using RabbitMQ, .NET Core and Linux

Let's test the versatile MassTransit framework using RabbitMQ, .NET Core and Linux and see if it can serve as a reliable messaging system.
On a previous post we introduced MassTransit on this blog and presented and some reasons why it may be a real nice alternative to your system. Today we will review a simple use case: I will simulate a client/server arquitecture by building two console applications using MassTransit as the service bus, RabbitMQ as the transport running on Docker, .Net Core and Linux.

Sounds complicated? Let's take a look.

Installing RabbitMQ

The quickest way to install RabbitMQ locally is by using RabbitMQ's official Docker image. Assuming you have docker installed on your machine, pulling and running it is as simple as:
$ docker run --hostname rmqhost --name rmqcontainer -p 15672:15672 -p 5672:5672 rabbitmq:3.7.5-management
Before running that command, let's examine what each part means:
  • --hostname rmqhost : sets the host name
  • --name rmqcontainer : sets the name of the container
  • -p 15672:15672 : maps container port 15672 to host port 15672 so you can access on your localhost
  • -p 5672:5672 : maps container port 5672 to host port 5672 so you can access on your localhost
  • rabbitmq:3.7.5-management : the name of the image to donwload and run. I chose that one because it has a nice UI to manage RabbitMQ in case you want to play with it.
If you don't have that image yet, Docker will pull it for you and initialize a container based on the parameters above.

Once the download is complete, Docker will init RabbitMQ for us. On my Fedora box, I get:

With your image loaded and you can then access the Management UI on http://localhost:15672:
Type guest/guest as username/password, and you should be logged in:
Cool. Now that we have RabbitMQ running, let's take a look at MassTransit.

Building a shared .NET POCO Contract

Since we're building a client and a server, we also need to build a shared contract they can access. Because the client and the server may (and should) run on different servers, the common solution is to build a class library and reference it on both projects.

In .NET Core we simply type in the terminal:
dotnet new console -n MassTransit.RabbitMQ.Contracts
Then open that project and add this simple message:
That's it. Build that project to validate everything is ok and let's move to the client.

Building a MassTransit RabbitMQ Client

As previously said, the client will need to do two important things:
  • connect to the bus so it can start sending messages
  • send messages that the server recognizes. That's why we created the contract on the step above.
You can initialize your client with a command similar to the one executed above. Once you have your project created, the important bits are: adding a reference to the contract project previously created, initializing the bus and publishing a message to RabbitMQ.

Initializing the bus

To initialize the bus, write a code similar to:

Publishing a message

Now, we should be able to publish a message with a code like: Build this project with $ dotnet build to make sure everything is ok but don't run it yet. We still need to build the server.

Building a MassTransit RabbitMQ Server

The simple server is pretty similar to the client with the difference that:
  • the server does not publish messages
  • the server contains handlers (consumers) to messages published
Build a new console app and reference the contract project created above. The gist below shows how to init a service that will run on a console terminal and handle the CreateAccount message:

Testing!

Now, let's test both the client and the server to see if they're working ok. Don't forget that now you'll need your RabbitMQ instance running. I suggest running the apps side by side and let's see how that goes:

My Client App:
 My Server App:

And my RabbitMQ console:
So, from the above, you see that the messages sent from the client are reaching the server. Remember, those applications do not know about each other and the only coupling between them is the standalone contract project that both references.

Conclusion

That's it! My first experience with MassTransit was a breeze. I'm very satisfied so far with my experience with this framework and will probably write a post or two more to details other use cases (mainly sagas and error handling).

Feel free to download the source code used on this post directly from my GitHub page.

More about MassTransit?

 In case you're interested, consider reading:

See Also

For more posts about MassTransit, please click here.
Do you have any comment or suggestion about this post? Please contact me @BrunoHilden