在 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 消息。希望对您有所帮助!

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

相关推荐
Anastasiozzzz9 小时前
RabbitMQ介绍与基础架构
分布式·rabbitmq
洛阳纸贵9 小时前
JAVA高级工程师--RabbitMQ消息可靠性、若依集成升级
java·rabbitmq·java-rabbitmq
jiayong239 小时前
MQ性能优化面试题
java·性能优化·kafka·rabbitmq
小北方城市网1 天前
Spring Cloud Gateway 全链路监控与故障自愈实战
spring boot·python·rabbitmq·java-rabbitmq·数据库架构
weixin_421994782 天前
更复杂的结构 - 类与对象
.net·.netcore
小北方城市网2 天前
Spring Cloud Gateway 进阶实战:自定义过滤器、动态路由与全链路日志监控
spring boot·python·rabbitmq·java-rabbitmq·数据库架构
Roye_ack2 天前
【微服务 Day6】SpringCloud实战开发(RabbitMQ高级篇 + 死信交换机、延迟消息)
spring cloud·微服务·rabbitmq·mq
不想写bug呀2 天前
RabbitMQ相关问题总结
rabbitmq·工作模式
Knight_AL2 天前
RabbitMQ 中 Ready 和 Unacked 到底是什么意思?如何用它们判断系统是否健康
分布式·rabbitmq
小北方城市网3 天前
Spring Cloud 服务治理实战:构建高可用微服务体系
spring boot·python·rabbitmq·java-rabbitmq·数据库架构