In this article, we are going to discuss the usage of RabbitMQ Message Queue, Asynchronous communication between microservices, and containerization of microservices using docker
Before starting this article, I will suggest you read my following articles related to microservice
- RabbitMQ Message Queue Using .NET Core 6 Web API
- Microservices Implementation With Ocelot Gateway Using .NET Core 6 API And Angular 14
- Implementation And Containerization Of Microservices Using .NET Core 6 And Docker
Agenda
- Introduction of RabbitMQ
- Benefits of RabbitMQ
- Implementation of Producer and Consumer Application
- RabbitMQ Message Queue Setup using Docker
- Containerization of Producer and Consumer using Docker
Prerequisites
- Visual Studio 2022
- Docker Desktop
- .NET Core 6 SDK
- SQL Server
Introduction of RabbitMQ
- Rabbit MQ is the message broker that acts as a middleware while using multiple microservices.
- RabbitMQ is an open-source message broker software. It is sometimes also called message-oriented middleware.
- RabbitMQ is written in the Erlang programming language.
- RabbitMQ is used to reduce a web application's load and delivery time when some of the resources have taken a lot of time to process the data.

- As you can see in the diagram above, there is one producer who sends a message to the RabbitMQ server. The server will store that message inside the queue in a FIFO manner.
- Once the producer has sent the message to the queue, there may be multiple consumers that want the message produced by the producer. In that case, consumers subscribe to the message and get that message from the Message Queue as you see in the above diagram.
- In this section, we will use one eCommerce Site as an example to understand more fully.
- There are multiple microservices running in the background while we are using the eCommerce website. There is one service that takes care of order details, and another service that takes care of payment details and receipts.
- Suppose we placed one order. At that time, the order service will start and process our order. After taking the order details, it will send data to the payment service, which takes the payment and sends the payment receipt to the end-users.
- In this case, there may be a chance of some technical issue occurring in the payment service. If the user did not receive the payment receipt due to this, the user will be impacted and connected with the support team to get the status of the order.
- There may be another scenario on the user(consumer) side. Perhaps due to some technical issue, the user is exit from the application when the payment is in process. but he will not get any receipt details after payment is successfully processed from backend services.
- In these scenarios, the RabbitMQ plays an essential role to process messages in the message queue. So, when the consumer gets online, he will receive that order receipt message from the message queue, produced by the producer without impacting the web application.
- All these examples are just for understanding purposes. There are a lot of scenarios in which RabbitMQ may play an important role while using multiple microservices. Sometimes RabbitMQ is used fully to load balancing between multiple services, or for many other purposes.
Benefits of RabbitMQ
There are many benefits to using a Message Broker to send data to the consumer. Below, we will discuss a few of these benefits.
High Availability
When multiple microservices are used by the application, if one of the microservices is stopped due to technical reasons at that time, the message will never be lost. Instead, it persists in the RabbitMQ server. After some time, when our service starts working, it will connect with RabbitMQ and take the pending message easily.
Scalability
When we use RabbitMQ, at that time our application does not depend on only one server and virtual machine to process a request. If our server is stopped at that time, RabbitMQ will transfer our application load to another server that has the same services running in the background.
Implementation of Producer and Consumer Application
Let’s start the practical implementation of the Application. Here we will take the example of a product owner, who sends a product to offer to product users using a message queue and users will receive that message using a background service that continuously accesses the message queue to receive the product offer message which is sent by the owner and save into the database
Step 1
Create Blank Solution

Step 2
Configure Solution

Step 3
Create Product Owner Microservice which adds and sends product offers to end user

Step 4
Configure Microservice

Step 5
Provide additional information

Step 6
Create Product User Microservice as a consumer. Follow the same steps to create a web API application as Product Owner Service
Step 7
Project Structure

Step 8
Let’s start Implementation of Product Owner Service

Also, Install the following NuGet Packages

Step 9
Create Product Details and Product Offer Detail Class inside the Model folder
Product Details
namespace ProductOwner.Microservice.Model
{
public class ProductDetails
{
public int Id { get; set; }
public string ProductName { get; set; }
public int ProductPrice { get; set; }
}
}
Product Offer Detail
namespace ProductOwner.Microservice.Model
{
public class ProductOfferDetail
{
public int Id { get; set; }
public int ProductID { get; set; }
public string ProductName { get; set; }
public string ProductOfferDetails { get; set; }
}
}
Step 10
Next, create DbContextClass inside the Data folder
using Microsoft.EntityFrameworkCore;
using ProductOwner.Microservice.Model;
namespace ProductOwner.Microservice.Data
{
public class DbContextClass : DbContext
{
protected readonly IConfiguration Configuration;
public DbContextClass(IConfiguration configuration)
{
Configuration = configuration;
}
protected override void OnConfiguring(DbContextOptionsBuilder options)
{
options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection"));
}
public DbSet<ProductDetails> Products { get; set; }
}
}
Step 11
Later on, create Static Configuration Manager to configure the appsettings.json file to retrieve environmental variables
namespace ProductOwner.Microservice.Utility
{
static class StaticConfigurationManager
{
public static IConfiguration AppSetting
{
get;
}
static StaticConfigurationManager()
{
AppSetting = new ConfigurationBuilder().SetBasePath(Directory.GetCurrentDirectory()).AddJsonFile("appsettings.json").Build();
}
}
}
Step 12
Create IProductService and ProductService class for data manipulation
IProductService
using ProductOwner.Microservice.Model;
namespace ProductOwner.Microservice.Services
{
public interface IProductService
{
public Task<IEnumerable<ProductDetails>> GetProductListAsync();
public Task<ProductDetails> GetProductByIdAsync(int id);
public Task<ProductDetails> AddProductAsync(ProductDetails product);
public bool SendProductOffer(ProductOfferDetail productOfferDetails);
}
}
ProductService
using Microsoft.EntityFrameworkCore;
using Newtonsoft.Json;
using ProductOwner.Microservice.Data;
using ProductOwner.Microservice.Model;
using ProductOwner.Microservice.Utility;
using RabbitMQ.Client;
using System.Text;
namespace ProductOwner.Microservice.Services
{
public class ProductService : IProductService
{
private readonly DbContextClass _dbContext;
public ProductService(DbContextClass dbContext)
{
_dbContext = dbContext;
}
public async Task<IEnumerable<ProductDetails>> GetProductListAsync()
{
return await _dbContext.Products.ToListAsync();
}
public async Task<ProductDetails> GetProductByIdAsync(int id)
{
return await _dbContext.Products.Where(x => x.Id == id).FirstOrDefaultAsync();
}
public async Task<ProductDetails> AddProductAsync(ProductDetails product)
{
var result = _dbContext.Products.Add(product);
await _dbContext.SaveChangesAsync();
return result.Entity;
}
public bool SendProductOffer(ProductOfferDetail productOfferDetails)
{
var RabbitMQServer = "";
var RabbitMQUserName = "";
var RabbutMQPassword = "";
if (Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT") == "Production")
{
RabbitMQServer = Environment.GetEnvironmentVariable("RABBIT_MQ_SERVER");
RabbitMQUserName = Environment.GetEnvironmentVariable("RABBIT_MQ_USERNAME");
RabbutMQPassword = Environment.GetEnvironmentVariable("RABBIT_MQ_PASSWORD");
}
else
{
RabbitMQServer = StaticConfigurationManager.AppSetting["RabbitMQ:RabbitURL"];
RabbitMQUserName = StaticConfigurationManager.AppSetting["RabbitMQ:Username"];
RabbutMQPassword = StaticConfigurationManager.AppSetting["RabbitMQ:Password"];
}
try
{
var factory = new ConnectionFactory()
{ HostName = RabbitMQServer, UserName = RabbitMQUserName, Password = RabbutMQPassword };
using (var connection = factory.CreateConnection())
using (var channel = connection.CreateModel())
{
//Direct Exchange Details like name and type of exchange
channel.ExchangeDeclare(StaticConfigurationManager.AppSetting["RabbitMqSettings:ExchangeName"], StaticConfigurationManager.AppSetting["RabbitMqSettings:ExchhangeType"]);
//Declare Queue with Name and a few property related to Queue like durabality of msg, auto delete and many more
channel.QueueDeclare(queue: StaticConfigurationManager.AppSetting["RabbitMqSettings:QueueName"],
durable: true,
exclusive: false,
autoDelete: false,
arguments: null);
//Bind Queue with Exhange and routing details
channel.QueueBind(queue: StaticConfigurationManager.AppSetting["RabbitMqSettings:QueueName"], exchange: StaticConfigurationManager.AppSetting["RabbitMqSettings:ExchangeName"], routingKey: StaticConfigurationManager.AppSetting["RabbitMqSettings:RouteKey"]);
//Seriliaze object using Newtonsoft library
string productDetail = JsonConvert.SerializeObject(productOfferDetails);
var body = Encoding.UTF8.GetBytes(productDetail);
var properties = channel.CreateBasicProperties();
properties.Persistent = true;
//publish msg
channel.BasicPublish(exchange: StaticConfigurationManager.AppSetting["RabbitMqSettings:ExchangeName"],
routingKey: StaticConfigurationManager.AppSetting["RabbitMqSettings:RouteKey"],
basicProperties: properties,
body: body);
return true;
}
}
catch (Exception)
{
}
return false;
}
}
}
Step 13
Add the connection string and some RabbitMQ server settings related to configuration
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"AllowedHosts": "*",
"ConnectionStrings": {
"DefaultConnection": "Data Source=DESKTOP;Initial Catalog=ProductOwnerServiceDB;User Id=sa;Password=database;"
},
"RabbitMQ": {
"RabbitURL": "localhost",
"Username": "guest",
"Password": "guest"
},
"RabbitMqSettings": {
"ExchangeName": "OfferExchange",
"ExchhangeType": "direct",
"QueueName": "offer_queue",
"RouteKey": "offer_route"
}
}
Step 14
Register a few services inside Program.cs class
using ProductOwner.Microservice.Data;
using ProductOwner.Microservice.Services;
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddScoped<IProductService, ProductService>();
builder.Services.AddDbContext<DbContextClass>();
builder.Services.AddControllers();
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
var app = builder.Build();
// Configure the HTTP request pipeline.
app.UseSwagger();
app.UseSwaggerUI();
app.UseHttpsRedirection();
app.UseAuthorization();
app.MapControllers();
app.Run();
Step 15
Next, Create a Product Controller
using Microsoft.AspNetCore.Mvc;
using ProductOwner.Microservice.Model;
using ProductOwner.Microservice.Services;
namespace ProductOwner.Microservice.Controllers
{
[Route("api/[controller]")]
[ApiController]
public class ProductsController : ControllerBase
{
private readonly IProductService productService;
public ProductsController(IProductService _productService)
{
productService = _productService;
}
[HttpGet("list")]
public Task<IEnumerable<ProductDetails>> ProductListAsync()
{
var productList = productService.GetProductListAsync();
return productList;
}
[HttpGet("filterlist")]
public Task<ProductDetails> GetProductByIdAsync(int Id)
{
return productService.GetProductByIdAsync(Id);
}
[HttpPost("addproduct")]
public Task<ProductDetails> AddProductAsync(ProductDetails product)
{
var productData = productService.AddProductAsync(product);
return productData;
}
[HttpPost("sendoffer")]
public bool SendProductOfferAsync(ProductOfferDetail productOfferDetails)
{
bool isSent = false;
if (productOfferDetails != null)
{
isSent = productService.SendProductOffer(productOfferDetails);
return isSent;
}
return isSent;
}
}
}











Hamid KhanPosted Aug 22, 2022, 12:40 PM
Awesome Article...............