asp.net 使用rabbitmq事例
本例asp.net 使用rabbitmq需求背景:为了提升用户体验,用户点击下单按钮,后台先做一些简单必要的操作,返回给用户一个友好提示(比如提示处理中,或者订单状态为处理中),然后发通过发消息给队列,把耗时久的操作留给rabbitmq队列处理。
1、生产者封装类:
public class Publisher
{
private readonly string _exchange;
private readonly string _hostName;
private readonly string _password;
private readonly Uri _uri;
private readonly string _userName;
private readonly string _virtualHost; /// <param name="exchange"></param>
/// <param name="hostName"></param>
/// <param name="userName"></param>
/// <param name="password"></param>
/// <param name="virtualHost"></param>
/// <param name="uri">AMQP Address</param>
public Publisher(string exchange, string hostName, string userName, string password, string virtualHost, Uri uri)
{
_hostName = hostName;
_exchange = exchange;
_userName = userName;
_password = password;
_virtualHost = virtualHost;
_uri = uri; Factory = new ConnectionFactory
{
HostName = _hostName,
UserName = _userName,
Password = _password,
VirtualHost = _virtualHost,
Endpoint = new AmqpTcpEndpoint(_uri),
RequestedHeartbeat =
};
Factory.RequestedHeartbeat = ;
} public string HostName
{
get { return _hostName; }
} public string Exchange
{
get { return _exchange; }
} public string UserName
{
get { return _userName; }
} public string Password
{
get { return _password; }
} public string VirtualHost
{
get { return _virtualHost; }
} public Uri Uri
{
get { return _uri; }
} public ConnectionFactory Factory { get; private set; } /// <summary>
/// 直连式交换机,发消息
/// </summary>
/// <param name="queueName">队列名</param>
/// <param name="message">消息</param>
/// <param name="durable">消息是否持久化</param>
public void PublishDirectMessage(string queueName, string message, bool durable=false)
{
if (null == Factory)
{
throw new ArgumentException("connection factory initialization error");
} if (string.IsNullOrWhiteSpace(message))
{
throw new ArgumentNullException("message can not be null.");
} if (string.IsNullOrWhiteSpace(Exchange))
{
throw new ArgumentNullException("exchange can not be null.");
} try
{
using (var connection = Factory.CreateConnection())
{
//通道 (Channel),在C#客户端里叫Model(不明白为什么这么取名字),其他客户端基本都叫Channel
using (var channel = connection.CreateModel())
{
//定义交换机
channel.ExchangeDeclare(Exchange, ExchangeType.Direct, durable: durable,
autoDelete: false, arguments: null); //定义队列,如果名称相同不会重复创建
channel.QueueDeclare(queueName, durable: durable, exclusive: false,
autoDelete: false, arguments: null); //绑定
channel.QueueBind(queueName, Exchange, routingKey: queueName); //消息可持久化
IBasicProperties props = null;
if (durable) {
props = channel.CreateBasicProperties();
props.SetPersistent(true);
} //发送消息到队列
var msgBody = Encoding.UTF8.GetBytes(message);
channel.BasicPublish(Exchange, routingKey: queueName, basicProperties: props,
body: msgBody);
}
}
}
catch (Exception ex)
{
LogHelper.Log(LogCategory.Error, ex.Message, ex);
}
} /// <summary>
/// Fanout(广播)式交换机
/// </summary>
/// <param name="message"></param>
public void PublishFanoutMessage(string message)
{
if (null == Factory)
{
throw new ArgumentException("connection factory initialization error");
} if (string.IsNullOrWhiteSpace(message))
{
throw new ArgumentNullException("message can not be null.");
} if (string.IsNullOrWhiteSpace(Exchange))
{
throw new ArgumentNullException("exchange can not be null.");
} try
{
using (var connection = Factory.CreateConnection())
{
using (var channel = connection.CreateModel())
{
channel.ExchangeDeclare(Exchange, ExchangeType.Fanout);
byte[] body = Encoding.UTF8.GetBytes(message);
channel.BasicPublish(Exchange, "", null, body);
}
}
}
catch (Exception ex)
{
LogHelper.Log(LogCategory.Error, ex.Message, ex);
}
}
}
生产者
2、消费者封装类:
public delegate void ReceiveMessageHandle(string inputStr);
public delegate bool ReceiveAnswerMessageHandle(string inputStr); /// <typeparam name="T">要接收的数据类型</typeparam>
public class Subscriber<T> : IDisposable
{
private readonly string _exchange;
private readonly string _hostName;
private readonly string _password;
private readonly Uri _uri;
private readonly string _userName;
private readonly string _virtualHost; /// <param name="exchange"></param>
/// <param name="hostName"></param>
/// <param name="userName"></param>
/// <param name="password"></param>
/// <param name="virtualHost"></param>
/// <param name="uri">AMQP Address</param>
public Subscriber(string exchange, string hostName, string userName, string password, string virtualHost,
Uri uri)
{
_hostName = hostName;
_exchange = exchange;
_userName = userName;
_password = password;
_virtualHost = virtualHost;
_uri = uri; Factory = new ConnectionFactory
{
HostName = _hostName,
UserName = _userName,
Password = _password,
VirtualHost = _virtualHost,
Endpoint = new AmqpTcpEndpoint(_uri),
RequestedHeartbeat =
}; Connection = Factory.CreateConnection();
Channel = Connection.CreateModel();
} public string HostName
{
get { return _hostName; }
} public string Exchange
{
get { return _exchange; }
} public string UserName
{
get { return _userName; }
} public string Password
{
get { return _password; }
} public string VirtualHost
{
get { return _virtualHost; }
} public Uri Uri
{
get { return _uri; }
} public ConnectionFactory Factory { get; private set; } public IModel Channel { get; private set; }
public IConnection Connection { get; private set; }
public EventingBasicConsumer Consumer { get; private set; } private string QueueName { get; set; } public string Message { get; set; } //public delegate string MessageHandle(); /// <summary>
/// 手动释放
/// </summary>
void IDisposable.Dispose()
{
if (Channel != null)
{
Consumer = null;
Channel.Close();
Channel.Dispose();
} if (Connection != null)
{
Consumer = null;
Connection.Close();
Connection.Dispose();
} GC.SuppressFinalize(this);
} /// <summary>
/// 托管释放
/// </summary>
~Subscriber()
{
if (Channel != null)
{
Consumer = null;
Channel.Close();
Channel.Dispose();
} if (Connection != null)
{
Consumer = null;
Connection.Close();
Connection.Dispose();
}
} public ReceiveMessageHandle ReceiveMessageHandler { get; set; }
public ReceiveAnswerMessageHandle ReceiveAnswerMessageHandle { get; set; } /// <summary>
/// 接受广播消息
/// <param name="tryTimes">消费失败后,继续尝试消费的次数</param>
/// </summary>
public void ReceiveFanoutMessage(int tryTimes = )
{
try
{
//Channel.ExchangeDeclare(Exchange, ExchangeType.Fanout);
//QueueName = Channel.QueueDeclare().QueueName;
//Channel.QueueBind(QueueName, Exchange, "");
//Consumer = new EventingBasicConsumer(Channel);
//Consumer.Received += (model, dlvrArgs) =>
//{
// byte[] body = dlvrArgs.Body;
// Message = Encoding.UTF8.GetString(body);
// ReceiveMessageHandler(Message);
//};
//Channel.BasicConsume(QueueName, true, Consumer); Channel.ExchangeDeclare(Exchange, ExchangeType.Fanout);
QueueName = Channel.QueueDeclare().QueueName;
Channel.QueueBind(QueueName, Exchange, "");
Consumer = new EventingBasicConsumer(Channel);
Consumer.Received += (model, dlvrArgs) =>
{
byte[] body = dlvrArgs.Body;
if (body != null && body.Length > )
{
Message = Encoding.UTF8.GetString(body);
if (!string.IsNullOrWhiteSpace(Message))
{
bool isConsumeSuccess = false;// 是否消费成功
int consumeCount = ;//尝试消费次数
while (!isConsumeSuccess)
{
consumeCount++;
isConsumeSuccess = ReceiveAnswerMessageHandle(Message);
if (isConsumeSuccess || consumeCount >= tryTimes)
{
Channel.BasicAck(dlvrArgs.DeliveryTag, false);//将队列里面的消息进行释放
isConsumeSuccess = true;
}
else
{
//重新放入队列,等待再次消费
Channel.BasicAck(dlvrArgs.DeliveryTag, true);
}
}
}
}
};
Channel.BasicConsume(QueueName, false, Consumer);
}
catch (Exception ex)
{
LogHelper.Log(LogCategory.Error, ex.Message, ex);
}
} /// <summary>
/// 接受直连交换机消息
/// </summary>
/// <param name="queueName">队列名</param>
/// <param name="durable">消息是否持久化</param>
/// <param name="tryTimes">消费失败后,继续尝试消费的次数</param>
/// <returns></returns>
public void ReceiveDirectMessage(string queueName, bool durable = false, int tryTimes = )
{
try
{
Channel.ExchangeDeclare(Exchange, ExchangeType.Direct, durable: durable, autoDelete: false, arguments: null);
Channel.QueueDeclare(queueName, durable: durable, exclusive: false, autoDelete: false, arguments: null);
Channel.QueueBind(queueName, Exchange, routingKey: queueName);
//订阅模式 (有消息到达将被自动接收) 消费者
Consumer = new EventingBasicConsumer(Channel);
//绑定消息接收后的事件委托
Consumer.Received += (model, dlvrArgs) =>
{
byte[] body = dlvrArgs.Body;
if (body != null && body.Length > )
{
Message = Encoding.UTF8.GetString(body);
if (!string.IsNullOrWhiteSpace(Message))
{
bool isConsumeSuccess = false;// 是否消费成功
int consumeCount = ;//尝试消费次数
while (!isConsumeSuccess)
{
consumeCount++;
isConsumeSuccess = ReceiveAnswerMessageHandle(Message);
if (isConsumeSuccess || consumeCount >= tryTimes)
{
Channel.BasicAck(dlvrArgs.DeliveryTag, false);//将队列里面的消息进行释放
isConsumeSuccess = true;
}
else
{
//重新放入队列,等待再次消费
Channel.BasicAck(dlvrArgs.DeliveryTag, true);
}
}
}
}
};
Channel.BasicConsume(queueName, false, Consumer);
} catch (Exception ex)
{
LogHelper.Log(LogCategory.Error, ex.Message, ex);
}
} public T ToJson()
{
return JsonConvert.DeserializeObject<T>(Message);
}
}
消费者
3、新建控制台程序,发送消息:
class Program
{
public static string MqUri = ConfigHelper.GetConfig("RabbitMQ", "MqUri");
public static string MqExchange = ConfigHelper.GetConfig("RabbitMQ", "MqExchange");
public static string MqHostName = ConfigHelper.GetConfig("RabbitMQ", "MqHostName");
public static string MqUserName = ConfigHelper.GetConfig("RabbitMQ", "MqUserName");
public static string MqPassword = ConfigHelper.GetConfig("RabbitMQ", "MqPassword"); static void Main(string[] args)
{
string userCommand = "";
while (userCommand != "exit")
{
Console.WriteLine("请输入:");
userCommand = Console.ReadLine(); //发送消息
var publisher = new Publisher(MqExchange, MqHostName,
MqUserName, MqPassword, "/", new Uri(MqUri)); publisher.PublishFanoutMessage(userCommand);
}
}
}
发送消息控制台应用
4、新建控制台程序,接受消息:
internal class Program
{
public static string MqUri = ConfigHelper.GetConfig("RabbitMQ", "MqUri");
public static string MqExchange = ConfigHelper.GetConfig("RabbitMQ", "MqExchange");
public static string MqHostName = ConfigHelper.GetConfig("RabbitMQ", "MqHostName");
public static string MqUserName = ConfigHelper.GetConfig("RabbitMQ", "MqUserName");
public static string MqPassword = ConfigHelper.GetConfig("RabbitMQ", "MqPassword"); static void Main(string[] args)
{
Console.WriteLine("Start process data {0}", DateTime.Now);
try
{
var subscriber = new Subscriber<string>(
MqExchange, MqHostName, MqUserName, MqPassword, "/",
new Uri(MqUri))
{
ReceiveAnswerMessageHandle = SubscriberHandler1
}; subscriber.ReceiveFanoutMessage(); }
catch (Exception ex)
{
Console.WriteLine(ex);
}
} private static bool SubscriberHandler1(string msg)
{
Console.WriteLine(msg);
return true;
}
}
接受消息控制台应用
5、配置文件:
上面两个控制台的配置文件一样,如下:
<RabbitMQ>
<add key="MqUri" value="amqp://localhost/" />
<add key="MqExchange" value="MyExchange" />
<add key="MqHostName" value="localhost" />
<add key="MqUserName" value="root" />
<add key="MqPassword" value="root" />
</RabbitMQ>
6、结果图:

asp.net 使用rabbitmq事例的更多相关文章
- DotNet 资源大全中文版(Awesome最新版)
Awesome系列的.Net资源整理.awesome-dotnet是由quozd发起和维护.内容包括:编译器.压缩.应用框架.应用模板.加密.数据库.反编译.IDE.日志.风格指南等. 算法与数据结构 ...
- 【资源大全】.NET资源大全中文版(Awesome最新版)
算法与数据结构(Algorithms and Data structures) 应用程序接口(API) 应用程序框架(Application Frameworks) 模板引擎(Application ...
- ASP.NET Core Web API下事件驱动型架构的实现(三):基于RabbitMQ的事件总线
在上文中,我们讨论了事件处理器中对象生命周期的问题,在进入新的讨论之前,首先让我们总结一下,我们已经实现了哪些内容.下面的类图描述了我们已经实现的组件及其之间的关系,貌似系统已经变得越来越复杂了. 其 ...
- ASP.NET Core2利用MassTransit集成RabbitMQ
在ASP.NET Core上利用MassTransit来集成使用RabbitMQ真的很简单,代码也很简洁.近期因为项目需要,我便在这基础上再次进行了封装,抽成了公共方法,使得使用RabbitMQ的调用 ...
- 如何从40亿整数中找到不存在的一个 webservice Asp.Net Core 轻松学-10分钟使用EFCore连接MSSQL数据库 WPF实战案例-打印 RabbitMQ与.net core(五) topic类型 与 headers类型 的Exchange
如何从40亿整数中找到不存在的一个 前言 给定一个最多包含40亿个随机排列的32位的顺序整数的顺序文件,找出一个不在文件中的32位整数.(在文件中至少确实一个这样的数-为什么?).在具有足够内存的情况 ...
- ExpandoObject与DynamicObject的使用 RabbitMQ与.net core(一)安装 RabbitMQ与.net core(二)Producer与Exchange ASP.NET Core 2.1 : 十五.图解路由(2.1 or earler) .NET Core中的一个接口多种实现的依赖注入与动态选择看这篇就够了
ExpandoObject与DynamicObject的使用 using ImpromptuInterface; using System; using System.Dynamic; names ...
- 简述C#中IO的应用 RabbitMQ安装笔记 一次线上问题引发的对于C#中相等判断的思考 ef和mysql使用(一) ASP.NET/MVC/Core的HTTP请求流程
简述C#中IO的应用 在.NET Framework 中. System.IO 命名空间主要包含基于文件(和基于内存)的输入输出(I/O)服务的相关基础类库.和其他命名空间一样. System.I ...
- ASP.NET Core2基于RabbitMQ对Web前端实现推送功能
在我们很多的Web应用中会遇到需要从后端将指定的数据或消息实时推送到前端,通常的做法是前端写个脚本定时到后端获取,或者借助WebSocket技术实现前后端实时通讯.因定时刷新的方法弊端很多(已不再采用 ...
- 重温.NET下Assembly的加载过程 ASP.NET Core Web API下事件驱动型架构的实现(三):基于RabbitMQ的事件总线
重温.NET下Assembly的加载过程 最近在工作中牵涉到了.NET下的一个古老的问题:Assembly的加载过程.虽然网上有很多文章介绍这部分内容,很多文章也是很久以前就已经出现了,但阅读之后 ...
随机推荐
- 【原创】大叔问题定位分享(9)oozie提交spark任务报 java.lang.NoClassDefFoundError: org/apache/kafka/clients/producer/KafkaProducer
oozie中支持很多的action类型,比如spark.hive,对应的标签为: <spark xmlns="uri:oozie:spark-action:0.1"> ...
- Emacs Org-mode 2 文档结构
2.1 章节 org-mode用* 标识章节,一个* 代表一级标题,两个* 代表两级标题,以此类推.最多6颗星,也就是最多6级. 书写格式如下: * 标题一 ** 标题二 注意, * 后有空格.不同的 ...
- Javascript实现的数组降维——维度不同,怎么谈恋爱(修订版)
数组的元素可能是数组,这样一层层嵌套,可能得到一个嵌套很深的数组,数组降维要做的事就是把嵌套很深的数组展开,一般最后得到一个一维数组,其中的元素都是非数组元素,比如数组[1, [2, 3, [4, 5 ...
- 有标号的DAG计数I~IV
题解: https://www.cnblogs.com/zhoushuyu/p/10077241.html 看到这么一篇,发现挺不错的..
- Python_paramiko模块
paramiko模块安装:pip3 install paramiko paramiko模块(模拟SSH),是基于SSH(网络安全协议)用于连接远程服务器并执行相关操作. ssh: 基于口令的安全验证 ...
- Linux awk学习
零.awk标准语法 [root@wohaoshuai1 bbb]# echo "abcd" |awk 'BEGIN{print "wohaoshuai"} /a ...
- pc端网页,移动端网页(andorid、ios)离开页面做一个时间存储
如图所示:在一个页面中做了一个倒计时,然后用户想离开页面做其他事情,需求是离开页面之后把时间保存,下一次进来继续的时候时间还是上次离开的时间 第一次我用的事件是: // window.onbefor ...
- Android-SD卡相关操作
SD卡相关操作 1.获取 App 文件目录 //获取 当前APP 文件路径 String path1 = this.getFilesDir().getPath(); 当前APP目录也就是应用的这个目录 ...
- MongDB增删改查
增加 增加一条:db.th.insertOne({}) // 返回 _id 增加多条:db.th.insertMany([{},{},{}]) // 返回 _ids 针对Array增加操作: db.s ...
- Codechef August Challenge 2018 : Lonely Cycles
传送门 几波树形dp就行了. #include<cstdio> #include<cstring> #include<algorithm> #define MN 5 ...