DotNet Core中使用RabbitMQ
上一篇随笔记录到RabbitMQ的安装,安装完成,我们就开始使用吧。
RabbitMQ简介
AMQP,即Advanced Message Queuing Protocol,高级消息队列协议,是应用层协议的一个开放标准,为面向消息的中间件设计。消息中间件主要用于组件之间的解耦,消息的发送者无需知道消息使用者的存在,反之亦然。
AMQP的主要特征是面向消息、队列、路由(包括点对点和发布/订阅)、可靠性、安全。
RabbitMQ是一个开源的AMQP实现,服务器端用Erlang语言编写,支持多种客户端,如:Python、Ruby、.NET、Java、JMS、C、PHP、ActionScript、XMPP、STOMP等,支持AJAX。用于在分布式系统中存储转发消息,在易用性、扩展性、高可用性等方面表现不俗。
RabbitMQ提供了可靠的消息机制、跟踪机制和灵活的消息路由,支持消息集群和分布式部署。适用于排队算法、秒杀活动、消息分发、异步处理、数据同步、处理耗时任务、CQRS等应用场景。
DotNet Core使用RabbitMQ
通过nuget安装:https://www.nuget.org/packages/RabbitMQ.Client/
定义生产者:
//创建连接工厂
ConnectionFactory factory = new ConnectionFactory
{
UserName = "guest",//用户名
Password = "guest",//密码
HostName = "127.0.0.1"//rabbitmq ip
}; //创建连接
var connection = factory.CreateConnection();
//创建通道
var channel = connection.CreateModel();
//声明一个队列
channel.QueueDeclare("hello", false, false, false, null); Console.WriteLine("\nRabbitMQ连接成功,请输入消息,输入exit退出!"); string input;
do
{
input = Console.ReadLine(); var sendBytes = Encoding.UTF8.GetBytes(input);
//发布消息
channel.BasicPublish("", "hello", null, sendBytes); } while (input.Trim().ToLower() != "exit");
channel.Close();
connection.Close();
定义消费者:
//创建连接工厂
ConnectionFactory factory = new ConnectionFactory
{
UserName = "guest",//用户名
Password = "guest",//密码
HostName = "127.0.0.1"//rabbitmq ip
}; //创建连接
var connection = factory.CreateConnection();
//创建通道
var channel = connection.CreateModel(); //事件基本消费者
EventingBasicConsumer consumer = new EventingBasicConsumer(channel); //接收到消息事件
consumer.Received += (ch, ea) =>
{
var message = Encoding.UTF8.GetString(ea.Body);
Console.WriteLine($"收到消息: {message}");
//确认该消息已被消费
channel.BasicAck(ea.DeliveryTag, false);
};
//启动消费者 设置为手动应答消息
channel.BasicConsume("hello", false, consumer);
Console.WriteLine("消费者已启动");
Console.ReadKey();
channel.Dispose();
connection.Close();
演示如下:

启动了一个生产者,两个消费者,可以看见两个消费者都能接收到消息,消息投递到哪个消费者是由RabbitMQ决定的。
RabbitMQ消费失败的处理
RabbitMQ采用消息应答机制,即消费者收到一个消息之后,需要发送一个应答,然后RabbitMQ才会将这个消息从队列中删除,如果消费者在消费过程中出现异常,断开连接切没有发送应答,那么RabbitMQ会将这个消息重新投递。
我们来修改一下消费者的代码:
//接收到消息事件
consumer.Received += (ch, ea) =>
{
var message = Encoding.UTF8.GetString(ea.Body); Console.WriteLine($"收到消息: {message}"); Console.WriteLine($"收到该消息[{ea.DeliveryTag}] 延迟10s发送回执");
Thread.Sleep();
//确认该消息已被消费
channel.BasicAck(ea.DeliveryTag, false);
Console.WriteLine($"已发送回执[{ea.DeliveryTag}]");
};
演示如下:

从图中可以看出,设置了消息应答延迟10s,如果在这10s中,该消费者断开了连接,那么消息会被RabbitMQ重新投递。
使用RabbitMQ的Exchange
前面的例子,我们可以看到生产者将消息投递到Queue中,实际上这种方式在RabbitMQ中永远都不会发生的。实际的情况是,生产者将消息发送到Exchange(交换器),下图中的X,由Exchange(交换器)将消息路由到一个或多个Queue中(或者丢弃)。

AMQP协议中的核心思想就是生产者和消费者隔离,生产者从不直接将消息发送给队列。生产者通常不知道是否一个消息会被发送到队列中,只是将消息发送到一个交换机。先由Exchange来接收,然后Exchange按照特定的策略转发到Queue进行存储。同理,消费者也是如此。Exchange 就类似于一个交换机,转发各个消息分发到相应的队列中。
Exchange Types(交换器类型)
RabbitMQ常用的Exchange Type有Fanout、Direct、Topic、Headers这四种
1、Fanout:
这种类型的Exchange路由规则非常简单,它会把所有发送到该Exchange的消息路由到所有与它绑定的Queue中,这时Routing key不起作用

Fanout Exchange 不需要处理RouteKey 。只需要简单的将队列绑定到exchange 上。这样发送到exchange的消息都会被转发到与该交换机绑定的所有队列上。类似子网广播,每台子网内的主机都获得了一份复制的消息。
所以,Fanout Exchange 转发消息是最快的。
为了演示效果,定义了两个队列,分别为hello1,hello2,每个队列都拥有一个消费者。
static void Main(string[] args)
{
string exchangeName = "TestFanoutChange";
string queueName1 = "hello1";
string queueName2 = "hello2";
string routeKey = ""; //创建连接工厂
ConnectionFactory factory = new ConnectionFactory
{
UserName = "guest",//用户名
Password = "guest",//密码
HostName = "127.0.0.1"//rabbitmq ip
}; //创建连接
var connection = factory.CreateConnection();
//创建通道
var channel = connection.CreateModel(); //定义一个Direct类型交换机
channel.ExchangeDeclare(exchangeName, ExchangeType.Fanout, false, false, null); //定义队列1
channel.QueueDeclare(queueName1, false, false, false, null);
//定义队列2
channel.QueueDeclare(queueName2, false, false, false, null); //将队列绑定到交换机
channel.QueueBind(queueName1, exchangeName, routeKey, null);
channel.QueueBind(queueName2, exchangeName, routeKey, null); //生成两个队列的消费者
ConsumerGenerator(queueName1);
ConsumerGenerator(queueName2); Console.WriteLine($"\nRabbitMQ连接成功,\n\n请输入消息,输入exit退出!"); string input;
do
{
input = Console.ReadLine(); var sendBytes = Encoding.UTF8.GetBytes(input);
//发布消息
channel.BasicPublish(exchangeName, routeKey, null, sendBytes); } while (input.Trim().ToLower() != "exit");
channel.Close();
connection.Close();
}
/// <summary>
/// 根据队列名称生成消费者
/// </summary>
/// <param name="queueName"></param>
static void ConsumerGenerator(string queueName)
{
//创建连接工厂
ConnectionFactory factory = new ConnectionFactory
{
UserName = "guest",//用户名
Password = "guest",//密码
HostName = "127.0.0.1"//rabbitmq ip
}; //创建连接
var connection = factory.CreateConnection();
//创建通道
var channel = connection.CreateModel(); //事件基本消费者
EventingBasicConsumer consumer = new EventingBasicConsumer(channel); //接收到消息事件
consumer.Received += (ch, ea) =>
{
var message = Encoding.UTF8.GetString(ea.Body); Console.WriteLine($"Queue:{queueName}收到消息: {message}");
//确认该消息已被消费
channel.BasicAck(ea.DeliveryTag, false);
};
//启动消费者 设置为手动应答消息
channel.BasicConsume(queueName, false, consumer);
Console.WriteLine($"Queue:{queueName},消费者已启动");
}
运行效果如下:

2、Direct
这种类型的Exchange路由规则也很简单,它会把消息路由到哪些binding key与routingkey完全匹配的Queue中。

Direct模式,可以使用rabbitMQ自带的Exchange:default Exchange 。所以不需要将Exchange进行任何绑定(binding)操作 。消息传递时,RouteKey必须完全匹配,才会被队列接收,否则该消息会被抛弃。
static void Main(string[] args)
{
string exchangeName = "TestChange";
string queueName = "hello";
string routeKey = "helloRouteKey"; //创建连接工厂
ConnectionFactory factory = new ConnectionFactory
{
UserName = "guest",//用户名
Password = "guest",//密码
HostName = "127.0.0.1"//rabbitmq ip
}; //创建连接
var connection = factory.CreateConnection();
//创建通道
var channel = connection.CreateModel(); //定义一个Direct类型交换机
channel.ExchangeDeclare(exchangeName, ExchangeType.Direct, false, false, null); //定义一个队列
channel.QueueDeclare(queueName, false, false, false, null); //将队列绑定到交换机
channel.QueueBind(queueName, exchangeName, routeKey, null); Console.WriteLine($"\nRabbitMQ连接成功,Exchange:{exchangeName},Queue:{queueName},Route:{routeKey},\n\n请输入消息,输入exit退出!"); string input;
do
{
input = Console.ReadLine(); var sendBytes = Encoding.UTF8.GetBytes(input);
//发布消息
channel.BasicPublish(exchangeName, routeKey, null, sendBytes); } while (input.Trim().ToLower() != "exit");
channel.Close();
connection.Close();
运行效果如下:

3、Topic
这种类型的Exchange的路由规则支持 binding key 和 routing key 的模糊匹配,会把消息路由到满足条件的Queue。 binding key 中可以存在两种特殊字符 *与 #,用于做模糊匹配,其中 * 用于匹配一个单词,# 用于匹配0个或多个单词,单词以符号“.”为分隔符。
以上图中的配置为例,routingKey=”quick.orange.rabbit”的消息会同时路由到Q1与Q2,routingKey=”lazy.orange.fox”的消息会路由到Q1与Q2,routingKey=”lazy.brown.fox”的消息会路由到Q2,routingKey=”lazy.pink.rabbit”的消息会路由到Q2(只会投递给Q2一次,虽然这个routingKey与Q2的两个bindingKey都匹配);routingKey=”quick.brown.fox”、routingKey=”orange”、routingKey=”quick.orange.male.rabbit”的消息将会被丢弃,因为它们没有匹配任何bindingKey。
static void Main(string[] args)
{
string exchangeName = "TestTopicChange";
string queueName = "hello";
string routeKey = "TestRouteKey.*"; //创建连接工厂
ConnectionFactory factory = new ConnectionFactory
{
UserName = "guest",//用户名
Password = "guest",//密码
HostName = "127.0.0.1"//rabbitmq ip
}; //创建连接
var connection = factory.CreateConnection();
//创建通道
var channel = connection.CreateModel(); //定义一个Direct类型交换机
channel.ExchangeDeclare(exchangeName, ExchangeType.Topic, false, false, null); //定义队列1
channel.QueueDeclare(queueName, false, false, false, null); //将队列绑定到交换机
channel.QueueBind(queueName, exchangeName, routeKey, null); Console.WriteLine($"\nRabbitMQ连接成功,\n\n请输入消息,输入exit退出!"); string input;
do
{
input = Console.ReadLine(); var sendBytes = Encoding.UTF8.GetBytes(input);
//发布消息
channel.BasicPublish(exchangeName, "TestRouteKey.one", null, sendBytes); } while (input.Trim().ToLower() != "exit");
channel.Close();
connection.Close();
}
运行效果如下:

4、Headers
这种类型的Exchange不依赖于 routing key 与 binding key 的匹配规则来路由消息,而是根据发送的消息内容中的 headers 属性进行匹配。
参考:
官网:https://www.rabbitmq.com/tutorials/tutorial-one-dotnet.html
https://www.cnblogs.com/stulzq/p/7551819.html
https://www.jianshu.com/p/e55e971aebd8
DotNet Core中使用RabbitMQ的更多相关文章
- .NET Core中使用RabbitMQ正确方式
.NET Core中使用RabbitMQ正确方式 首先甩官网:http://www.rabbitmq.com/ 然后是.NET Client链接:http://www.rabbitmq.com/dot ...
- Dotnet Core中使用AutoMapper
官网:http://automapper.org/ 文档:https://automapper.readthedocs.io/en/latest/index.html GitHub:https://g ...
- 在ABP core中使用RabbitMq
距上一篇博客的更新一集很久了,主要是最近做的事情比较杂,中间也有一个难点,就是在ABP中加入APP扫码登录,本来想些的,但是觉得这个写出来会不会让我们的系统被破解-_-||,所以想了想,就没有写. 这 ...
- WSL2+Docker部署RabbitMQ以及在Asp.net core 中使用RabbitMQ示例(1)
本文主要在于最近因疫情不能外出,在家研究的一些技术积累. 主要用到的技术以及知识点: WSL 2 WSL 2+Docker Docker+RabbitMQ 在ASP.NET Core中使用Rabbit ...
- 依赖注入在 dotnet core 中实现与使用:1 基本概念
关于 Microsoft Extension: DependencyInjection 的介绍已经很多,但是多数偏重于实现原理和一些特定的实现场景.作为 dotnet core 的核心基石,这里准备全 ...
- DotNet Core中使用dapper
我们都知道,ORM全称是,Object Relationship Mapper,即,对象关系映射.也就是可以用object来map我们的db,而且市面上的orm框架有很多,其中有一个框架叫做dappe ...
- 依赖注入在 dotnet core 中实现与使用:4. 集成 Autofac
本示例使用 .net core 5 rc-1 实现. 1. 添加 Nuget 包引用 使用 Autofac 当然要添加 Autofac 的 Nuget 包,主要涉及到两个: Autofac.Exten ...
- 学习在.NET Core中使用RabbitMQ进行消息传递之持久化(二)
前言 上一节我们简单介绍了RabbitMQ和在安装后启动所出现的问题,本节我们开始正式进入RabbitMQ的学习,对于基本概念请从官网或者其他前辈博客上查阅,我这里不介绍基础性东西,只会简单提一下,请 ...
- 依赖注入在 dotnet core 中实现与使用:2 使用 Extensions DependencyInjection
既然是依赖注入容器,必然会涉及到服务的注册,获取服务实例,管理作用域,服务注入这四个方面. 服务注册涉及如何将我们的定义的服务注册到容器中.这通常是实际开发中使用容器的第一步,而容器本身通常是由框架来 ...
随机推荐
- NSURLSession使用(整理版)
NSURLSession使用 1.NSURLSession诞生于2013年,但其在前几年一直生活在NSURLConnection的阴影下,直到iOS9的出现,NSURLConnection被官方宣布弃 ...
- iOS 手势及触摸
转自:http://justsee.iteye.com/blog/1885538 一.响应链 在IOS开发中会遇到各种操作事件,通过程序可以对这些事件做出响应. 首先,当发生事件响应时,必须知道由谁来 ...
- node.js调试入门
1-1 Inspector介绍 使用Inspector调试Node.js的优势 可查看当前上下文的变量 可观察当前函数调用堆栈 不侵入代码 可在暂停状态下执行指定代码 Inspector的构成以及原理 ...
- linux终端界面的字颜色设置
目录 目录 说明 PS1 颜色语法 保存设置 说明 在网上找了好多资料都不是很详细,要不就是语法有错误. 所以弄了好久才整明白了,写下来方便后面的人学习. 本人linux虚拟机版本为CentOs 6. ...
- 数据库Oracle日期函数
SYSDATE 函数:是一个日期函数,它返回当前数据库服务器的日期和时间. 用日期计算: • 从日期加或者减一个数,结果是一个日期值 • 两个日期相减,得到两个日期之间的天数 ,可以加小时到日期上 S ...
- UVA-11107 Life Forms(求出现K次的子串,后缀数组+二分答案)
题解: 题意: 输入n个DNA序列,你的任务是求出一个长度最大的字符串,使得它在超过一半的DNA序列中出现.如果有多解,按照字典序从小到大输入所有解. 把n个DNA序列拼在一起,中间用没有出现过的字符 ...
- LCT(Link Cut Tree)总结
概念.性质简述 首先介绍一下链剖分的概念链剖分,是指一类对树的边进行轻重划分的操作,这样做的目的是为了减少某些链上的修改.查询等操作的复杂度.目前总共有三类:重链剖分,实链剖分和并不常见的长链剖分. ...
- 分布式监控告警平台Centreon快速使用
一. Centreon概述 Centreon是一款功能强大的分布式IT监控系统,它通过第三方组件可以实现对网络.操作系统和应用程序的监控:首先,它是开源的,我们可以免费使用它:其次,它的底层采用nag ...
- SpringMvc 跨域处理
导读 由于浏览器对于JavaScript的同源策略的限制,导致A网站(Ajax请求)不能通过JS去访问B网站的数据,于是跨域问题就出现了. 跨域指的是域名.端口.协议的组合不同就是跨域. http:/ ...
- 【Web技术】281- 滴滴开源小程序框架 Mpx2.0
滴滴Mpx框架负责人@hiyuki,滴滴出行网约车webapp乘客团队的负责人,也是滴滴开源的小程序框架Mpx的负责人和核心作者 Mpx是一款致力于提高小程序开发体验和效率的增强型小程序框架,目前在滴 ...