Integrating .NET Core with RabbitMQ - Part 2/2

Views: 126

Table of Contents

Part 1: AMQP and RabbitMQ

Part 2: RabbitMQ Prerequisites and Demo Project



In the previous article, you got to know what are AMQP and RabbitMQ. Now, warm up that grey matter and get ready to test out that newly acquired knowledge and start coding.

Installing RabbitMQ Prerequisites

In this tutorial, we will show you how to install RabbitMQ in Windows. It can be installed using two options: one is with Chocolatey (an optimal installation method); and the other is by using the installer, which we will be doing in this post. If you’re on a different operating system, you can visit RabbitMQ official website.

  1. Download and install Erlang/OTP 22.1 (or higher) for Windows Binary File, and run it in an administrative account.
  2. Download and install Latest RabbitMQ Server. As of this writing, the latest version is 3.8.1, which we will be installing.
  3. Once the installation is complete, check RabbitMQ Status by going to RabbitMQ Command Prompt and typing: rabbitmqctl.bat status.



Creating a Demo Project using Visual Studio 2019

This part of the tutorial will now guide you on how to create a demo project with Visual Studio 2019.

  1. Create two .Net Core Console applications in one solution—one Sender project and one Receiver project.

  2. Next, install the RabbitMQ package in both projects. In the Visual Studio toolbar, click>Tools>Nuget Package Manager>Package Manager Console.

  3. Select the target project where the RabbitMQ.client package is to be installed. Start by choosing Sender in the Default Project option, type install-package RabbitMQ.Client, then press Enter. Once the package is installed, do the same for the Receiver project by choosing Receiver this time in the Default Project in the Package Manager Console.

  4. Once the package is installed in both projects, go to the Sender project, open Program.cs, paste the following lines of code, and examine:

    using RabbitMQ.Client;
    using System;
    using System.Text;
    namespace Sender
    {
      class Program
      {
        public static void Main(string[] args)
        {
          var factory = new ConnectionFactory() { HostName = "localhost" }; // If your broker resides on a different machine, you can specify the name or the IP address.
          using (var connection = factory.CreateConnection()) // Creates the RabbitMQ connection
          using (var channel = connection.CreateModel()) // Creates a channel, which is where most of the API for getting things done resides.
          {
            //Declares the queue
            channel.QueueDeclare(queue: "hello", // The name of the queue
                durable: false, // true if we are declaring a durable queue(the queue will survive a server restart)
                exclusive: false, // true if we are declaring an exclusive queue (restricted to this connection)
                autoDelete: false, // true if we are declaring an auto delete queue (server will delete it when no longer in use)
                arguments: null); // other properties for the queue
    
            Console.WriteLine("Please enter your message. Type 'exit' to exit.");
            while (true)
            {
              //Converts message to byte array
              string message = Console.ReadLine();
              if (message?.ToUpper() == "EXIT")
              {
                  break;
              }
    
                var body = Encoding.UTF8.GetBytes(message);
    
                //Publish message
                channel.BasicPublish(exchange: "", // the exchange to publish the message to
    
                                     routingKey: "hello", // the routing key
                                     basicProperties: null, // other properties for the message
                                     body: body); // the message body
    
                Console.WriteLine("Sent: {0}", message);
            }
          }
        }
      }
    }


  5. In the Receiver project, open Program.cs, paste the following lines of code and examine:

    using RabbitMQ.Client;
    using RabbitMQ.Client.Events;
    using System;
    using System.Text;
    using System.Threading;
    namespace Receiver
    {
        class Program
        {
            public static void Main(string[] args)
            {
                var factory = new ConnectionFactory() { HostName = "localhost" }; // If your broker resides on a different machine, you can specify the name or the IP address.
                using (var connection = factory.CreateConnection()) // Creates the RabbitMQ connection
                using (var channel = connection.CreateModel()) // Creates a channel, which is where most of the API for getting things done resides.
                {
                    // We will also have to declare the queue here,
                    // because this application might start first so we will make sure that the queue exists before receiving messages.
                    channel.QueueDeclare(queue: "hello", // The name of the queue
                                         durable: false, // true if we are declaring a durable queue(the queue will survive a server restart)
                                         exclusive: false, // true if we are declaring an exclusive queue (restricted to this connection)
                                         autoDelete: false, // true if we are declaring an auto delete queue (server will delete it when no longer in use)
                                         arguments: null); // other properties (construction arguments) for the queue
    
                    var consumer = new EventingBasicConsumer(channel);
                    // Callback
                    consumer.Received += (model, ea) =>
                    {
                        var body = ea.Body;
                        var message = Encoding.UTF8.GetString(body);
                        Console.WriteLine("Received: {0}", message);
                    };
    
                    // Start receiving messages
                    channel.BasicConsume(queue: "hello", // the name of the queue
                                         autoAck: true, // true if the server should consider messages acknowledged once delivered;
                                         //false if the server should expect explicit acknowledgements
                                         consumer: consumer); // an interface to the consumer object
                    Console.WriteLine("Press [enter] to exit.");
                    Console.ReadLine();
                }
            }
        }
    }


  1. After examining, run both projects. You can run each project using Virtual Studio by selecting the startup project and pressing CTRL+F5.

  2. Alternatively, you may also run the projects using the console. To do this, right-click Receiver project, then click ‘Open folder in file explorer’. In the Address bar of the file explorer tab, type cmd, press Enter, then type dotnet run. Follow the same process for the Sender project.

  3. Finally, you can now start sending and receiving messages through RabbitMQ.



Using the Computer Name or IP Address as Hostname

There may be instances when you would prefer to use the Computer Name or IP Address in the connection. By default however, RabbitMQ does not allow guests to connect remotely. When you run the application in this scenario, it will return with an error message that says: “ACCESS_REFUSED - Login was refused using authentication mechanism PLAIN. For details see the broker log file.”

Note that a guest user can only connect from the localhost by default. This is to limit well-known credential use in production systems. To be able to use the computer name or IP Address as hostname in client applications, you need to connect to the host with credentials.

To add a user to RabbitMQ, open the RabbitMQ Command Prompt and paste each line.

  1. To create a user named ‘testuser’ with password ‘topsecretpassword’:

    rabbitmqctl add_user testuser topsecretpassword 
  2. To set a user as administrator:

    rabbitmqctl set_user_tags testuser administrator
  3. To set permission to user:

    rabbitmqctl set_permissions -p / testuser ".*" ".*" ".*" 

Another way to add a user is to use the RabbitMQ Management in the browser. We will show this in the next part.

Using RabbitMQ Management

  1. Start by enabling RabbitMQ Management. In the Start menu, search for the RabbitMQ Command Prompt and type:

    rabbitmq-plugins.bat enable rabbitmq_management

    Then press Enter.

  2. Next, open the browser and go to http://localhost:15672/.

  3. Log in using the default guest account.

    Username: guest
    Password: guest

  4. Go to the Admin Tab> expand ‘Add a user’> and fill in the user’s details.

  5. Click ‘Add user’ and the user will be saved to RabbitMQ’s database. You should be able to see the newly-added user in the Users section. To add a permission for that user, click on the user’s name.

  6. Now go back to Visual Studio. Overwrite these lines of code (see figure below) in both projects in Program.cs, using the new user account and password you just created through the command line or using RabbitMQ Management.

  7. Run the two projects, and this time, it should not return the “ACCESS_ REFUSED...” error message previously encountered.



Creating and Using Work Queues (Task Queues)

In this section of the tutorial, we will show you how to create a Work Queue that can be used to distribute time-consuming tasks among multiple workers. One of the advantages of using a Task Queue is the ability to easily parallelise work. So in case there is a buildup of backlog work, more workers can be added, allowing you to scale effortlessly.

  1. In the previous sections, we created our Sender and Receiver projects in one solution. Now, we will add 2 two more console projects for our work queue demo. For this example we will name these projects — ‘Worker’ and ‘NewTask’.

  2. Add RabbitMQ.Client package to both new projects.

  3. Expand the Worker project, go to program.cs, and paste these lines of code:

    using RabbitMQ.Client;
    using RabbitMQ.Client.Events;
    using System;
    using System.Text;
    using System.Threading;
    
    namespace Worker
    {
      class Program
      {
        private const string hostName = "RANDRINO-PC", userName = "roylandandrino", password = "topsecretpassword";
        public static void Main(string[] args)
        {
          var factory = new ConnectionFactory() { HostName = hostName, UserName = userName, Password = password };
          using (var connection = factory.CreateConnection()) // Creates the RabbitMQ connection
          using (var channel = connection.CreateModel()) // Creates a channel, which is where most of the API for getting things done resides.
          {
            // We will also have to declare the queue here,
            // because this application might start first so we will make sure that the queue exists before receiving messages.
            channel.QueueDeclare(queue: "task_queue", // The name of the queue
                        durable: false, // true if we are declaring a durable queue(the queue will survive a server restart)
                        exclusive: false, // true if we are declaring an exclusive queue (restricted to this connection)
                        autoDelete: false, // true if we are declaring an auto delete queue (server will delete it when no longer in use)
                        arguments: null); // other properties (construction arguments) for the queue
    
            var consumer = new EventingBasicConsumer(channel);
            // Callback
            consumer.Received += (model, ea) =>
            {
              var body = ea.Body;
              var message = Encoding.UTF8.GetString(body);
              Console.Write("Received: {0}", message);
    
              Thread.Sleep(5000); // Our fake task that will finish every 5 seconds.
              Console.WriteLine(" [Done]"); // When task is done, displays [done].
            };
    
            // Start receiving messages
            channel.BasicConsume(queue: "task_queue", // the name of the queue
                        autoAck: true,  // true if the server should consider messages acknowledged once delivered;
                                    //false if the server should expect explicit acknowledgements
                        consumer: consumer); // an interface to the consumer object
    
            Console.WriteLine("Waiting for message/s.");
            Console.ReadLine();
          }
        }
      }
    }


  4. Next, expand the New Task project, go to program.cs, and paste these lines of code:

    using RabbitMQ.Client;
    using System;
    using System.Text;
    
    namespace NewTask
    {
      class Program
      {
        private const string hostName = "RANDRINO-PC", userName = "roylandandrino", password = "topsecretpassword";
        public static void Main(string[] args)
        {
          var factory = new ConnectionFactory() { HostName = hostName, UserName = userName, Password = password };
          using (var connection = factory.CreateConnection()) // Creates the RabbitMQ connection
          using (var channel = connection.CreateModel()) // Creates a channel, which is where most of the API for getting things done resides.
          {
            Console.WriteLine("Please enter your message. Type 'exit' to exit.");
            //Declares the queue
            channel.QueueDeclare(queue: "task_queue", // The name of the queue
                        durable: false, // true if we are declaring a durable queue(the queue will survive a server restart)
                        exclusive: false, // true if we are declaring an exclusive queue (restricted to this connection)
                        autoDelete: false, // true if we are declaring an auto delete queue (server will delete it when no longer in use)
                        arguments: null); // other properties for the queue
    
            var properties = channel.CreateBasicProperties();
            properties.Persistent = true;
    
            while (true)
            {
              string message = Console.ReadLine();
              if(message?.ToUpper() == "EXIT")
              {
                break;
              }
    
              var body = Encoding.UTF8.GetBytes(message); // Converts message to byte array
    
              //Publish message
              channel.BasicPublish(exchange: "", // the exchange to publish the message to
                            routingKey: "task_queue", // the routing key
                            basicProperties: properties, // other properties for the message
                            body: body); // the message body
            }
          }
        }
      }
    }


  5. Run the Worker project three times and the New Task project two times by selecting the project (Worker or New Task) and pressing CTRL+F5.

    The windows should appear like this:

    Enter messages in the New Task/Sender as many times as you can, and see how RabbitMQ will distribute each message to every Worker in sequence. This process is called round robin.

Message Acknowledgements

Now once you send messages and a worker is still processing the task, killing the worker will cause it to lose the messages it was processing at that moment. Since you don’t want to lose the task, you should ensure that the task continues and is transferred to a new running worker.

To make sure that a message is never lost, RabbitMQ supports message acknowledgments. An ack (or acknowledgement) is returned by the consumer to inform RabbitMQ that a particular message has been received and processed, and that RabbitMQ is free to delete it.

If a consumer dies (i.e., its channel is closed, the connection is closed, or the TCP connection is lost) without sending an ack, RabbitMQ will understand that the message wasn't fully processed, and there is a need to re-queue it. If there are other consumers online at the same time, RabbitMQ will then quickly re-deliver it to another consumer. This way you can be sure that no message is lost, even if workers occasionally die.

There are no message timeouts—RabbitMQ will redeliver the message when a consumer dies. So it's fine even if processing a message takes a very, very long time.

Manual message acknowledgments are turned on by default. In previous examples, we explicitly turned them off by setting the autoAck ("automatic acknowledgement mode") parameter to true so that message acknowledgements are sent automatically. Now we remove this flag and have the worker manually send a proper acknowledgment once a task is done.

To do this, add this line in program.cs in the Worker project:

channel.BasicAck(deliveryTag: ea.DeliveryTag, multiple: false);

Then set autoAck value to false.

With the use of channel.BasicAck, you can be sure that even if you kill a worker (using CTRL+C) while it is in the middle of processing a message, nothing will be lost. All unacknowledged messages will be redelivered soon after the worker dies.

The channel.BasicQoS parameter allows you to specify the quality of service you require in sending messages. Refer to the figure above to find out what each of these values indicate.

preFetchSize: The server will send a message in advance if it is equal to or smaller in size than the available prefetch size (and also falls into other prefetch limits). This may be set to zero, meaning "no specific limit", although other prefetch limits may still apply. The prefetch-size is ignored if the no-ack option is set.

preFetchCount: Specifies a prefetch window in terms of whole messages. This field may be used in combination with the prefetch-size field; a message will only be sent in advance if both prefetch windows (and those at the channel and connection level) allow it. The prefetch-count is ignored if the no-ack option is set.

Global: "By default the QoS settings apply to the current channel only. If this field is set, they are applied to the entire connection." Instead, RabbitMQ takes global=false to mean that the QoS settings should apply per-consumer (for new consumers on the channel; existing ones being unaffected) and global=true to mean that the QoS settings should apply per-channel.



Creating a GUID Sender and Receiver Demo Project

In this project, we will guide you in creating a GUID sender that sends a message every 5 seconds. We will also be setting durable:true and Persistent=true, and see how the messages (GUID) will be received and how they will survive when RabbitMQ service restarts.

  1. In GUIDMessenger solution, add two console projects named ‘Guid.Sender’, ‘Guid.Receiver’ and a .Net Core Class Library named ‘Guid.Core’.

  2. Install RabbitMQ.Client package to the Guid.Core project.

  3. In the Guid.Core project, add a class named ApplicationSettings.cs. This class will hold the RabbitMQ Credentials from the appSettings.json file in the Guid.Sender and Guid.Receiver. Later on, we will set this up in our service collection.

  4. Add an appSettings.json file in the respective root directories of both Guid.Sender and Guid.Receiver projects.

    Then add these lines to both json files.

  5. In the Guid.Core project, add a folder named ‘Interfaces’ and add the necessary interfaces for our projects.

    public interface IReceiver
        {
            public void Receive();
        }
    public interface ISender
        {
            public void Send();
        }
    public interface IWorker
        {
            void Run();
        }
        public interface IRunner : IDisposable
        {
            void Run(TimerCallback waitCallback);
        }


  6. Create another folder named ‘Services’ and add our implementations. Then add a class named MessageReceiver.cs and put in these lines.

    using Guid.Core.Interfaces;
    
    namespace Guid.Core.Services
    {
      public class MessageReceiver : IWorker
      {
        private readonly IReceiver receiver;
        public MessageReceiver(IReceiver receiver)
        {
          this.receiver = receiver;
        }
        public void Run()
        {
          receiver.Receive("Arcanys");
        }
      }
    }


  7. Now add a class named TimedMessageSender.cs and add the lines below. This implementation of IWorker will create a number of sender actions and invoke them to execute in parallel using ‘Parallel.Invoke’.

    using System;
    using System.Threading.Tasks;
    using Guid.Core.Interfaces;
    
    namespace Guid.Core.Services
    {
      public class TimedMessageSender : IWorker, IDisposable
      {
        private readonly ISender sender;
        private readonly IRunner runner;
        private int counter = 0;
        public TimedMessageSender(IRunner runner, ISender sender)
        {
          this.sender = sender;
          this.runner = runner;
        }
    
        public void Run()
        {   
          runner.Run(DoSelectedWork);
          Console.ReadLine();
        }
    
        /// <summary>
        /// Initialize specific senders
        /// </summary>
        /// <param name="state"></param>
        private void DoSelectedWork(object state)
        {
    
          Parallel.Invoke(
            () => sender.Send("royland", "Arcanys", counter + " " + System.Guid.NewGuid().ToString()),
            () => sender.Send("allan", "Arcanys", counter + " " + System.Guid.NewGuid().ToString()),
            () => sender.Send("rafael", "Arcanys", counter + " " + System.Guid.NewGuid().ToString()),
            () => sender.Send("fred", "Arcanys", counter + " " + System.Guid.NewGuid().ToString()),
            () => sender.Send("hans", "Arcanys", counter + " " + System.Guid.NewGuid().ToString())
            );
          counter++;
        }
    
        public void Dispose()
        {
          runner?.Dispose();
        }
    
      }
    }


  8. Next, we will create an implementation of IReceiver interface with RabbitMQ. To do this, create a folder within Guid.Core named ‘RabbitMQ’ and add a class named ‘RabbitMQReceiver’. Then add the following lines of code.

    using Guid.Core.Interfaces;
    using RabbitMQ.Client;
    using RabbitMQ.Client.Events;
    using System;
    using System.Text;
    using System.Threading;
    
    namespace Guid.Core.RabbitMQ
    {
      public class RabbitMQReceiver : IReceiver
      {
        private readonly ApplicationSettings applicationSettings;
        public RabbitMQReceiver(ApplicationSettings applicationSettings)
        {
          this.applicationSettings = applicationSettings;
        }
    
        public void Receive(string name)
        {
          var factory = new ConnectionFactory() { HostName = applicationSettings.RabbitMQServer, UserName = applicationSettings.RabbitMQUsername, Password =
    applicationSettings.RabbitMQPassword };
          using (var connection = factory.CreateConnection()) // Creates the RabbitMQ connection
          using (var channel = connection.CreateModel()) // Creates a channel, which is where most of the API for getting things done resides.
          {
            // We will also have to declare the queue here,
            // because this application might start first so we will make sure that the queue exists before receiving messages.
            channel.QueueDeclare(queue: name, // The name of the queue
                        durable: true, // true if we are declaring a durable queue(the queue will survive a server restart)
                        exclusive: false, // true if we are declaring an exclusive queue (restricted to this connection)
                        autoDelete: false, // true if we are declaring an auto delete queue (server will delete it when no longer in use)
                        arguments: null); // other properties (construction arguments) for the queue
    
            // Request a specific Quality of Service
            channel.BasicQos(prefetchSize: 0, prefetchCount: 1, global: false);
    
            var consumer = new EventingBasicConsumer(channel);
            // Callback
            consumer.Received += (model, ea) =>
            {
              var body = ea.Body;
              var message = Encoding.UTF8.GetString(body);
              Console.WriteLine($"Received: {message}");
    
              channel.BasicAck(deliveryTag: ea.DeliveryTag, multiple: false);
            };
    
            // Start receiving messages
            channel.BasicConsume(queue: name, // the name of the queue
                        autoAck: false, // true if the server should consider messages acknowledged once delivered;
                                        // false if the server should expect explicit acknowledgements
                        consumer: consumer); // an interface to the consumer object
            Console.WriteLine("Waiting for message/s.");
            Console.ReadLine();
          }
        }
      }
    }


  9. We will also add an implementation of ISender interface with RabbitMQ. In the RabbitMQ folder, add a class named ‘RabbitMQSender’ then add the lines of code below.

    using Guid.Core.Interfaces;
    using RabbitMQ.Client;
    using System;
    using System.Text;
    using System.Threading;
    
    namespace Guid.Core.RabbitMQ
    {
      public class RabbitMQSender : ISender
      {
        private readonly ApplicationSettings applicationSettings;
        public RabbitMQSender(ApplicationSettings rabbitMQSettings)
        {
          this.applicationSettings = rabbitMQSettings;
        }
        public void Send(string sender, string receiver, string message)
        {
    
          var factory = new ConnectionFactory() { HostName = applicationSettings.RabbitMQServer, UserName = applicationSettings.RabbitMQUsername, Password =
    applicationSettings.RabbitMQPassword };
          using (var connection = factory.CreateConnection()) // Creates the RabbitMQ connection
          using (var channel = connection.CreateModel()) // Creates a channel, which is where most of the API for getting things done resides.
          {
            //Declares the queue
            channel.QueueDeclare(queue: receiver, // The name of the queue
                        durable: true, // true if we are declaring a durable queue(the queue will survive a server restart)
                        exclusive: false, // true if we are declaring an exclusive queue (restricted to this connection)
                        autoDelete: false, // true if we are declaring an auto delete queue (server will delete it when no longer in use)
                        arguments: null); // other properties for the queue
    
            var properties = channel.CreateBasicProperties();
            properties.Persistent = true; // Marking messages as persistent doesn't fully guarantee that a message won't be lost.
                                        // Although it tells RabbitMQ to save the message to disk,
                                        // there is still a short time window when RabbitMQ has accepted a message and hasn't saved it yet.
    
            var body = Encoding.UTF8.GetBytes($"{message} from {sender}"); // Converts message to byte array
            //Publish message
            channel.BasicPublish(exchange: "", // the exchange to publish the message to
                        routingKey: receiver, // the routing key
                        basicProperties: properties, // other properties for the message
                        body: body); // the message body
    
            Console.WriteLine($"Sent: {message} Thread: {Thread.CurrentThread.ManagedThreadId} from {sender}");
          }
        }
      }
    }


  10. Next, add an implementation of our IRunner interface.

    using Guid.Core.Interfaces;
    using System;
    using System.Threading;
    
    namespace Guid.Core.Services
    {
      public class TimerRunner : IRunner
      {
        private Timer timer;
        private const int interval = 5;
        public void Run(TimerCallback callback)
        {
          timer = new Timer(callback, null, TimeSpan.Zero, TimeSpan.FromSeconds(interval));
        }
        public void Dispose()
        {
          timer?.Dispose();
        }
      }
    }



Now that the required Interfaces and Implementations have been created, it’s time to set up the project references and Dependency Injection of the Guid.Receiver and Guid.Sender project. Follow the steps below.

  1. Expand Guid.Sender> right click Dependencies > Add Reference > ‘check’ the Guid.Core project, then click OK.

  2. Next, expand Guid.Receiver > right click Dependencies > Add Reference > ‘check’ the Guid.Core project, then click OK.

  3. Open the Guid.Sender / program.cs and add these lines of code.

    using Guid.Core;
    using Guid.Core.Interfaces;
    using Guid.Core.RabbitMQ;
    using Guid.Core.Services;
    using Microsoft.Extensions.Configuration;
    using Microsoft.Extensions.DependencyInjection;
    using Microsoft.Extensions.Hosting;
    using System.IO;
    
    namespace Guid.Sender
    {
      class Program
      {  
        public static void Main(string[] args)
        {
          CreateHostBuilder(args).Build().Run();
        }
        public static IHostBuilder CreateHostBuilder(string[] args) =>
          Host.CreateDefaultBuilder(args)
            .ConfigureServices((hostContext, services) =>
            {
              string path = Directory.GetParent(Directory.GetCurrentDirectory()).Parent.Parent.FullName; //Gets the path of the appsettings.json
              var builder = new ConfigurationBuilder().SetBasePath(path).AddJsonFile("appsettings.json"); //Adds the appsettings.json file to the Configuration Builder
    
              services.AddTransient<IWorker, TimedMessageSender>(); //Registers our Implementation of IWorker
              services.AddTransient<ISender, RabbitMQSender>(); //Registers our Implementation of ISender
              services.AddTransient<IRunner, TimerRunner>(); //Registers our Implementation of IRunner
    
              //Gets the matching property keys and values from the appsettings.json then binds to the ApplicationSettings class
              var config = builder.Build();
              var applicationSettings = config.GetSection("ApplicationSettings").Get<ApplicationSettings>();
    
              //register our application settings as singleton.
              services.AddSingleton(applicationSettings);
              //gets the service from the registered implementations of IWorker from the service collection and Run.
              services.BuildServiceProvider().GetService<IWorker>().Run();
            });
      }
    }


  4. Open the Guid.Receiver / program.cs and add these lines of code.

    using Guid.Core;
    using Guid.Core.Interfaces;
    using Guid.Core.RabbitMQ;
    using Guid.Core.Services;
    using Microsoft.Extensions.Configuration;
    using Microsoft.Extensions.DependencyInjection;
    using Microsoft.Extensions.Hosting;
    using System.IO;
    
    namespace Guid.Receiver
    {
      class Program
      {
        public static void Main(string[] args)
        {
          CreateHostBuilder(args).Build().Run();
        }
        public static IHostBuilder CreateHostBuilder(string[] args) =>
          Host.CreateDefaultBuilder(args)
            .ConfigureServices((hostContext, services) =>
            {
              string path = Directory.GetParent(Directory.GetCurrentDirectory()).Parent.Parent.FullName; //Gets the path of the appsettings.json
              var builder = new ConfigurationBuilder().SetBasePath(path).AddJsonFile("appsettings.json"); //Adds the appsettings.json file to the Configuration Builder
    
              services.AddTransient<IWorker, MessageReceiver>(); //Registers our Implementation of IWorker
              services.AddTransient<IReceiver, RabbitMQReceiver>(); //Registers our Implementation of IReceiver
    
              //Gets the matching property keys and values from the appsettings.json then binds to the ApplicationSettings class
              var config = builder.Build();
              var applicationSettings = config.GetSection("ApplicationSettings").Get<ApplicationSettings>();
    
              //register our application settings as singleton.
              services.AddSingleton(applicationSettings);
              //gets the service from the registered implementations of IWorker from the service collection and Run.
              services.BuildServiceProvider().GetService<IWorker>().Run();
            });
      }
    }


  5. Now run both Guid.Receiver and Guid.Sender projects.

  6. After 2 or 3 seconds, close or kill the process of our receiver app. This is done so that messages from the senders will not be acknowledged.

  7. Stop and Start RabbitMQ Service.

  8. Once you’ve restarted RabbitMQ service, run the receiver app again and you will see the messages that were not received when the receiver app was closed earlier.

So how was it? Were you able to get all that? Were your demo projects successful? A big kudos to you if they were, and I hope you more success on future RabbitMQ integration projects.

About the author

Rafael (Rafa to close friends) is a .NET architect at Arcanys. He can get quite engrossed in the tech world and especially likes reading about innovations in containerization, .NET technology (of course), microservices architecture, and Python. Surprisingly though, he can be pretty handy in the kitchen and can actually cook you some yummy paella if you’re nice and say, “Por favor!” To occupy his time when he’s not at work, he goes scuba diving, plays music or soccer, or adds snapshots to his collection of wildlife photography.

Be part of our growing community.

Join us and outsource smarter.

Please verify that you are not a robot.