Rabbit MQ 实例(.NET)

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

    }
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值