Publishing RabbitMQ Message In ASP.NET Core

Introduction

 
Some days ago, I wrote an article to introduce how to consume RabbitMQ messages via background service in ASP.NET Core.
 
And in this article, you will learn how to publish RabbitMQ messages.
 

Run Up RabbitMQ Service

 
Publishing RabbitMQ Message In ASP.NET Core
 

RabbitMQ Settings

 
Adding configuration of RabbitMQ in appsettings.json
  1. {  
  2.   "Logging": {  
  3.     "LogLevel": {  
  4.       "Default""Warning"  
  5.     }  
  6.   },  
  7.   "AllowedHosts""*",  
  8.   "rabbit": {  
  9.     "UserName""guest",  
  10.     "Password""guest",  
  11.     "HostName""localhost",  
  12.     "VHost""/",  
  13.     "Port": 5672  
  14.   }  
  15. }  
Creating a class that maps the rabbit section in appsettings.json
  1. public class RabbitOptions  
  2. {  
  3.     public string UserName { getset; }  
  4.   
  5.     public string Password { getset; }  
  6.   
  7.     public string HostName { getset; }  
  8.   
  9.     public int Port { getset; } = 5672;  
  10.   
  11.     public string VHost { getset; } = "/";  
  12. }  

Reuse Channels of RabbitMQ Connection

 
Why should we reuse channels?
 
Based on the official .NET/C# Client API Guide document, we can consider reusing channels because these are long-lived but since many recoverable protocol errors will result in channel closure, the closing and opening of new channels per operation are usually unnecessary.
 
Here, we will use the object pool to do this job! Microsoft provides a package named Microsoft.Extensions.ObjectPool can help us simplify some of the work.
 
Before using the object pool, we should declare the policy of the channel at first. Here, we create a class named RabbitModelPooledObjectPolicy that implements IPooledObjectPolicy<IModel>.
  1. using Microsoft.Extensions.ObjectPool;  
  2. using Microsoft.Extensions.Options;  
  3. using RabbitMQ.Client;  
  4.   
  5. public class RabbitModelPooledObjectPolicy : IPooledObjectPolicy<IModel>  
  6. {  
  7.     private readonly RabbitOptions _options;  
  8.   
  9.     private readonly IConnection _connection;  
  10.   
  11.     public RabbitModelPooledObjectPolicy(IOptions<RabbitOptions> optionsAccs)  
  12.     {  
  13.         _options = optionsAccs.Value;  
  14.         _connection = GetConnection();  
  15.     }  
  16.   
  17.     private IConnection GetConnection()  
  18.     {  
  19.         var factory = new ConnectionFactory()  
  20.         {  
  21.             HostName = _options.HostName,  
  22.             UserName = _options.UserName,  
  23.             Password = _options.Password,  
  24.             Port = _options.Port,  
  25.             VirtualHost = _options.VHost,  
  26.         };  
  27.   
  28.         return factory.CreateConnection();  
  29.     }  
  30.   
  31.     public IModel Create()  
  32.     {  
  33.         return _connection.CreateModel();  
  34.     }  
  35.   
  36.     public bool Return(IModel obj)  
  37.     {  
  38.         if (obj.IsOpen)  
  39.         {  
  40.             return true;  
  41.         }  
  42.         else  
  43.         {  
  44.             obj?.Dispose();  
  45.             return false;  
  46.         }  
  47.     }  
  48. }  
There are two important methods in it, one is Create, the other one is Return.
 
The Create method tells the pool how to create the channel object.
 
The Return method tells the pool that if the channel object is still in a state that can be used, we should return it to the pool; otherwise, we should not use it the next time.
 

RabbitMQ Manager

 
We create a management interface to handle the Publish method.
  1. public interface IRabbitManager  
  2. {  
  3.     void Publish<T>(T message, string exchangeName, string exchangeType, string routeKey)   
  4.         where T : class;  
  5. }  
The following code demonstrates an implementing class of it.
  1. public class RabbitManager : IRabbitManager  
  2. {  
  3.     private readonly DefaultObjectPool<IModel> _objectPool;  
  4.   
  5.     public RabbitManager(IPooledObjectPolicy<IModel> objectPolicy)  
  6.     {  
  7.         _objectPool = new DefaultObjectPool<IModel>(objectPolicy, Environment.ProcessorCount * 2);  
  8.     }  
  9.   
  10.     public void Publish<T>(T message, string exchangeName, string exchangeType, string routeKey)   
  11.         where T : class  
  12.     {  
  13.         if (message == null)  
  14.             return;  
  15.   
  16.         var channel = _objectPool.Get();  
  17.   
  18.         try  
  19.         {  
  20.             channel.ExchangeDeclare(exchangeName, exchangeType, truefalsenull);  
  21.   
  22.             var sendBytes = Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(message));  
  23.   
  24.             var properties = channel.CreateBasicProperties();  
  25.             properties.Persistent = true;  
  26.   
  27.             channel.BasicPublish(exchangeName, routeKey, properties, sendBytes);  
  28.         }  
  29.         catch (Exception ex)  
  30.         {  
  31.             throw ex;  
  32.         }  
  33.         finally  
  34.         {  
  35.             _objectPool.Return(channel);                  
  36.         }  
  37.     }  
  38. }  
We create an object pool in the constructor. Before publishing messages to RabbitMQ, we should get a channel from the object pool, then construct the payload.
 
After publishing, we should return this channel object to the object pool whether the publish succeeds or fails.
 

RabbitMQ Extension

 
Create an extension method to simplify the registration.
  1. public static class RabbitServiceCollectionExtensions  
  2. {  
  3.     public static IServiceCollection AddRabbit(this IServiceCollection services, IConfiguration configuration)  
  4.     {  
  5.         var rabbitConfig = configuration.GetSection("rabbit");  
  6.         services.Configure<RabbitOptions>(rabbitConfig);  
  7.   
  8.         services.AddSingleton<ObjectPoolProvider, DefaultObjectPoolProvider>();  
  9.         services.AddSingleton<IPooledObjectPolicy<IModel>, RabbitModelPooledObjectPolicy>();  
  10.   
  11.         services.AddSingleton<IRabbitManager, RabbitManager>();  
  12.   
  13.         return services;  
  14.     }  
  15. }  
Go to Startup class.
  1. public void ConfigureServices(IServiceCollection services)  
  2. {  
  3.     services.AddRabbit(Configuration);  
  4.   
  5.     services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);  
  6. }  

Usage of RabbitMQ Manager

 
We add some code in ValuesController .
  1. [Route("api/[controller]")]  
  2. [ApiController]  
  3. public class ValuesController : ControllerBase  
  4. {  
  5.     private IRabbitManager _manager;  
  6.   
  7.     public ValuesController(IRabbitManager manager)  
  8.     {  
  9.         _manager = manager;  
  10.     }  
  11.   
  12.     // GET api/values  
  13.     [HttpGet]  
  14.     public ActionResult<IEnumerable<string>> Get()  
  15.     {  
  16.         // other opreation  
  17.   
  18.         // if above operation succeed, publish a message to RabbitMQ  
  19.   
  20.         var num = new System.Random().Next(9000);  
  21.   
  22.         // publish message  
  23.         _manager.Publish(new  
  24.         {  
  25.             field1 = $"Hello-{num}",  
  26.             field2 = $"rabbit-{num}"                  
  27.         }, "demo.exchange.topic.dotnetcore""topic""*.queue.durable.dotnetcore.#");  
  28.   
  29.         return new string[] { "value1""value2" };  
  30.     }  
  31. }  
Here we will create a topic type exchange named demo.exchange.topic.dotnetcore, and it also will send the message to the queues that are binding the routing key named *.queue.durable.dotnetcore.#.
 
Note 
A message in a queue will only be consumed by one consumer.
 

Result

 
For demonstration, we create a queue and bind it to the routing key instead of creating consumers.
 
Publishing RabbitMQ Message In ASP.NET Core
 
After publishing a message, we can find out if the message is ready. 
 
Publishing RabbitMQ Message In ASP.NET Core
 
We can use the GetMessage button to check the message.
 
Publishing RabbitMQ Message In ASP.NET Core
 

Summary

 
This article showed you how to publish the RabbitMQ message in ASP.NET Core. I hope this will help you!