隊列工廠之(MSMQ)
最近vs2017神器正式版發布讓人很是激動,vs2017支持了很多語言的開發,從前端-後端-底層的支持,堪稱是工具中的神器;netcore我喜愛的架構之一也得到了大力的宣傳,應群友的邀請將在隊列工廠(msmq,redis,rabbitmq)一些列文章過後,繼續增加.netcore方面的文章,只為.netcore發展更好貢獻一份微弱的力量;本章內容分享的是隊列(msmq,redis,rabbitmq)封裝的隊列工廠之MSMQ希望大家能夠喜歡,也希望各位多多"掃碼支持"和"推薦"謝謝!
創建隊列工廠QueueReposity<T>
. 隊列公共操作接口IQueue
. 配置文件操作類ConfClass<T>
. 非安全單例創建隊列實例
Win7和Server2008安裝MSMQ支持
MSMQ測試用例(服務端+客戶端)
下面一步一個腳印的來分享:
創建隊列工廠QueueReposity<T>
首先,因為這裏需要統一封裝幾個常用的隊列方式的用法,因此采用了簡單工廠模式,所以有了QueueReposity<T>;
. 隊列公共操作接口IQueue
工廠模式的特性創建實例,因為這裏封裝的都是隊列,故而能提取出統一的規則來,因此定義了如下接口(這裏沒有考慮一些隊列兼容的異步方法請忽略):
/// <summary> /// 隊列公共操作 /// </summary> public interface IQueue : IDisposable { /// <summary> /// 創建隊列 /// </summary> void Create(); /// <summary> /// 總數 /// </summary> /// <returns></returns> int Total(); /// <summary> /// 讀取一個隊列 /// </summary> /// <returns></returns> Message Read(); ///// <summary> ///// 讀取多個隊列 ///// </summary> ///// <returns></returns> //List<Message> ReadAll(); /// <summary> /// 寫入隊列 /// </summary> /// <returns></returns> bool Write(string content, string name = ""); }
. 配置文件操作類ConfClass<T>
因為每個隊列的都有自己的配置信息,因此封裝了統一管理的配置文件讀取類ConfClass<T>,來讀取配置在同一個xml文件中的配置信息,如下封裝了自定義配置文件的屬性和讀取方法:
#region 文件操作類 /// <summary> /// 配置文件操作類 /// </summary> /// <typeparam name="T"></typeparam> public class ConfClass<T> where T : class,new() { public ConfClass() { var apiNodeName = this.GetType().Name; Reader(apiNodeName); } #region 單例模式 public static readonly object Singleton_Lock = new object(); /// <summary> /// 單例對象 /// </summary> private static T t = default(T); /// <summary> /// 通過方法獲取單例 /// </summary> /// <param name="t"></param> /// <returns></returns> public static T GetInstance(T t) { t = t ?? new T(); return t; } /// <summary> /// 通過屬性獲取單例(在繼承的時候使用) /// </summary> public static T Current { get { t = t ?? new T(); return t; } } #endregion #region 配置文件操作 #region 配置文件屬性 /// <summary> /// 配置文件地址 /// </summary> //public string ConfPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Conf", "ShenNiuApi.xml"); public string ConfPath = @"C:\Conf\ShenNiuApi.xml"; /// <summary> /// 配置文件父節點名稱 /// </summary> public string ConfParentNodeName = "ShenNiuApi"; /// <summary> /// 配置文件內容 /// </summary> public string ConfContent { get; set; } /// <summary> /// 配置文件文檔doc對象 /// </summary> public XmlDocument doc { get; set; } /// <summary> /// 賬號 /// </summary> public string UserName { get; set; } /// <summary> /// 密碼 /// </summary> public string UserPwd { get; set; } /// <summary> /// 接口地址 /// </summary> public string ApiUrl { get; set; } /// <summary> /// 秘鑰 /// </summary> public string ApiKey { get; set; } #endregion public ConfClass(string ConfPath, string ConfParentNodeName="") { this.ConfPath = string.IsNullOrWhiteSpace(ConfPath) ? this.ConfPath : ConfPath; this.ConfParentNodeName = string.IsNullOrWhiteSpace(ConfParentNodeName) ? this.ConfParentNodeName : ConfParentNodeName; var apiNodeName = this.GetType().Name; Reader(apiNodeName); } /// <summary> /// 讀取配置信息 /// </summary> /// <param name="apiNodeName"></param> public void Reader(string apiNodeName) { try { if (string.IsNullOrWhiteSpace(ConfPath) || string.IsNullOrWhiteSpace(ConfParentNodeName)) { throw new Exception("配置文件地址或者配置文件父節點名稱不能為空"); } if (!File.Exists(ConfPath)) { return; } //獲取配置文件信息 using (StreamReader reader = new StreamReader(ConfPath)) { this.ConfContent = reader.ReadToEndAsync().Result; } if (string.IsNullOrWhiteSpace(this.ConfContent)) { return; } //加入doc中 this.doc = new XmlDocument(); this.doc.LoadXml(this.ConfContent); //解析 var parentNode = string.Format("{0}/{1}", this.ConfParentNodeName, apiNodeName); var apiNode = this.doc.SelectSingleNode(parentNode); if (apiNode == null) { throw new Exception("未能找到" + parentNode + "節點"); } this.UserName = apiNode.SelectSingleNode("UserName").InnerText; this.UserPwd = apiNode.SelectSingleNode("UserPwd").InnerText; this.ApiUrl = apiNode.SelectSingleNode("ApiUrl").InnerText; this.ApiKey = apiNode.SelectSingleNode("ApiKey").InnerText; } catch (Exception ex) { throw new Exception("加載配置文件" + this.ConfPath + "異常:" + ex.Message); } } #endregion } #endregion
這個配置文件的類主要運用在隊列實例繼承上,只要繼承了默認就會讀取響應的配置節點信息;配置xml文件默認存儲的地址: C:\Conf\ShenNiuApi.xml ,最大父節點名稱默認:ShenNiuApi,格式如下所示:
<ShenNiuApi> <QMsmq> <UserName></UserName> <UserPwd></UserPwd> <ApiUrl>.\Private$\MyMsmq</ApiUrl> <ApiKey></ApiKey> </QMsmq> </ShenNiuApi>
. 非安全單例創建隊列實例
由於工廠都是專門用來提供實例的存在,創建實例的模式也有很多這種,這裏我選擇的是非安全單例創建隊列實例,所有在ConfClass類中默認加入了單例模式:
#region 單例模式 public static readonly object Singleton_Lock = new object(); /// <summary> /// 單例對象 /// </summary> private static T t = default(T); /// <summary> /// 通過方法獲取單例 /// </summary> /// <param name="t"></param> /// <returns></returns> public static T GetInstance(T t) { t = t ?? new T(); return t; } /// <summary> /// 通過屬性獲取單例(在繼承的時候使用) /// </summary> public static T Current { get { t = t ?? new T(); return t; } } #endregion
因此這裏所說的工廠模式通過泛型傳遞類型,再創建實例的具體代碼只有這麽點,簡短精煉:
/// <summary> /// 隊列工廠 /// </summary> public class QueueReposity<T> where T : class,IQueue, new() { public static IQueue Current { get { return PublicClass.ConfClass<T>.Current; } } }
Win7和Server2008安裝MSMQ支持
上面分享的是隊列工廠的結構,到這裏就要開始我們的第一個MSMQ隊列的安裝和封裝分享了;首先來看Win7測試環境上怎麽安裝MSMQ的支持:開始菜單-》控制面板-》程序和功能:
-》打開或關閉Windows功能-》勾選如圖所示隊列安裝組件:
-》確定等待安裝完成;到此win7安裝msmq就完成了,因為msmq是系統默認的所以安裝起來很方便,當然server2008也差不多,按照如下操作安裝(這裏我使用租的阿裏雲Server2008R2服務器為例):開始-》控制面板-》程序(下面的打開或關閉Window功能)->功能-》添加功能-》消息隊列:
在server上安裝的步驟基本沒啥變化,是不是很簡單;安裝完成後這樣你的電腦或服務器就支持msmq了,此刻的你是不是很興奮,覺得又能學到新東西了呵呵;
MSMQ測試用例(服務端+客戶端)
首先,這裏我用控制臺程序做測試用例,我分為客戶端和服務端,用服務端通過分裝的插入隊列方法插入數據,然後通過客戶端讀取隊列信息,先來上個圖撐撐場面吧:
這裏我創建了MSMQ的分裝類 public class QMsmq : PublicClass.ConfClass<QMsmq>, IQueue 實現了隊列接口IQueue和繼承配置文件類ConfClass<QMsmq>,此時具體的方法體如下:
public class QMsmq : PublicClass.ConfClass<QMsmq>, IQueue { private MessageQueue _msmq = null; public void Create() { if (string.IsNullOrWhiteSpace(this.ApiUrl)) { throw new Exception("創建隊列需要指定隊列:地址"); } _msmq = MessageQueue.Exists(this.ApiUrl) ? new MessageQueue(this.ApiUrl) : _msmq ?? MessageQueue.Create(this.ApiUrl); //設置數據格式 _msmq.Formatter = new XmlMessageFormatter(new Type[] { typeof(string) }); } public int Total() { if (_msmq == null) { throw new Exception("請先創建隊列"); } return _msmq.GetAllMessages().Length; } public Message Read() { try { if (_msmq == null) { throw new Exception("請先創建隊列"); } //60s超時 return _msmq.Receive(TimeSpan.FromSeconds(60)); } catch (Exception ex) { throw new Exception(ex.Message); } } //public List<Message> ReadAll() //{ // try // { // if (_msmq == null) { throw new Exception("請先創建隊列"); } // var messages = _msmq.GetAllMessages(); // return messages.ToList(); // } // catch (Exception ex) // { // throw new Exception(ex.Message); // } //} public bool Write(string content, string name = "") { try { if (_msmq == null) { throw new Exception("請先創建隊列"); } if (string.IsNullOrWhiteSpace(content)) { throw new Exception("填充內容不能為空"); } var message = new Message(); message.Body = content; message.Label = name; _msmq.Send(message); return true; } catch (Exception ex) { throw new Exception(ex.Message); } } public void Dispose() { if (_msmq != null) { _msmq.Close(); _msmq.Dispose(); _msmq = null; } } }
到這裏我們的MSMQ簡單封裝代碼已經完成了,咋們再來通過控制臺調用下這個隊列客戶端代碼:
class Program { static void Main(string[] args) { Client(); } /// <summary> /// 客戶端 /// </summary> private static void Client() { //實例化QMsmq對象 var msmq = QueueReposity<QMsmq>.Current; try { Console.WriteLine("創建:msmq"); msmq.Create(); while (true) { try { var result = msmq.Read(); Console.WriteLine(string.Format("接受第{0}個:{1}", result.Label, result.Body)); } catch (Exception ex) { Console.WriteLine("異常信息:" + ex.Message); } } } catch (Exception ex) { throw ex; } finally { Console.WriteLine("釋放。"); msmq.Dispose(); } } }
這裏能夠看出客戶端代碼中使用MSMQ步驟主要有:QueueReposity<QMsmq>.Current工廠創建自定義隊列實例-》Create()創建-》Read()讀取-》Dispose()釋放mq,流程還算清晰吧;如下服務端代碼:
class Program { static void Main(string[] args) { Server(); } /// <summary> /// 服務端 /// </summary> private static void Server() { //實例化QMsmq對象 var msmq = QueueReposity<QMsmq>.Current; try { Console.WriteLine("創建:msmq"); msmq.Create(); var num = 0; do { Console.WriteLine("輸入循環數量(數字,0表示結束):"); var readStr = Console.ReadLine(); num = string.IsNullOrWhiteSpace(readStr) ? 0 : Convert.ToInt32(readStr); Console.WriteLine("插入數據:"); for (int i = 0; i < num; i++) { var str = "我的編號是:" + i; msmq.Write(str, i.ToString()); Console.WriteLine(str); } } while (num > 0); } catch (Exception ex) { } finally { Console.WriteLine("釋放。"); msmq.Dispose(); } Console.ReadLine(); } }
服務端的步驟幾乎和客戶端差不多,區別在於一個讀取一個寫入,服務端步驟:QueueReposity<QMsmq>.Current工廠創建自定義隊列實例-》Create()創建-》Write()寫入-》Dispose()釋放mq;以上對MSMQ的代碼分享和環境搭建講解,希望能給您帶來好的幫助,謝謝閱讀;
本文出自 “神牛步行3博客” 博客,請務必保留此出處http://shenniu003.blog.51cto.com/3316359/1923484
隊列工廠之(MSMQ)