RabbitMQ Messaging for .NET 8 Web API with Windows Client Part 1

This article shows you how to use Rabbit MQ with c# application. Here I will explain how to consume the WEB API, how Rabbit MQ is broadcasting, and how the client application uses the broadcast message.

What is Rabbit MQ & its features?

RabbitMQ is an open-source message broker software that facilitates communication and data exchange between various components of distributed applications. RabbitMQ functions as a message queue, managing the routing, queuing, and delivery of messages from senders (producers) to receivers (consumers).

  • Decoupling applications: RabbitMQ can be used to decouple applications, which means that they can communicate with each other without being a monolith.
  • Implementing async communication: RabbitMQ can be used to implement asynchronous communication, which means that messages are sent and received without blocking the sender or receiver.
  • Real-time streaming: RabbitMQ can be used to implement real-time streaming, which means that messages are delivered in real time.
  • Load balancing: RabbitMQ can be used to load balance messages between different consumers.
  • Failover: RabbitMQ can be used to provide failover for applications. This means that if one RabbitMQ node fails, another node can take over and continue to deliver messages.
  • Auditing: RabbitMQ can be used to audit messages. This means that you can track who sent and received messages and when they were sent and received.
  • Monitoring: RabbitMQ can be monitored to track its performance and health.

Benefits of RabbitMQ

  1. Multi-platform communication which means that messages are serialized/deserialized in common languages such as JSON.
  2. Open source for that very large community can develop and improve the issues.
  3. Flexible, Reliable, and Scalable.
  4. Support Multiple protocols (STOMP, MQTT, RPC, HTTPS, HTTP, etc).

RabbitMQ Installation

Download Rabbit MQ for Windows as I am using Windows Operating System.

RabbitMQ Download Link and Installation Process

Default Configuration

  • Endpoint address: http://localhost:15672/
  • Login: guest
  • Password: guest
  • Windows Service Name: RabbitMQ
  • Windows menu item to start the service if not started: RabbitMQ Service - start

Create Dotnet core webapi and broadcast the message (Using the Latest .Net 8).

  • Tools: Visual Studio 2022
  • Check the latest dotnet version
  • Open CMD and type: dotnet --version
  • Check all the versions: dotnet --list-SDKs

Step 1. Add new dotnet webapi project.

Dotnet webapi

Step 2. Select the framework.

Framework

Step 3. Create the project and also please check and confirm that the project is the .net 8 framework.

.Net 8 framework

Then start the coding

Add NewFolder call Model, and add Product Model class with the name of Product.cs.

namespace RabbitMQProductApi.Models
{
    public class Product
    {
        public int ProductID { get; set; }
        public string ProductName { get; set; }=string.Empty;
        public string ProductDescription { get; set; }= string.Empty;
        public int ProductPrice { get; set; }
        public int ProductStock { get; set; }
    }
}

Add NewFolder call RabbitMQ, add Rabbitmq interface name with IRabbitMQProducer.cs.

namespace RabbitMQProductApi.RabbitMQ
{
    public interface IRabbitMQProducer
    {
        public void SendProductMessage<T>(T message);
    }
}

Add a new RabbitMQProducer Class and consume the IRabbitMQProducer interface. Please install the latest RabbitMQ.Client from nuget.org.

using RabbitMQ.Client;

namespace RabbitMQProductApi.RabbitMQ
{
    public class RabbitMQProducer : IRabbitMQProducer
    {
        public void SendProductMessage<T>(T message)
        {
            var factory=new ConnectionFactory() { HostName = "localhost" };
            var connection = factory.CreateConnection();
            var channel = connection.CreateModel();
            channel.QueueDeclare(queue: "ProductQueue", durable: false, exclusive: false, autoDelete: false, arguments: null);
            var json= System.Text.Json.JsonSerializer.Serialize(message);
            var body = System.Text.Encoding.UTF8.GetBytes(json);
            channel.BasicPublish(exchange:"", routingKey: "ProductQueue", basicProperties: null, body: body);
        }
    }
}

Add a New folder called Data ( Which is used for Database purposes), Please be sure that you have installed Entity framework for this project using nuget.org.

using Microsoft.EntityFrameworkCore;
using RabbitMQProductApi.Models;

namespace RabbitMQProductApi.Data
{
    public class DBContextClass:DbContext
    {
        protected readonly IConfiguration Configuration;
        public DBContextClass(IConfiguration configuration)
        {
            Configuration = configuration;
        }
        protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        {
            optionsBuilder.UseSqlServer("Server=Machine Name;Database=ProductDB;Trusted_Connection=True;");
            optionsBuilder.UseSqlServer(Configuration.GetConnectionString("DefaultConnection"));
        }
        
        public DbSet<Product> Products { get; set; }
    }
}

Add NewFolder Services and add Service Interface name with IProductService.cs.

namespace RabbitMQProductApi.Services
{
    public interface IProductServices
    {
        public IEnumerable<Product> GetProducts();
        public Product GetProduct(int id);
        public Product AddProduct(Product product);
        public Product UpdateProduct(Product product);
        public bool DeleteProduct(int id);
        public bool DeleteProduct(Product product);

    }
}

Add ProductService.cs class use IProductServices.

namespace RabbitMQProductApi.Services
{
    public class ProductServices : IProductServices
    {
        private readonly DBContextClass _dbContext;
        public ProductServices(DBContextClass dbContext)
        {
            _dbContext = dbContext;
        }

        public IEnumerable<Product> GetProducts()
        {
            return _dbContext.Products.ToList();
        }

        public Product GetProduct(int id)
        {
            return _dbContext.Products.FirstOrDefault(x => x.ProductID == id);
        }

        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 result=_dbContext.Products.FirstOrDefault(x => x.ProductID == id);
            if (result != null)
            {
                _dbContext.Products.Remove(result);
                _dbContext.SaveChanges();
                return true;
            }
            return false;
        }

        public bool DeleteProduct(Product product)
        {
            var result = _dbContext.Products.FirstOrDefault(x => x.ProductID == product.ProductID);
            if (result != null)
            {
                _dbContext.Products.Remove(result);
                _dbContext.SaveChanges();
                return true;
            }
            else
            {
                return false;
            }
        } 
    }
}

Add-Migration script, execute the below command in the Package Manager console.

- add-migration "ProductMigration"

Then update the DB by passing the below command.

- update-database
 protected override void Up(MigrationBuilder migrationBuilder)
 {
     migrationBuilder.CreateTable(
         name: "Products",
         columns: table => new
         {
             ProductID = table.Column<int>(type: "int", nullable: false)
                 .Annotation("SqlServer:Identity", "1, 1"),
             ProductName = table.Column<string>(type: "nvarchar(max)", nullable: false),
             ProductDescription = table.Column<string>(type: "nvarchar(max)", nullable: false),
             ProductPrice = table.Column<int>(type: "int", nullable: false),
             ProductStock = table.Column<int>(type: "int", nullable: false)
         },
         constraints: table =>
         {
             table.PrimaryKey("PK_Products", x => x.ProductID);
         });
 }

 /// <inheritdoc />
 protected override void Down(MigrationBuilder migrationBuilder)
 {
     migrationBuilder.DropTable(
         name: "Products");
 }

Now add NewFolder, named with controllers, and add ProductController.cs.

namespace RabbitMQProductApi.Controllers
{
    [Route("api/[controller]")]
    [ApiController]
    public class ProductController : ControllerBase
    {
        private readonly IRabbitMQProducer _rabbitMQProducer;
        private readonly ILogger<ProductController> _logger;
        private readonly IProductServices _productService;
        public ProductController(ILogger<ProductController> logger, IProductServices productService, IRabbitMQProducer rabbitMQProducer)
        {
            _logger = logger;
            _productService = productService;
            _rabbitMQProducer = rabbitMQProducer;
        }
        [HttpGet("productlist")]
        public IActionResult GetProducts()
        {
            var products = _productService.GetProducts();
            return Ok(products);
        }
        [HttpGet("product/{id}")]
        public IActionResult GetProduct(int id)
        {
            var product = _productService.GetProduct(id);
            if (product == null)
            {
                return NotFound();
            }
            return Ok(product);
        }
        [HttpPost("addproduct")]
        public IActionResult AddProduct([FromBody] Product product)
        {
            var newProduct = _productService.AddProduct(product);
            _rabbitMQProducer.SendProductMessage(newProduct);
            return Ok(newProduct);
            //return CreatedAtRoute("GetProduct", new { id = newProduct.ProductID }, newProduct);
        }
        [HttpPut("updateproduct")]
        public IActionResult UpdateProduct([FromBody] Product product)
        {
            var updatedProduct = _productService.UpdateProduct(product);
            return Ok(updatedProduct);
        }
        [HttpDelete("deleteproduct/{id}")]
        public IActionResult DeleteProduct(int id)
        {
            var result = _productService.DeleteProduct(id);
            if (result)
            {
                return Ok();
            }
            return NotFound();
        }

        [HttpDelete("deleteproduct")]
        public IActionResult DeleteProduct([FromBody]Product product)
        {
            var result = _productService.DeleteProduct(product);
            if (result)
            {
                return Ok();
            }
            return NotFound();
        }

    }

Update the Program.cs class with code below.

namespace RabbitMQProductApi
{
    public class Program
    {
        public static void Main(string[] args)
        {
            var builder = WebApplication.CreateBuilder(args);

            // Add services to the container.
            builder.Services.AddScoped<IProductServices, ProductServices>();
            builder.Services.AddDbContext<DBContextClass>();
            builder.Services.AddScoped<IRabbitMQProducer, RabbitMQProducer>();
            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();
        }
    }
}

Now build the project and run it on a local machine.

Local machine

Add item into product DB.

Product DB

Please check the DB.

DB

Done

Will see in the next Part, How to consume the message in the client application.