介绍
前几天写了一篇文章,介绍如何在ASP.NET Core中通过后台服务消费RabbitMQ消息。在本文中,您将学习如何发布 RabbitMQ 消息。
运行 RabbitMQ 服务

如果您喜欢此文章,请收藏、点赞、评论,谢谢,祝您快乐每一天。
RabbitMQ 设置
在appsettings.json 中添加 RabbitMQ 的配置
{
"Logging": {
"LogLevel": {
"Default": "Warning"
}
},
"AllowedHosts": "*",
"rabbit": {
"UserName": "guest",
"Password": "guest",
"HostName": "localhost",
"VHost": "/",
"Port": 5672
}
}
创建一个映射appsettings.json 中的rabbit部分的类
public class RabbitOptions
{
public string UserName { get; set; }
public string Password { get; set; }
public string HostName { get; set; }
public int Port { get; set; } = 5672;
public string VHost { get; set; } = "/";
}
重用 RabbitMQ 连接的通道
为什么要重用渠道?
根据官方的.NET/C# 客户端 API 指南文档,我们可以考虑重用通道,因为这些通道是长期存在的,但由于许多可恢复的协议错误将导致通道关闭,因此每次操作关闭和打开新通道通常是不必要的。
这里,我们将使用对象池来完成这个工作!微软提供了一个名为Microsoft.Extensions.ObjectPool的包 可以帮助我们简化一些工作。
在使用对象池之前,我们首先需要声明通道的策略。这里我们创建一个名为RabbitModelPooledObjectPolicy的类 ,并实现 IPooledObjectPolicy<IModel>接口。
using Microsoft.Extensions.ObjectPool;
using Microsoft.Extensions.Options;
using RabbitMQ.Client;
public class RabbitModelPooledObjectPolicy : IPooledObjectPolicy<IModel>
{
private readonly RabbitOptions _options;
private readonly IConnection _connection;
public RabbitModelPooledObjectPolicy(IOptions<RabbitOptions> optionsAccs)
{
_options = optionsAccs.Value;
_connection = GetConnection();
}
private IConnection GetConnection()
{
var factory = new ConnectionFactory()
{
HostName = _options.HostName,
UserName = _options.UserName,
Password = _options.Password,
Port = _options.Port,
VirtualHost = _options.VHost,
};
return factory.CreateConnection();
}
public IModel Create()
{
return _connection.CreateModel();
}
public bool Return(IModel obj)
{
if (obj.IsOpen)
{
return true;
}
else
{
obj?.Dispose();
return false;
}
}
}
其中有两个重要的方法,一个是Create,另一个是Return。
Create 方法告诉池如何创建通道对象。
Return方法告诉池,如果通道对象仍然处于可以使用的状态,我们应该将其返回到池中;否则,我们下次不应该使用它。
RabbitMQ 管理器
我们创建一个管理接口来处理发布方法。
public interface IRabbitManager
{
void Publish<T>(T message, string exchangeName, string exchangeType, string routeKey)
where T : class;
}
下面的代码演示了它的一个实现类。
public class RabbitManager : IRabbitManager
{
private readonly DefaultObjectPool<IModel> _objectPool;
public RabbitManager(IPooledObjectPolicy<IModel> objectPolicy)
{
_objectPool = new DefaultObjectPool<IModel>(objectPolicy, Environment.ProcessorCount * 2);
}
public void Publish<T>(T message, string exchangeName, string exchangeType, string routeKey)
where T : class
{
if (message == null)
return;
var channel = _objectPool.Get();
try
{
channel.ExchangeDeclare(exchangeName, exchangeType, true, false, null);
var sendBytes = Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(message));
var properties = channel.CreateBasicProperties();
properties.Persistent = true;
channel.BasicPublish(exchangeName, routeKey, properties, sendBytes);
}
catch (Exception ex)
{
throw ex;
}
finally
{
_objectPool.Return(channel);
}
}
}
我们在构造函数中创建了一个对象池。在向 RabbitMQ 发布消息之前,我们需要从对象池中获取一个通道,然后构造有效负载。
发布后,无论发布成功还是失败,我们都应该将此通道对象返回到对象池中。
RabbitMQ 扩展
创建扩展方法来简化注册。
public static class RabbitServiceCollectionExtensions
{
public static IServiceCollection AddRabbit(this IServiceCollection services, IConfiguration configuration)
{
var rabbitConfig = configuration.GetSection("rabbit");
services.Configure<RabbitOptions>(rabbitConfig);
services.AddSingleton<ObjectPoolProvider, DefaultObjectPoolProvider>();
services.AddSingleton<IPooledObjectPolicy<IModel>, RabbitModelPooledObjectPolicy>();
services.AddSingleton<IRabbitManager, RabbitManager>();
return services;
}
}
转到启动类 Startup.cs。
public void ConfigureServices(IServiceCollection services)
{
services.AddRabbit(Configuration);
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
}
RabbitMQ Manager 的使用
我们在ValuesController中添加一些代码 。
Route("api/\[controller\]")
ApiController
public class ValuesController : ControllerBase
{
private IRabbitManager _manager;
public ValuesController(IRabbitManager manager)
{
_manager = manager;
}
// GET api/values
HttpGet
public ActionResult<IEnumerable<string>> Get()
{
// other opreation
// if above operation succeed, publish a message to RabbitMQ
var num = new System.Random().Next(9000);
// publish message
_manager.Publish(new
{
field1 = $"Hello-{num}",
field2 = $"rabbit-{num}"
}, "demo.exchange.topic.dotnetcore", "topic", "*.queue.durable.dotnetcore.#");
return new string[] { "value1", "value2" };
}
}
这里我们将创建一个名为demo.exchange.topic.dotnetcore的主题类型交换,它还将消息发送到绑定名为*.queue.durable.dotnetcore.#的路由键的队列。
笔记
队列中的一条消息只会被一个消费者消费。
结果
为了演示,我们创建一个队列并将其绑定到路由键,而不是创建消费者。

发布消息后,我们可以查看消息是否准备好。

我们可以使用GetMessage按钮来检查消息。

概括
本文介绍了如何在 ASP.NET Core 中发布 RabbitMQ 消息。希望对您有所帮助!
如果您喜欢此文章,请收藏、点赞、评论,谢谢,祝您快乐每一天。