Rabbit MQ 实例(.NET)
using Newtonsoft.Json;
using RabbitMQ.Client;
using RabbitMQ.Client.Events;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using log4net;
namespace Vcredit.RC.Helper.RabbitMQ
{
public class RabbitMqConfig
{
/// <summary>
/// Ip
/// </summary>
public string Ip { get; set; }
/// <summary>
/// 用户名
/// </summary>
public string UserName { get; set; }
/// <summary>
/// 密码
/// </summary>
public string Password { get; set; }
/// <summary>
/// 端口号
/// </summary>
public int Port { get; set; }
/// <summary>
/// 虚拟路径
/// </summary>
public string VirtualHost { get; set; }
/// <summary>
/// 队列名
/// </summary>
public string QueueName { get; set; }
/// <summary>
/// 交换机
/// </summary>
public string ExchangeName { get; set; }
/// <summary>
/// 交换机类型direct,topic, fanout
/// </summary>
public string ExchangeType { get; set; }
/// <summary>
/// 交换机与队列绑定的关键字
/// </summary>
public string RoutingKey { get; set; }
/// <summary>
/// 消费者通道同一时间接受的消息上限
/// </summary>
public ushort PrefetchCount { get; set; }
/// <summary>
/// 是否持久化该队列
/// </summary>
public bool DurableQueue { get; set; }
/// <summary>
/// 是否持久化队列中的消息
/// </summary>
public bool DurableMessage { get; set; }
/// <summary>
/// 消息头,可以获取设置x-death等
/// </summary>
public IDictionary<string, object> Headers { get; set; }
/// <summary>
/// 参数,如x-message-ttl,x-dead-letter-exchange,x-dead-letter-routing-key
/// </summary>
public IDictionary<string, object> Arguments { get; set; }
}
/// <summary>
/// 数据被执行后的处理方式
/// </summary>
public enum ProcessingResultsEnum
{
/// <summary>
/// 处理成功
/// </summary>
Accept,
/// <summary>
/// 可以重试的错误
/// </summary>
Retry,
/// <summary>
/// 无需重试的错误
/// </summary>
Reject,
}
public class MessageQueueSerice
{
#region 字段
public static IConnection _connection;
private static ILog _logger = LogManager.GetLogger(typeof(RedisHelper));
#endregion
#region 构造函数
/// <summary>
/// 构造函数
/// </summary>
/// <param name="config"></param>
public MessageQueueSerice(RabbitMqConfig RabbitConfig)
{
try
{
CreateConn(RabbitConfig);
}
catch (Exception)
{
throw;
}
}
#endregion
#region 初始化
/// <summary>
/// 创建连接
/// </summary>
public void CreateConn(RabbitMqConfig RabbitConfig)
{
ConnectionFactory cf = new ConnectionFactory();
cf.Port = RabbitConfig.Port; //服务器的端口
cf.Endpoint = new AmqpTcpEndpoint(new Uri("amqp://" + RabbitConfig.Ip + "/")); //服务器ip
cf.UserName = RabbitConfig.UserName; //登录账户
cf.Password = RabbitConfig.Password; //登录账户
cf.VirtualHost = RabbitConfig.VirtualHost; //虚拟主机
cf.RequestedHeartbeat = 60; //虚拟主机
//cf.AutomaticRecoveryEnabled = true;//将自动恢复连接
//cf.NetworkRecoveryInterval = TimeSpan.FromSeconds(10);//每10秒钟尝试恢复一次
_connection = cf.CreateConnection();
}
#endregion
#region 方法
#region 发送消息
/// <summary>
/// 发送消息,泛型
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="message"></param>
/// <returns></returns>
public bool Send<T>(T messageInfo, ref string errMsg, RabbitMqConfig RabbitConfig)
{
if (messageInfo == null)
{
errMsg = "消息对象不能为空";
return false;
}
string value = JsonConvert.SerializeObject(messageInfo);
return Send(value, ref errMsg, RabbitConfig);
}
/// <summary>
/// 发送消息,string类型
/// </summary>
/// <param name="message"></param>
/// <param name="errMsg"></param>
/// <returns></returns>
public bool Send(string message, ref string errMsg, RabbitMqConfig RabbitConfig)
{
if (string.IsNullOrEmpty(message))
{
errMsg = "消息不能为空";
return false;
}
try
{
if (!_connection.IsOpen)
{
CreateConn(RabbitConfig);
}
using (var channel = _connection.CreateModel())
{
//推送消息
byte[] bytes = Encoding.UTF8.GetBytes(message);
IBasicProperties properties = channel.CreateBasicProperties();
properties.DeliveryMode = Convert.ToByte(RabbitConfig.DurableMessage ? 2 : 1); //支持可持久化数据
if (RabbitConfig.Headers != null)
{
properties.Headers = RabbitConfig.Headers;
}
channel.ExchangeDeclare(RabbitConfig.ExchangeName, RabbitConfig.ExchangeType.ToString(), RabbitConfig.DurableQueue, false, null);
channel.QueueDeclare(RabbitConfig.QueueName, RabbitConfig.DurableQueue, false, false, RabbitConfig.Arguments);
channel.QueueBind(RabbitConfig.QueueName, RabbitConfig.ExchangeName, RabbitConfig.RoutingKey, null);
channel.BasicPublish(RabbitConfig.ExchangeName, RabbitConfig.RoutingKey, properties, bytes);
return true;
}
}
catch (Exception ex)
{
errMsg = ex.Message;
return false;
}
}
#endregion
#region 接受消息,使用Func进行处理
public void Receive<T>(Func<T, IDictionary<string, object>, bool> method, RabbitMqConfig RabbitConfig)
{
try
{
using (var channel = _connection.CreateModel())
{
#region 绑定队列和交换机
channel.ExchangeDeclare(RabbitConfig.ExchangeName, RabbitConfig.ExchangeType.ToString(), RabbitConfig.DurableQueue, false, null);
channel.QueueDeclare(RabbitConfig.QueueName, RabbitConfig.DurableQueue, false, false, RabbitConfig.Arguments);
channel.QueueBind(RabbitConfig.QueueName, RabbitConfig.ExchangeName, RabbitConfig.RoutingKey, null);
#endregion
#region 业务
//RabbitConfig.PrefetchCount输入1,那如果接收一个消息,但是没有应答,则客户端不会收到下一个消息
channel.BasicQos(0, RabbitConfig.PrefetchCount, false);
//在队列上定义一个消费者
var consumer = new EventingBasicConsumer(channel);
consumer.Received += (model, ea) =>
{
//阻塞函数,获取队列中的消息
ProcessingResultsEnum processingResult = ProcessingResultsEnum.Retry;
ulong deliveryTag = 0;
try
{
deliveryTag = ea.DeliveryTag;
byte[] bytes = ea.Body;
string body = Encoding.UTF8.GetString(bytes);
T info = JsonConvert.DeserializeObject<T>(body);
bool r = method(info, ea.BasicProperties.Headers);//调用自己的业务方法进行相关处理
processingResult = r ? ProcessingResultsEnum.Accept : ProcessingResultsEnum.Retry;
}
catch (Exception ex)
{
processingResult = ProcessingResultsEnum.Reject; //系统无法处理的错误
_logger.Error("RabbitMq消息处理异常", ex);//写日志
}
finally
{
switch (processingResult)
{
case ProcessingResultsEnum.Accept:
//回复确认处理成功
channel.BasicAck(deliveryTag,
false);//处理单条信息
break;
case ProcessingResultsEnum.Retry:
//发生错误了,但是还可以重新提交给队列重新分配
channel.BasicNack(deliveryTag, false, true);
break;
case ProcessingResultsEnum.Reject:
//发生严重错误,无法继续进行,这种情况应该写日志或者是发送消息通知管理员
channel.BasicNack(deliveryTag, false, false);
break;
}
}
};
channel.BasicConsume(RabbitConfig.QueueName,
false,//和tcp协议的ack一样,为false则服务端必须在收到客户端的回执(ack)后才能删除本条消息
consumer);
System.Threading.Thread.Sleep(-1);
}
#endregion
}
catch (Exception ex)
{
//写日志
_logger.Error("RabbitMq获取消息异常", ex);
}
}
#endregion
#endregion
}
}