在 ASP.NET Core 中发布 RabbitMQ 消息

介绍

前几天写了一篇文章,介绍如何在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 消息。希望对您有所帮助!

如果您喜欢此文章,请收藏、点赞、评论,谢谢,祝您快乐每一天。

相关推荐
心念枕惊11 小时前
.NET CORE 授权进阶-角色、策略与动态权限实现
java·前端·.netcore
余—笙12 小时前
Docker安装rabbitmq并安装延迟队列插件
docker·容器·rabbitmq
完美火龙篇 四月的友2 天前
通俗易懂,什么是.NET?什么是.NET Framework?什么是.NET Core?
.net·.netcore
稚南城才子,乌衣巷风流4 天前
RabbitMQ 消息队列:从入门到实战
分布式·rabbitmq
过期动态5 天前
【LeetCode 热题 100】找到字符串中所有字母异位词
java·数据结构·算法·leetcode·职场和发展·rabbitmq
YDS8297 天前
大营销平台 —— 活动SKU库存扣减业务及其一致性处理
java·spring boot·redis·rabbitmq·ddd
霸道流氓气质7 天前
Kiro 中配置 RabbitMQ MCP Server 指南
分布式·rabbitmq·ruby
quweiie7 天前
tp8使用rabbitMQ消息队列的示例
消息队列·rabbitmq·thinkphp消息队列
六点_dn7 天前
RabbitMQ学习笔记-定义与作用
笔记·学习·rabbitmq
Steadfast_GG10 天前
RabbitMQ升级打怪之路(1) - RabbitMQ概述
消息队列·rabbitmq·流量削峰·消息分发·异步解耦