zoukankan      html  css  js  c++  java
  • RabbitMQ操作代码封装

    1、Message.cs

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    
    namespace XFC.RabbitMQ.Domain
    {
        /// <summary>
        /// 消息实体
        /// </summary>
        public class Message
        {
            /// <summary>
            /// 消息创建
            /// </summary>
            /// <param name="value"></param>
            /// <param name="headers">头信息</param>
            /// <param name="contentType">MIME content type,缺省值为 text/plain</param>
            public Message(string value, IDictionary<string, object> headers, string contentType)
            {
                Value = value;
                Headers = headers;
                ContentType = contentType;
            }
    
            /// <summary>
            /// 消息创建
            /// </summary>
            /// <param name="value"></param>
            /// <param name="headers">头信息</param>
            public Message(string value, IDictionary<string, object> headers)
                : this(value, headers, "text/plain")
            {
         
            }
    
            /// <summary>
            /// 消息创建
            /// </summary>
            /// <param name="value"></param>
            /// <param name="contentType">MIME content type</param>
            public Message(string value, string contentType)
                : this(value, null, contentType)
            {
    
            }
    
            /// <summary>
            /// 消息创建
            /// </summary>
            /// <param name="value"></param>
            public Message(string value)
                : this(value, null, "text/plain")
            {
    
            }
    
            /// <summary>
            /// 消息创建
            /// </summary>
            public Message()
                : this("", null, "text/plain")
            {
    
            }
            /// <summary>
            /// 消息值
            /// </summary>
            public string Value { get; set; }
    
            /// <summary>
            /// 消息头
            /// </summary>
            public IDictionary<string, object> Headers { get; set; }
    
            /// <summary>
            /// MIME content type
            /// </summary>
            public string ContentType { get; set; }
        }
    }
    View Code

    2、RabbitMqPublisher.cs

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    using RabbitMQ.Client;
    using XFC.RabbitMQ.Domain;
    
    namespace XFC.RabbitMQ
    {
        public class RabbitMqPublisher
        {
            private readonly string _rabbitMqUri;
    
            /// <summary>
            /// 构造函数
            /// </summary>
            /// <param name="rabbitMqUri">连接串,如 amqp://guest:guest@localhost:5672/</param>
            public RabbitMqPublisher(string rabbitMqUri)
            {
                this._rabbitMqUri = rabbitMqUri;
            }
    
            /// <summary>
            /// 创建连接
            /// </summary>
            private IConnection CreateConnection()
            {
                var factory = new ConnectionFactory
                {
                    Uri = new Uri(_rabbitMqUri)
                };
    
               return factory.CreateConnection();
            }
    
            /// <summary>
            /// 创建信道
            /// </summary>
            private IModel CreateChannel(IConnection con, string exchangeName, string exchangeType, string queueName, string routeKey)
            {
                var channel = con.CreateModel();
                channel.ExchangeDeclare(exchangeName, exchangeType, true, false, null);
                if (!string.IsNullOrEmpty(queueName))
                {
                    channel.QueueDeclare(queueName, true, false, false, null); //创建一个消息队列,用来存储消息
                    channel.QueueBind(queueName, exchangeName, routeKey, null);
                }
               
                channel.BasicQos(0, 3, true); //在非自动确认消息的前提下,如果一定数目的消息(通过基于consume或者channel设置Qos的值)未被确认前,不进行消费新的消息
                return channel;
            }
    
            /// <summary>
            /// 发送ExchangeType类型为Direct的消息
            /// </summary>
            /// <param name="exchangeName">交换机名称</param>
            /// <param name="routeKey">消息路由key</param>
            /// <param name="message">消息实体</param>
            /// <param name="queueName">缺省队列名(不存在则自动创建),设置后可避免消息发送后由于没有队列接收而丢失的问题</param>
            /// <returns></returns>
            public bool PublishDirectMessage(string exchangeName, string routeKey, Message message, string queueName = "")
            {
                return this.PublishMessage(exchangeName, ExchangeType.Direct, queueName, routeKey, new[] { message });
            }
    
            /// <summary>
            /// 批量发送ExchangeType类型为Direct的消息
            /// </summary>
            /// <param name="exchangeName">交换机名称</param>
            /// <param name="routeKey">消息路由key</param>
            /// <param name="messages">消息实体</param>
            /// <param name="queueName">缺省队列名(不存在则自动创建),设置后可避免消息发送后由于没有队列接收而丢失的问题</param>
            /// <returns></returns>
            public bool PublishDirectMessages(string exchangeName, string routeKey, IEnumerable<Message> messages, string queueName = "")
            {
                return this.PublishMessage(exchangeName, ExchangeType.Direct, queueName, routeKey, messages);
            }
    
            /// <summary>
            /// 发送ExchangeType类型为Fanout的消息
            /// </summary>
            /// <param name="exchangeName">交换机名称</param>
            /// <param name="message">消息实体</param>
            /// <param name="queueName">缺省队列名(不存在则自动创建),设置后可避免消息发送后由于没有队列接收而丢失的问题</param>
            /// <returns></returns>
            public bool PublishFanoutMessage(string exchangeName, Message message, string queueName = "")
            {
                return this.PublishMessage(exchangeName, ExchangeType.Fanout, queueName, "", new[] { message });
            }
    
            /// <summary>
            /// 批量发送ExchangeType类型为Fanout的消息
            /// </summary>
            /// <param name="exchangeName">交换机名称</param>
            /// <param name="messages">消息实体</param>
            /// <param name="queueName">缺省队列名(不存在则自动创建),设置后可避免消息发送后由于没有队列接收而丢失的问题</param>
            /// <returns></returns>
            public bool PublishFanoutMessages(string exchangeName, IEnumerable<Message> messages, string queueName = "")
            {
                return this.PublishMessage(exchangeName, ExchangeType.Fanout, queueName, "", messages);
            }
    
            private bool PublishMessage(string exchangeName, string exchangeType, string queueName, string routeKey, IEnumerable<Message> messages)
            {
                using (var con = CreateConnection())
                {
                    using (var channel = CreateChannel(con, exchangeName, exchangeType, queueName, routeKey))
                    {
                        channel.ConfirmSelect();//启用消息发送确认机制
    
                        foreach (var message in messages)
                        {
                            var body = Encoding.UTF8.GetBytes(message.Value);
                            var properties = channel.CreateBasicProperties();
                            properties.Persistent = true; //使消息持久化
                            properties.Headers = message.Headers;
                            properties.ContentType = string.IsNullOrEmpty(message.ContentType) ? "text/plain" : message.ContentType;
                            channel.BasicPublish(exchangeName, routeKey, properties, body);
                        }
    
                        return channel.WaitForConfirms();
                    }
                }
            }
        }
    }
    View Code

    3、RabbitMqQuery.cs

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    using RabbitMQ.Client;
    using XFC.RabbitMQ.Domain;
    
    namespace XFC.RabbitMQ
    {
        public class RabbitMqQuery
        {
            private readonly string _rabbitMqUri;
    
            /// <summary>
            /// 构造函数
            /// </summary>
            /// <param name="rabbitMqUri">连接串,如 amqp://guest:guest@localhost:5672/</param>
            public RabbitMqQuery(string rabbitMqUri)
            {
                this._rabbitMqUri = rabbitMqUri;
            }
    
            /// <summary>
            /// 创建连接
            /// </summary>
            private IConnection CreateConnection()
            {
                var factory = new ConnectionFactory
                {
                    Uri = new Uri(_rabbitMqUri)
                };
    
               return factory.CreateConnection();
            }
    
            /// <summary>
            /// 拉取队列中的数据
            /// </summary>
            /// <param name="queueName">队列名</param>
            /// <returns></returns>
            public Message GetMessage(string queueName)
            {
                using (var con = this.CreateConnection())
                {
                    var channel = con.CreateModel();
                    var rs = channel.BasicGet(queueName, true);
                    return ResultToMessage(rs);
                } 
            }
    
            /// <summary>
            /// 批量拉取队列中的数据
            /// </summary>
            /// <param name="queueName">队列名</param>
            /// <param name="queryCount">拉取数据的条数,默认为1</param>
            /// <returns></returns>
            public Message[] GetMessages(string queueName, int queryCount = 1)
            {
                if (queryCount <= 0){ queryCount = 1; }
    
                var msgLst = new List<Message>();
                using (var con = this.CreateConnection())
                {
                    var channel = con.CreateModel();
                    for (int i = 0; i < queryCount; i++)
                    {
                        var rs = channel.BasicGet(queueName, true);
                        if (rs != null)
                        {
                            msgLst.Add(ResultToMessage(rs));
                        }
                        else
                        {
                            break;
                        }
                    } 
                }
    
                return msgLst.ToArray();
            }
    
            private Message ResultToMessage(BasicGetResult rs)
            {
                var msg = new Message();
                if (rs != null)
                {
                    var body = rs.Body;
                    msg.Value = Encoding.UTF8.GetString(body);
                    msg.ContentType = rs.BasicProperties.ContentType;
                    msg.Headers = rs.BasicProperties.Headers;
                }
    
                return msg;
            }
        }
    }
    View Code

    4、RabbitMqListener.cs

    using RabbitMQ.Client;
    using RabbitMQ.Client.Events;
    using System;
    using System.Collections.Generic;
    using System.IO;
    using System.Linq;
    using System.Text;
    using System.Threading;
    using System.Threading.Tasks;
    using RabbitMQ.Client.Exceptions;
    using XFC.Log;
    using XFC.RabbitMQ.Domain;
    
    namespace XFC.RabbitMQ
    {
        /// <summary>
        /// RabbitMq消息监听器
        /// </summary>
        public class RabbitMqListener : IDisposable
        {
            private ConnectionFactory _factory;
            private IConnection _con;
            private IModel _channel;
            private EventingBasicConsumer _consumer;
            private readonly string _rabbitMqUri;
            private readonly string _queueName;
            private Func<Message, bool> _messageHandler;
    
            /// <summary>
            /// 释放标记
            /// </summary>
            private bool disposed;
    
            ~RabbitMqListener()
            {
                Dispose(false);
            }
    
            /// <summary>
            /// RabbitMQ消息监听器
            /// </summary>
            /// <param name="rabbitMqUri">连接串,如 amqp://guest:guest@localhost:5672/</param>
            /// <param name="queueName">要监听的队列</param>
            public RabbitMqListener(string rabbitMqUri, string queueName)
            {
                this._rabbitMqUri = rabbitMqUri;
                this._queueName = queueName;
            }
    
            /// <summary>
            /// 创建连接
            /// </summary>
            private void CreateConnection()
            {
                _factory = new ConnectionFactory
                {
                    Uri = new Uri(_rabbitMqUri),
                    RequestedHeartbeat = 20,//与服务器协商使用的心跳超时间隔(以秒为单位)。
                    AutomaticRecoveryEnabled = true,//开启网络异常重连机制
                    NetworkRecoveryInterval = TimeSpan.FromSeconds(10),//设置每10s重连一次网络
                    TopologyRecoveryEnabled = true //开启重连后恢复拓扑(交换,队列,绑定等等)。
                };
    
                _con = _factory.CreateConnection();
                _con.ConnectionShutdown += (sender, e) => ReMessageListen();//掉线重新连接并监听队列消息
            }
    
            /// <summary>
            /// 创建信道
            /// </summary>
            private void CreateChannel()
            {
                _channel = _con.CreateModel();
                _channel.BasicQos(0, 3, true); //在非自动确认消息的前提下,如果一定数目的消息(通过基于consume或者channel设置Qos的值)未被确认前,不进行消费新的消息
            }
    
            private Message ResultToMessage(BasicDeliverEventArgs rs)
            {
                var msg = new Message();
                if (rs != null)
                {
                    var body = rs.Body;
                    msg.Value = Encoding.UTF8.GetString(body);
                    msg.ContentType = rs.BasicProperties.ContentType;
                    msg.Headers = rs.BasicProperties.Headers;
                }
    
                return msg;
            }
    
            /// <summary>
            /// 监听队列消息
            /// </summary>
            /// <param name="messageHandler">消息处理器,当监测到队列消息时回调该处理器</param>
            /// <returns>监听状态</returns>
            public bool MessageListen(Func<Message, bool> messageHandler)
            {
                try
                {
                    this.CreateConnection();
                    this.CreateChannel();
    
                    _consumer = new EventingBasicConsumer(_channel); //基于事件的消息推送方式
                    _consumer.Received += (sender, e) =>
                    {
                        var message = this.ResultToMessage(e);
                        if (messageHandler != null)
                        {
                            this._messageHandler = messageHandler;
                            try
                            {
                                var isOk = this._messageHandler(message);
                                if (isOk)
                                {
                                    _channel.BasicAck(e.DeliveryTag, false);
                                }
                            }
                            catch (Exception ex)
                            {
                                LoggerManager.ErrorLog.Error("消息处理器执行异常:" + ex.Message, ex);
                            } 
                        }
                    };
    
                    _channel.BasicConsume(_queueName, false, _consumer); //手动确认
                    return true;
                }
                catch (Exception ex)
                {
                    LoggerManager.ErrorLog.Error("尝试监听队列消息出现错误:" + ex.Message, ex);
                }
                return false;
            }
    
            private void ReMessageListen()
            {
                try
                {
                    //清除连接及频道
                    CleanupResource();
    
                    var mres = new ManualResetEventSlim(false); //初始化状态为false
                    while (!mres.Wait(3000)) //每3秒监测一次状态,直到状态为true
                    {
                        if (MessageListen(_messageHandler))
                        {
                            mres.Set(); //设置状态为true并跳出循环
                        }
                    }
                }
                catch (Exception ex)
                {
                    LoggerManager.ErrorLog.Error("尝试连接RabbitMQ服务器出现错误:" + ex.Message, ex);
                }
            }
    
            /// <summary>
            /// 清理资源
            /// </summary>
            private void CleanupResource()
            {
                if (_channel != null && _channel.IsOpen)
                {
                    try
                    {
                        _channel.Close();
                    }
                    catch (Exception ex)
                    {
                        LoggerManager.ErrorLog.Error("尝试关闭RabbitMQ信道遇到错误", ex);
                    }
                    _channel = null;
                }
    
                if (_con != null && _con.IsOpen)
                {
                    try
                    {
                        _con.Close();
                    }
                    catch (Exception ex)
                    {
                        LoggerManager.ErrorLog.Error("尝试关闭RabbitMQ连接遇到错误", ex);
                    }
                    _con = null;
                }
            }
    
            protected virtual void Dispose(bool disposing)
            {
                if (disposed)
                {
                    return;
                }
                CleanupResource();
                disposed = true;
            }
    
            public void Dispose()
            {
                Dispose(true);
                GC.SuppressFinalize(this);
            }
        }
    }
    View Code

    5、RabbitMqDelayPublisher

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    using RabbitMQ.Client;
    using XFC.Exceptions;
    using XFC.RabbitMQ.Domain;
    
    namespace XFC.RabbitMQ
    {
        public class RabbitMqDelayPublisher
        {
            private readonly string _rabbitMqUri;
            private readonly string _dlxExchangeName;
            private readonly string _dlxQueueName;
            private readonly string _dlxRouteKey;
    
            /// <summary>
            /// 构造函数
            /// </summary>
            /// <param name="rabbitMqUri">连接串,如 amqp://guest:guest@localhost:5672/</param>
            public RabbitMqDelayPublisher(string rabbitMqUri)
            {
                this._rabbitMqUri = rabbitMqUri;
            }
    
            /// <summary>
            /// 构造函数
            /// </summary>
            /// <param name="rabbitMqUri">连接串,如 amqp://guest:guest@localhost:5672/</param>
            /// <param name="dlxExchangeName">死信队列交换机名称</param>
            /// <param name="dlxQueueName">死信队列名称</param>
            /// <param name="dlxRouteKey">死信队列消息路由key</param>
            public RabbitMqDelayPublisher(string rabbitMqUri, string dlxExchangeName, string dlxQueueName, string dlxRouteKey)
                : this(rabbitMqUri)
            {
                this._dlxExchangeName = dlxExchangeName;
                this._dlxQueueName = dlxQueueName;
                this._dlxRouteKey = dlxRouteKey;
            }
            /// <summary>
            /// 创建连接
            /// </summary>
            private IConnection CreateConnection()
            {
                var factory = new ConnectionFactory
                {
                    Uri = new Uri(_rabbitMqUri)
                };
    
                return factory.CreateConnection();
            }
    
            /// <summary>
            /// 创建信道
            /// </summary>
            private IModel CreateChannel(IConnection con, string exchangeName, string exchangeType, string queueName, string routeKey, int delayTime)
            {
                if (string.IsNullOrEmpty(queueName))
                {
                    throw new XFCException("queueName不能为空");
                }
    
                var channel = con.CreateModel();
    
                var dlxExchangeName = string.IsNullOrEmpty(this._dlxExchangeName) ? string.Format("dlx_{0}", exchangeName) : this._dlxExchangeName;
                var dlxQueueName = string.IsNullOrEmpty(this._dlxQueueName) ? string.Format("dlx_{0}", queueName) : this._dlxQueueName;
                var dlxRouteKey = string.IsNullOrEmpty(this._dlxRouteKey) ? (string.IsNullOrEmpty(routeKey) ? Guid.NewGuid().ToString().Replace("-", "") : string.Format("dlx_{0}", routeKey)) : this._dlxRouteKey;
    
                channel.ExchangeDeclare(dlxExchangeName, ExchangeType.Direct, true, false, null);
                channel.QueueDeclare(dlxQueueName, true, false, false, null);
                channel.QueueBind(dlxQueueName, dlxExchangeName, dlxRouteKey, null);
    
                var args = new Dictionary<string, object>
                {
                    {"x-message-ttl", delayTime},
                    {"x-dead-letter-exchange", dlxExchangeName},
                    {"x-dead-letter-routing-key", dlxRouteKey}
                };
    
                channel.ExchangeDeclare(exchangeName, exchangeType, true, false, null);
                channel.QueueDeclare(queueName, true, false, false, args);
                channel.QueueBind(queueName, exchangeName, routeKey, null);
    
                channel.BasicQos(0, 1, true);
                return channel;
            }
    
            /// <summary>
            /// 发送ExchangeType类型为Direct的消息
            /// </summary>
            /// <param name="exchangeName">交换机名称</param>
            /// <param name="routeKey">消息路由key</param>
            /// <param name="expireTime">过期时间,单位为秒</param>
            /// <param name="message">消息实体</param>
            /// <param name="queueName">队列名(必填)</param>
            /// <returns></returns>
            public bool PublishDirectMessage(string exchangeName, string queueName, string routeKey, int expireTime, Message message)
            {
                return this.PublishMessage(exchangeName, ExchangeType.Direct, queueName, routeKey, expireTime, new[] { message });
            }
    
            /// <summary>
            /// 批量发送ExchangeType类型为Direct的消息
            /// </summary>
            /// <param name="exchangeName">交换机名称</param>
            /// <param name="routeKey">消息路由key</param>
            /// <param name="expireTime">过期时间,单位为秒</param>
            /// <param name="messages">消息实体</param>
            /// <param name="queueName">队列名(必填)</param>
            /// <returns></returns>
            public bool PublishDirectMessages(string exchangeName, string queueName, string routeKey, int expireTime, IEnumerable<Message> messages)
            {
                return this.PublishMessage(exchangeName, ExchangeType.Direct, queueName, routeKey, expireTime, messages);
            }
    
            /// <summary>
            /// 发送ExchangeType类型为Fanout的消息
            /// </summary>
            /// <param name="exchangeName">交换机名称</param>
            /// <param name="expireTime">过期时间,单位为秒</param>
            /// <param name="message">消息实体</param>
            /// <param name="queueName">队列名(必填)</param>
            /// <returns></returns>
            public bool PublishFanoutMessage(string exchangeName, string queueName, int expireTime, Message message)
            {
                return this.PublishMessage(exchangeName, ExchangeType.Fanout, queueName, "", expireTime, new[] { message });
            }
    
            /// <summary>
            /// 批量发送ExchangeType类型为Fanout的消息
            /// </summary>
            /// <param name="exchangeName">交换机名称</param>
            /// <param name="expireTime">过期时间,单位为秒</param>
            /// <param name="messages">消息实体</param>
            /// <param name="queueName">队列名(必填)</param>
            /// <returns></returns>
            public bool PublishFanoutMessages(string exchangeName, string queueName, int expireTime, IEnumerable<Message> messages)
            {
                return this.PublishMessage(exchangeName, ExchangeType.Fanout, queueName, "", expireTime, messages);
            }
    
            private bool PublishMessage(string exchangeName, string exchangeType, string queueName, string routeKey, int expireTime, IEnumerable<Message> messages)
            {
                using (var con = CreateConnection())
                {
                    using (var channel = CreateChannel(con, exchangeName, exchangeType, queueName, routeKey, expireTime * 1000))
                    {
                        channel.ConfirmSelect();//启用消息发送确认机制
                        foreach (var message in messages)
                        {
                            var body = Encoding.UTF8.GetBytes(message.Value);
                            var properties = channel.CreateBasicProperties();
                            properties.Persistent = true; //使消息持久化
                            properties.Headers = message.Headers;
                            properties.ContentType = string.IsNullOrEmpty(message.ContentType) ? "text/plain" : message.ContentType;
                            channel.BasicPublish(exchangeName, routeKey, properties, body);
                        }
                        var state = channel.WaitForConfirms();
                        return state;
                    }
                }
            }
        }
    }
    View Code

    6、Test

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    using RabbitMQ.Client;
    using XFC.RabbitMQ.Domain;
    
    namespace XFC.RabbitMQ.Test
    {
        class Program
        {
            private const string RabbitHostUri = "amqp://guest:guest@localhost:5672/";
            private const string ExchangeName = "xfc.mq.test";
            private const string QueueName = "xfc.mq.test.queue";
            private const string RouteKey = "xfc.mq.test.key";
    
            static void Main(string[] args)
            {
                var publisher = new XFC.RabbitMQ.RabbitMqPublisher(RabbitHostUri);
                var dic = new Dictionary<string, object>();
                dic.Add("uniquekey", "s34sdf3423234523sdfdsgf");
                dic.Add("callbackurl", "http://wwww.1234.com/callback");
    
                var ms =new List<Message>();
                for (int i = 0; i < 1000; i++)
                {
                    ms.Add(new Message("hello...", dic, "application/json"));
                }
                publisher.PublishDirectMessages(ExchangeName, RouteKey, ms, QueueName);
                Console.WriteLine("is ok");
                Console.ReadKey();
    
                var mqQuery = new XFC.RabbitMQ.RabbitMqQuery(RabbitHostUri);
                var ss = mqQuery.GetMessages(QueueName, 1000);
                foreach (var s in ss)
                {
                    Console.WriteLine(s.Value);
                    Console.WriteLine(s.ContentType);
                    foreach (var header in s.Headers)
                    {
                        Console.WriteLine(header.Key + ":" + Encoding.UTF8.GetString((Byte[])header.Value));
                    }
    
                }
    
                Console.ReadKey();
    
                using (var mqListener = new XFC.RabbitMQ.RabbitMqListener(RabbitHostUri, QueueName))
                {
                    mqListener.MessageListen(msg =>
                    {
                        Console.WriteLine(msg.Value);
                        return true;
                    });
    
                    Console.WriteLine("按任意键退出程序...");
                    Console.ReadKey();
                }
            }
        }
    }
    View Code
     
  • 相关阅读:
    侯策《前端开发核心知识进阶》读书笔记——JS基础
    侯策《前端开发核心知识进阶》读书笔记——API实现
    侯策《前端开发核心知识进阶》读书笔记——Javascript中的Closure
    侯策《前端开发核心知识进阶》读书笔记——Javascript中的this
    xss攻击和csrf攻击的定义及区别
    浏览器缓存类型
    函数截流和防抖
    阮一峰《ECMAScript 6 入门》读书笔记—— Generator 函数
    阮一峰《ECMAScript 6 入门》读书笔记—— Iterator
    阮一峰《ECMAScript 6 入门》读书笔记——Promise
  • 原文地址:https://www.cnblogs.com/huangzelin/p/11202627.html
Copyright © 2011-2022 走看看