Search  
Always will be ready notify the world about expectations as easy as possible: job change page
Aug 26, 2022

RabbitMQ Message Queue using .NET Core 6 Web API

Author:
Jaydeep Patil
Source:
Views:
8205

We are going to discuss the RabbitMQ Message Queue and its implementation using .NET Core 6 API as Message Producer and Console Application as a Message Consumer.

Agenda

  • Introduction of RabbitMQ
  • Benefits of using RabbitMQ
  • Implementation of RabbitMQ in .NET Core 6

Prerequisites

  • Visual Studio 2022
  • Docker Desktop
  • .NET Core 6 SDK

Introduction of RabbitMQ

  • Rabbit MQ is the message broker which acts as a middleware while using multiple microservices.
  • RabbitMQ is open-source message broker software and sometimes also called message-oriented middleware.
  • RabbitMQ is written in the Erlang programming language.
  • It is used to reduce the load and delivery time of our web application when some of the resources have taken a lot of time to process the data.


RabbitMQ Working

  • As you can see in the above diagram there is one producer which sends a message to the RabbitMQ server and the server will store that message inside the queue in a FIFO manner.
  • Once the producer sent the message to the queue that there may be multiple consumers which 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 take one eCommerce Site example to understand the things get easier.
  • There are multiple microservices that are running in the background while we using the eCommerce website there is one service that takes care of order details and another service takes care of payment details and receipt.
  • Suppose we placed one order at that time order service will start and process our order and after taking the order details it will send data to the payment service which takes the money and send the payment receipt to the end-users.
  • In that case, there might be a chance of some technical issue happening in the payment service and the user did not get the payment receipt due to this, the user is impacted and connected with the support team and trying to get the status of the order.
  • Also, there might be another scenario on the user(consumer) side, like due to some technical issue user is exit from the application when the payment is in process. but he did not get any receipt details after payment is successfully done from backend services.
  • So, in these scenarios, the RabbitMQ plays a very important role to persist messages in the message queue and when the consumer gets online he receives that order receipt message from the message queue which is produced by the producer without impacting the web application.
  • All these examples are just for understanding purpose, there may be a lot of scenarios in which RabbitMQ play a very big role while we using multiple microservices sometimes RabbitMQ is used fully to load balancing between multiple services and many other purposes.

Benefits of using RabbitMQ

There are a lot of benefits while using Message Broker to send data to the consumer from which we will discuss a few.

1. Hight Availability

  • When multiple microservices are used by the application and meanwhile one of the microservice is stopped due to technical reasons at that time our message is never lost and persisted in the RabbitMQ server and after some time when our service starts working so it will connect with RabbitMQ and take the pending message easily.

2. Scalability

  • When we use RabbitMQ at that time our application does not depend on only one server and virtual machine to process the request when our server is getting stopped at that time we transfer our application load to another server that has the same services running in the background.

RabbitMQ Implementation with .NET Core 6

Let’s start with the practical implementation of RabbitMQ using .NET Core 6 Web API as producer and Console Application as a consumer.

Step 1)

Create a .NET Core API project.

Step 2)

Configure your project.

Step 3)

Provide additional information about your project.

Step 4)

Project Structure of Producer Application.

Step 5)

Install a few NuGet Package.

Step 6)

Create Product Class inside Models folder.

namespace RabitMqProductAPI.Models
{
    public class Product
    {
        public int ProductId { get; set; }
        public string ProductName { get; set; }
        public string ProductDescription { get; set; }
        public int ProductPrice { get; set; }
        public int ProductStock { get; set; }
    }
}

Step 7)

Next, create DbContextClass.cs class inside Data folder.

using Microsoft.EntityFrameworkCore;
using RabitMqProductAPI.Models;

namespace RabitMqProductAPI.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<Product> Products { get; set; }
    }
}

Step 8)

Later on, create IProductService.cs and ProductService.cs class inside the Services folder.

using RabitMqProductAPI.Models;

namespace RabitMqProductAPI.Services
{
    public interface IProductService
    {
        public IEnumerable<Product> GetProductList();
        public Product GetProductById(int id);
        public Product AddProduct(Product product);
        public Product UpdateProduct(Product product);
        public bool DeleteProduct(int Id);
    }
}

Create a ProductService.cs.

using RabitMqProductAPI.Data;
using RabitMqProductAPI.Models;

namespace RabitMqProductAPI.Services
{
    public class ProductService : IProductService
    {
        private readonly DbContextClass _dbContext;

        public ProductService(DbContextClass dbContext)
        {
            _dbContext = dbContext;
        }
        
        public IEnumerable<Product> GetProductList()
        {
            return _dbContext.Products.ToList();
        }
        
        public Product GetProductById(int id)
        {
            return _dbContext.Products.Where(x => x.ProductId == id).FirstOrDefault();
        }
        
        public Product AddProduct(Product product)
        {
            var result = _dbContext.Products.Add(product);
            _dbContext.SaveChanges();

            return result.Entity;
        }
        
        public Product UpdateProduct(Product product)
        {
            var result = _dbContext.Products.Update(product);
            _dbContext.SaveChanges();

            return result.Entity;
        }
        
        public bool DeleteProduct(int Id)
        {
            var filteredData = _dbContext.Products.Where(x => x.ProductId == Id).FirstOrDefault();
            var result = _dbContext.Remove(filteredData);
            _dbContext.SaveChanges();

            return result != null ? true : false;
        }
    }
}

Step 9)

Create IRabitMQProducer.cs and RabitMQProducer.cs classes for the message queue inside the RabbitMQ folder.

namespace RabitMqProductAPI.RabitMQ
{
    public interface IRabitMQProducer
    {
        public void SendProductMessage<T>(T message);
    }
}

Next, Create RabitMQProducer.cs class.

using Newtonsoft.Json;
using RabbitMQ.Client;
using System.Text;

namespace RabitMqProductAPI.RabitMQ
{
    public class RabitMQProducer : IRabitMQProducer
    {
        public void SendProductMessage<T>(T message)
        {
            // Here we specify the Rabbit MQ Server. We use rabbitmq docker image and use it
            var factory = new ConnectionFactory
            {
                HostName = “localhost”
            };
            
            // Create the RabbitMQ connection using connection factory details as i mentioned above
            var connection = factory.CreateConnection();
            
            // Here we create channel with session and model
            using var channel = connection.CreateModel();
            
            // Declare the queue after mentioning name and a few property related to that
            channel.QueueDeclare(“product”, exclusive: false);
            
            // Serialize the message
            var json = JsonConvert.SerializeObject(message);
            var body = Encoding.UTF8.GetBytes(json);
            
            // Put the data on to the product queue
            channel.BasicPublish(exchange: “”, routingKey: “product”, body: body);
        }
    }
}

Step 10)

After that create a new ProductController.cs.

using Microsoft.AspNetCore.Mvc;
using RabitMqProductAPI.Models;
using RabitMqProductAPI.RabitMQ;
using RabitMqProductAPI.Services;

namespace RabitMqProductAPI.Controllers
{
    [Route("api/[controller]")]
    [ApiController]
    public class ProductController : ControllerBase
    {
        private readonly IProductService productService;
        private readonly IRabitMQProducer _rabitMQProducer;
        
        public ProductController(IProductService _productService, IRabitMQProducer rabitMQProducer)
        {
            productService = _productService;
            _rabitMQProducer = rabitMQProducer;
        }
        
        [HttpGet("productlist")]
        public IEnumerable<Product> ProductList()
        {
            var productList = productService.GetProductList();

            return productList;
        }

        [HttpGet("getproductbyid")]
        public Product GetProductById(int Id)
        {
            return productService.GetProductById(Id);
        }
        
        [HttpPost("addproduct")]
        public Product AddProduct(Product product)
        {
            var productData = productService.AddProduct(product);
            
            // send the inserted product data to the queue and consumer will listening this data from queue
            _rabitMQProducer.SendProductMessage(productData);
            
            return productData;
        }
        
        [HttpPut("updateproduct")]        
        public Product UpdateProduct(Product product)
        {
            return productService.UpdateProduct(product);
        }
        
        [HttpDelete("deleteproduct")]
        public bool DeleteProduct(int Id)
        {
            return productService.DeleteProduct(Id);
        }
    }
}

Here as you see we inject the IRabitMQProducer service inside the constructor and use in the addproduct API endpoint to send data into the message queue which inserts product details inside the RabbitMQ queue and later on the consumer will get that data, the continuously listening queue.

Step 11)

Add connection string inside appsetting.json file.

{
    "Logging": {
        "LogLevel": {
            "Default": "Information",
            "Microsoft.AspNetCore": "Warning"
        }
    },
    "AllowedHosts": "*",
    "ConnectionStrings": {
        "DefaultConnection": "Data Source=DESKTOP-***;Initial Catalog=RabitMQDemo;User Id=**;Password=***@1;"
    }
}

Step 12)

Next, register a few services inside the Program.cs class.

using RabitMqProductAPI.Data;
using RabitMqProductAPI.RabitMQ;
using RabitMqProductAPI.Services;

var builder = WebApplication.CreateBuilder(args);

// Add services to the container.
builder.Services.AddScoped<IProductService, ProductService>();
builder.Services.AddDbContext<DbContextClass>();
builder.Services.AddScoped<IRabitMQProducer, RabitMQProducer>();

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.
if (app.Environment.IsDevelopment())
{
    app.UseSwagger();
    app.UseSwaggerUI();
}

app.UseHttpsRedirection();

app.UseAuthorization();

app.MapControllers();

app.Run();

Step 13)

Add migration and update using the following entity framework command after executing that into the package manager console under the main project

add-migration "first"

update-database 

Step 14)

Install Rabbitmq docker file using the following command (Note- docker desktop is in running mode.

docker pull rabbitmq:3-management

Next, create a container and start using Rabbitmq Dockerfile which we downloaded.

docker run — rm -it -p 15672:15672 -p 5672:5672 rabbitmq:3-management

Step 15)

Finally, run your application and you will see swagger UI and API endpoints.

This is all about Product Web API as producer. Let’s create a new console application as the consumer consumes the message which is sent by the producer.

Step 1)

Add a new console application inside the same solution.

Step 2)

Configure your new project.

Step 3)

Provide some additional information.

Step 4)

Install a few NuGet packages.

Step 5)

Add the following code inside the Program.cs class.

using RabbitMQ.Client;
using RabbitMQ.Client.Events;
using System.Text;

// Here we specify the Rabbit MQ Server. We use rabbitmq docker image and use it
var factory = new ConnectionFactory
{
    HostName = "localhost"
};

// Create the RabbitMQ connection using connection factory details as i mentioned above
var connection = factory.CreateConnection();

// Here we create channel with session and model
using var channel = connection.CreateModel();

// Declare the queue after mentioning name and a few property related to that
channel.QueueDeclare("product", exclusive: false);

// Set Event object which listen message from chanel which is sent by producer
var consumer = new EventingBasicConsumer(channel);
consumer.Received += (model, eventArgs) =>
{
    var body = eventArgs.Body.ToArray();
    var message = Encoding.UTF8.GetString(body);
    Console.WriteLine($"Product message received: {message}");
};

// Read the message
channel.BasicConsume(queue: "product", autoAck: true, consumer: consumer);
Console.ReadKey();

Step 6)

Final Project Structure.

Step 7)

Go to the solution property and configure both the producer and the consumer project as a starting project as shown below.

Step 8)

Open the following URL to open the RabbitMQ dashboard on the port we set while running docker.

http://localhost:15672/

When you hit the URL after that login page is open.

Enter default user name ‘guest’ and password also ‘guest’ and next you will see the dashboard.

Open the queue tab in which you will see our product queue.

Step 9)

Enter the one product details and execute the API.

Step 10)

When you execute the above API using swagger then the message is sent in the queue and you can see immediately inside the console window of the consumer the product details that he listened to from the queue.

This is all about RabbitMQ, you can use this as per your requirement and purpose.

Conclusion

We discussed all the things related to RabbitMQ right from the introduction, working and then set up a docker image and a few functionalities related to the producer and the consumer using the product application.

Happy Learning!

Similar
Jul 18
Author: Ankit Sahu
Introduction Creating a CRUD (Create, Read, Update, Delete) API in .NET 8 with an In-memory collection is a common scenario in web development. In this article, we’ll walk through building a complete .NET 8 Web API with a real-world use...
Jan 21, 2021
The primary purpose of any caching mechanism is to improve performance of an application. As an ASP.NET developer you are probably aware that ASP.NET web forms as well as ASP.NET MVC could used Cache object to cache application data. This...
Apr 26
Author: HarrySrangal
You can’t miss these 50 questions if you are preparing for interviews. Last month I was preparing for the interviews and I have collated all the questions from different companies. Although there were many questions but I have picked top...
May 2, 2023
Microservice architecture is one of the most discussed software architecture trends at the moment, and it has forever changed the way enterprise applications are built. Rather than the slow, complex monolithic approach of the past, developers and companies everywhere are...
Send message
Type
Email
Your name
*Message