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的加载过程.虽然网上有很多文章介绍这部分内容,很多文章也是很久以前就已经出现了,但阅读之后 ...
随机推荐
- c语言宏定义详解
1,防止一个头文件被重复包含 #ifndef COMDEF_H #define COMDEF_H //头文件内容 #endif 2,重新定义一些类型,防止由于各种平台和编译器的不同,而产生的类型字节数 ...
- MySQL入门命令
SQL(Structured Query Language) SQL是结构化查询语言,是一种用来操作RDBMS的数据库语言,当前关系型数据库都支持使用SQL语言进行操作,也就是说可以通过 SQL 操作 ...
- SQL反模式学习笔记20 明文密码
目标:恢复或重置密码 反模式:使用明文存储密码 1.存储密码 使用明文存储密码或者在网络上传递密码是不安全的. 如果攻击者截取到你用来插入(或者修改)密码的sql语句,就可以获得密码. 黑客获 ...
- c_数据结构_队的实现
# 链式存储#include<stdio.h> #include<stdlib.h> #define STACK_INIT_SIZE 100//存储空间初始分配量 #defin ...
- ef core的外键约束笔记
ef core设置可选外键,有如下几种方式:1.在依赖实体AAA中,并不显式设置外键属性XXXId 2.手动设置外键属性XXXId为可空类型(int?等类型) 3.在实体类与数据表进行映射时,配置狭隘 ...
- Oracle存储过程向Hadoop迁移中的问题及方案
本文记录Oracle存储过程向Hadoop迁移中遇到的问题及响应的解决办法,作为初学者,文中内容有不妥之处欢迎指正, 1.不支持IN中的子查询,Solution,使用INNER JOIN将子查询操作添 ...
- [linux]主机访问虚拟机web服务(CentOS)
目的为了实现主机和虚拟机的通信,访问虚拟机中架设的web服务.按理说通过虚拟机ip + web服务端口,即可在浏览器访问虚拟机的web服务.但是由于CentOS的防火墙问题,对应web端口无法访问.通 ...
- SQL语句删除表中的字段只留下最新一行
方法一 DELETE FROM A WHERE `name` in ( SELECT a.name FROM( SELECT name FROM A a GROUP BY name HAVING CO ...
- Face The Right Way [POJ3276] [开关问题]
题意: 有n头奶牛排成一排,有的朝前(F)有的朝后(B),现在你可以使k头奶牛一次性翻转朝向(n>=k>=1),问你最少的翻转次数和此时对应的k值. Input Line 1: A sin ...
- JS AJAX 跨域
原因: 浏览器的同源策略,不允许AJAX 访问 其他接口 协议,域名,端口 一个不同 就跨域了 http 端口(80) https(443) 可以跨域的三个标签: 1. img : 打点统计,没有浏 ...