【C#】【筆記】- 消息隊列RabbitMQ demo

 

1、實現發送和接收,類RabbitMQServerT

注意:

鏈接隊列服務器時,參數必須和服務器配置一致

  private string queue;//隊列名
        private bool durable;//持久化
        private bool exclusive;//獨佔
        private bool autoDelete;//自動刪除

默認帳號guest不能遠程。

默認訪問隊列端口是5672,後臺網站端口默認是15672。

using System;
using System.ServiceProcess;
using MQServer.Log;
using RabbitMQ.Client;
using System.Text;
using System.Configuration;
using RabbitMQ.Client.Events;

namespace MQServer
{
    /// <summary>
    /// RabbitMQ消息隊列類
    /// </summary>
    public class RabbitMQServerT 
    {
        protected readonly Action<string, object> receive;//接收回調
        private object penetrate;//接收回調透傳參數
        private string queue;//隊列名
        private bool durable;//持久化
        private bool exclusive;//獨佔
        private bool autoDelete;//自動刪除
        private bool isBeginInvoke;//接收後業務是否異步,異步的話消息可能在確認前被其他線程讀走,造成重複讀。//不異步就阻塞。//異步請獨佔

        //接收消息對象
        private IConnection connection;
        private IModel channel;

        public bool IsReceive;

        private ConnectionFactory factory;
        private RabbitMQServerT()
        {
        }

        /// <summary>
        /// 使用默認配置參數
        /// </summary>
        /// <param name="_receive">消費事件,空則不消費</param>
        /// <param name="_queue">消息路徑最後一層名字,可用於區分業務</param>
        /// <param name="_penetrate">接收回調透傳參數</param>
        public RabbitMQServerT(Action<string, object> _receive, string _queue = @"hello", object _penetrate = null)
        {
            queue = _queue;
            receive = _receive;
            penetrate = _penetrate;
            isBeginInvoke = false;

            durable = bool.Parse(ConfigurationManager.AppSettings["RabbitMQ_durable"].ToString());//
            exclusive = bool.Parse(ConfigurationManager.AppSettings["RabbitMQ_exclusive"].ToString());//
            autoDelete = bool.Parse(ConfigurationManager.AppSettings["RabbitMQ_autoDelete"].ToString());//

            factory = new ConnectionFactory();
            factory.HostName = ConfigurationManager.AppSettings["RabbitMQHostName"];//RabbitMQ服務器
            factory.UserName = ConfigurationManager.AppSettings["RabbitMQUserName"];//用戶名
            factory.Password = ConfigurationManager.AppSettings["RabbitMQPassword"];//密碼
            factory.Port = int.Parse(ConfigurationManager.AppSettings["RabbitMQPort"].ToString());//
            if (!string.IsNullOrWhiteSpace(ConfigurationManager.AppSettings["RabbitMQVirtualHost"]))
            {
                factory.VirtualHost = ConfigurationManager.AppSettings["RabbitMQVirtualHost"];//
            }
        }

        /// <summary>
        /// 使用手動參數
        /// </summary>
        /// <param name="_receive">消費事件,空則不消費</param>
        /// <param name="_queue">消息路徑最後一層名字,可用於區分業務</param>
        /// <param name="_penetrate">接收回調透傳參數</param>
        /// <param name="factory">連接隊列服務器</param>
        /// <param name="durable">持久化</param>
        /// <param name="exclusive">獨佔</param>
        /// <param name="autoDelete">自動刪除</param>
        /// <param name="isBeginInvoke">接收是否異步//異步請獨佔,否則異常</param>
        public RabbitMQServerT(Action<string, object> _receive, string _queue, object _penetrate, ConnectionFactory factory
            ,bool durable,bool exclusive, bool autoDelete,bool isBeginInvoke)
        {
            queue = _queue;
            receive = _receive;
            penetrate = _penetrate;

            this.factory = factory;
            this.durable = durable;
            this.exclusive = exclusive;
            this.autoDelete = autoDelete;
            this.isBeginInvoke = isBeginInvoke;

            //異步請獨佔,不然會重複讀
            if (isBeginInvoke == true && exclusive == false) 
            {
                throw new Exception("接收消息隊列對象RabbitMQServerT參數isBeginInvoke=true異步執行接收業務,如果要異步執行業務,請獨佔該消息exclusive=true,否則會被其他線程重複讀取。");
            }
        }

        /// <summary>
        /// 發送消息
        /// </summary>
        /// <param name="message"></param>
        public void Send(string message)
        {
            //發送消息隊列
            try
            {
                using (var connection = factory.CreateConnection())
                {
                    using (var channel = connection.CreateModel())
                    {
                        channel.QueueDeclare(queue, durable, exclusive, autoDelete, null);//創建一個消息隊列
                        var body = Encoding.UTF8.GetBytes(message);
                        channel.BasicPublish("", queue, null, body); //開始傳遞

                        TLogHelper.Info(message, "RabbitMQServerTSend");//發送的內容寫進TXT
                    }
                }
            }
            catch (Exception ex)
            {
                TLogHelper.Error(ex.Message, "發送消息隊列異常RabbitMQServerTSend:\n" + message);
            }
        }

        /// <summary>
        /// 進行接收消息隊列
        /// </summary>
        public void Receive()
        {
            if (receive == null)
            {
                return;
            }
            IsReceive = true;
            try
            {
                connection = factory.CreateConnection();
                channel = connection.CreateModel();
              
                channel.QueueDeclare(queue, durable, exclusive, autoDelete, null);
                channel.BasicQos(prefetchSize: 0, prefetchCount: 1, global: false);

                var consumer = new EventingBasicConsumer(channel);
                consumer.Received += (model, ea) =>
                {
                    try
                    {
                        var body = ea.Body.ToArray();
                        var message = Encoding.UTF8.GetString(body);

                        //接收後業務
                        if (isBeginInvoke)
                        {
                            receive?.BeginInvoke(message, penetrate,(e)=>{
                                //確認消息
                                channel.BasicAck(ea.DeliveryTag, false);
                            },null);
                        }
                        else 
                        {
                            receive?.Invoke(message, penetrate);
                            //確認消息
                            channel.BasicAck(ea.DeliveryTag, false);
                        }
                    }
                    catch (Exception ex)
                    {
                        TLogHelper.Error(ex.Message, "接收消息隊列業務異常Received:"+queue);
                    }
                    finally
                    {
                        //再次生成接收
                        Receive();
                    }
                };
                channel.BasicConsume(queue, true, consumer);
            }
            catch (Exception ex)
            {
                TLogHelper.Error(ex.Message, "接收消息隊列異常Receive");
            }
        }

        /// <summary>
        /// 取消接收
        /// </summary>
        public void EndReceive()
        {
            IsReceive=false;
            channel.Dispose();
            connection.Dispose();
        }
    }
}
View Code

 

2、BLL實現消息業務

BaseMQBLL

using MQServer;
using System;

namespace BLL
{
    /// <summary>
    /// 使用隊列業務基類
    /// </summary>
    public abstract class BaseMQBLL
    {
        public readonly RabbitMQServerT MQ;

        private BaseMQBLL(){ }

        public BaseMQBLL(string queue,object _penetrate) 
        {
            MQ = new MQServer.RabbitMQServerT((string source, object o) => {
                try
                {
                    ReceiveBack(source, _penetrate);
                    ////test
                    //throw new Exception("測試消息異常");
                }
                catch (Exception)
                {
                    throw;
                }
            }, queue, _penetrate: null);
        }

        public abstract void ReceiveBack(string source, object receiveO);
    }
}
View Code

 

TestHello : BaseMQBLL

using MQServer.Log;

namespace BLL
{
    public class TestHello : BaseMQBLL
    {
        public TestHello()
            :base("hello",null)
        {
            ////默認開啓接收
            //MQ.Receive();
        }

        public override void ReceiveBack(string source, object receiveO)
        {
            TLogHelper.Info(source, "讀取消息在rabbitmain");
        }
    }
}
View Code

 

3、記錄日誌

TLogHelper

using Newtonsoft.Json;
using System;
using System.IO;
using System.Messaging;
using System.Text;

namespace MQServer.Log
{
    public class TLogHelper
    {
        public static object _lock = new object();
        public static void MQ(Message myMessage,  string detail = "") 
        {
            string msg = JsonConvert.SerializeObject(myMessage.Body);

            Write(msg, detail, "MessageQueue");
        }

        public static void Info(string msg, string detail = "")
        {
            Write(msg, detail, "Info");
        }
        public static void Info(object msg, string detail = "")
        {
            Write(JsonConvert.SerializeObject(msg), detail, "Info");
        }

        public static void Error(string msg, string detail = "")
        {
            Write(msg, detail, "Error");
        }

        private static void Write(string msg,string detail="", string title = "Info") 
        {
            DateTime now = DateTime.Now;
            string logPath = System.Configuration.ConfigurationManager.AppSettings["MQServerTLogPath"];

            if (!Directory.Exists(logPath))
            {
                Directory.CreateDirectory(logPath);
            }

            logPath += now.ToString("yyyyMMdd") + ".txt";
            lock (_lock)
            {
                FileStream fs = new FileStream(@logPath, FileMode.OpenOrCreate, FileAccess.Write);

                StreamWriter m_streamWriter = new StreamWriter(fs);

                m_streamWriter.BaseStream.Seek(0, SeekOrigin.End);

                m_streamWriter.WriteLine();
                m_streamWriter.WriteLine(now.ToString("yyyyMMddHHmmssfff") + " " + title);
                if (!string.IsNullOrWhiteSpace(detail))
                {
                    m_streamWriter.WriteLine(detail);
                }

                m_streamWriter.WriteLine(msg);

                m_streamWriter.Flush();

                m_streamWriter.Close();

                fs.Close();
            }
            

        }

        public static string Read() 
        {
            string res = "";
            string logPath = System.Configuration.ConfigurationManager.AppSettings["MQServerTLogPath"];
            
            logPath += DateTime.Now.ToString("yyyyMMdd") + ".txt";
            lock (_lock)
            {
                StreamReader fs = new StreamReader(@logPath, Encoding.UTF8);
                res = fs.ReadToEnd();
                fs.Dispose();
            }
            return res;
        }
    }
}
View Code

 

4、Form窗體測試

 RabbitMQForm : Form

using BLL;
using System;
using System.Windows.Forms;

namespace WinFormActiveMQ
{
    public partial class RabbitMQForm : Form
    {
        private Label la_main;
        private Timer tim;
        public RabbitMQForm()
        {
            InitializeComponent();

            la_main = new Label();
            la_main.Name = "la_main";
            la_main.Width = 282;
            la_main.TabIndex = 0;
            Controls.Add(la_main);

            tim = new Timer();
            tim.Interval = 1000;
            tim.Tick += CheckReceive;
            tim.Start();

        }

        private void Form1_Load(object sender, EventArgs e)
        {
            la_main.Text = "RabbitMQ消息隊列,點擊開啓接收。";
        }

        /// <summary>
        /// 檢測接收線程是否還在,不在了重新接收
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void CheckReceive(object sender, EventArgs e)
        {
            //測試Hello隊列
            if (TestHello.Checked) 
            {
                if (hello == null)
                {
                    hello = new TestHello();
                }
                if (!hello.MQ.IsReceive) 
                {
                    hello.MQ.Receive();
                }
            }
        }

        //測試Hello隊列
        static TestHello hello;
        private void TestHello_CheckedChanged(object sender, EventArgs e)
        {
            if (TestHello.Checked)
            {
                hello = new TestHello();
                hello.MQ.Receive();
                hello.MQ.Send("測試第一消息");
            }
            else 
            {
                hello.MQ.EndReceive();
                hello = null;
            }
        }
    }
}
View Code

 

RabbitMQForm

namespace WinFormActiveMQ
{
    partial class RabbitMQForm
    {
        /// <summary>
        /// Required designer variable.
        /// </summary>
        private System.ComponentModel.IContainer components = null;

        /// <summary>
        /// Clean up any resources being used.
        /// </summary>
        /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
        protected override void Dispose(bool disposing)
        {
            if (disposing && (components != null))
            {
                components.Dispose();
            }
            base.Dispose(disposing);
        }

        #region Windows Form Designer generated code

        /// <summary>
        /// Required method for Designer support - do not modify
        /// the contents of this method with the code editor.
        /// </summary>
        private void InitializeComponent()
        {
            this.TestHello = new System.Windows.Forms.CheckBox();
            this.SuspendLayout();
            // 
            // TestHello
            // 
            this.TestHello.AutoSize = true;
            this.TestHello.Location = new System.Drawing.Point(13, 46);
            this.TestHello.Name = "TestHello";
            this.TestHello.Size = new System.Drawing.Size(101, 19);
            this.TestHello.TabIndex = 0;
            this.TestHello.Text = "TestHello";
            this.TestHello.UseVisualStyleBackColor = true;
            this.TestHello.CheckedChanged += new System.EventHandler(this.TestHello_CheckedChanged);
            // 
            // RabbitMQForm
            // 
            this.ClientSize = new System.Drawing.Size(282, 253);
            this.Controls.Add(this.TestHello);
            this.Name = "RabbitMQForm";
            this.Text = "RabbitMQForm";
            this.Load += new System.EventHandler(this.Form1_Load);
            this.ResumeLayout(false);
            this.PerformLayout();

        }

        #endregion

        private System.Windows.Forms.CheckBox TestHello;
    }
}
View Code

 

5、默認配置

  <appSettings>
    <add key="MQServerTLogPath" value="d:/WinFormActiveMQLog/" />
    <add key="RabbitMQHostName" value="192.168.0.233" />
    <add key="RabbitMQUserName" value="admin" />
    <add key="RabbitMQPassword" value="123456" />
    <add key="RabbitMQPort" value="5672" />
    <add key="RabbitMQVirtualHost" value="" />
    <add key="RabbitMQ_durable" value="true" />
    <add key="RabbitMQ_exclusive" value="false" />
    <add key="RabbitMQ_autoDelete" value="false" />
  </appSettings>

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章