一直都在用Msmqbinding,也一直忽視了message裡面的內容格式是什麼樣的,這也是微軟給我們高層封裝帶給我們的開發效率,但同時一旦中間出了什麼問題,
就不知道從何查起了。有個需求是這樣的,服務端和客戶端採用離線連線,也就是訊息佇列模式,server接收端在處理訊息的時候,要根據一定的邏輯,如果該訊息不
滿足規則,就把訊息原樣的丟回訊息佇列中,問題就出現在這裡。。。訊息丟進去了,然後,然後就tmd的飛走了!!!先快速的看下程式碼。
一:示例程式碼
1.server端
1 public void Run(Test test) 2 { 3 if (test.str.Length % 10 == 0) 4 { 5 //重新丟回訊息佇列 6 MessageQueue mq = new MessageQueue(@".\private$\myqueue"); 7 Message msg = new Message(); 8 msg.Body = test; 9 msg.Formatter = new XmlMessageFormatter(new Type[] { test.GetType() }); 10 11 mq.Send(msg); 12 //Environment.Exit(0); 13 14 System.Console.WriteLine("已經成功丟回! ,當前執行緒:" + Thread.CurrentThread.ManagedThreadId); 15 } 16 else 17 { 18 System.Console.WriteLine("已經消費客戶端訊息!"); 19 } 20 }
2.服務程式碼
1 public void Run(Test test) 2 { 3 if (test.str.Length % 10 == 0) 4 { 5 //重新丟回訊息佇列 6 MessageQueue mq = new MessageQueue(@".\private$\myqueue"); 7 Message msg = new Message(); 8 msg.Body = test; 9 msg.Formatter = new XmlMessageFormatter(new Type[] { test.GetType() }); 10 11 mq.Send(msg); 12 //Environment.Exit(0); 13 14 System.Console.WriteLine("已經成功丟回! ,當前執行緒:" + Thread.CurrentThread.ManagedThreadId); 15 } 16 else 17 { 18 System.Console.WriteLine("已經消費客戶端訊息!"); 19 } 20 }
3.client端
1 static void Main(string[] args) 2 { 3 var msmq = new NetMsmqBinding(NetMsmqSecurityMode.None); 4 5 msmq.ExactlyOnce = false; 6 7 ChannelFactory<IHomeService> factory = new ChannelFactory<IHomeService>(msmq, 8 "net.msmq://localhost/private/myqueue"); 9 10 var client = factory.CreateChannel(); 11 12 for (int i = 0; i < int.MaxValue; i++) 13 { 14 var t = new Test() { str = "1111111111" }; 15 16 client.Run(t); 17 Console.WriteLine("呼叫第 " + i + " 次"); 18 } 19 20 var s = 10; 21 }
當時寫的急,也沒關注能不能用MessageQueue將訊息丟回訊息佇列中,然後讓WCF的MsmqBinding去讀取,結果上面的奇葩問題就來了,反正佇列中的資料
一直在減少,但是server端就是沒進來,tmd的wcf卻一個錯誤都不丟擲來,麻蛋。。。為了展示出效果,我特意做成了flash。
從上面的flash中,你可以看到console控制檯已經不在接受訊息了,但是奇怪的是訊息佇列中的資料還是一直在減少。。。。
二:懷疑
從開始在server端將message丟回訊息佇列的時候,我就有一點懷疑,或許這兩種message的內容格式不一樣,wcf在接受的時候應該會報錯,但是tmd的
就是沒有給小爺報錯,現在既然問題來了,我就去比較一下,到底兩種message的格式是什麼樣的,然後我就寫了兩份丟訊息佇列的方法。
1 static void Main(string[] args) 2 { 3 //第一種方式: 4 var msmq = new NetMsmqBinding(NetMsmqSecurityMode.None); 5 msmq.ExactlyOnce = false; 6 7 ChannelFactory<IHomeService> factory = new ChannelFactory<IHomeService>(msmq, 8 "net.msmq://localhost/private/myqueue"); 9 var client = factory.CreateChannel(); 10 11 var t = new Test() { str = "1111111111" }; 12 13 client.Run(t); 14 15 16 //第二種方式: 17 MessageQueue mq = new MessageQueue(@".\private$\myqueue"); 18 Message msg = new Message(); 19 msg.Body = t; 20 msg.Formatter = new XmlMessageFormatter(new Type[] { t.GetType() }); 21 22 mq.Send(msg); 23 }
然後我跑去MMC控制檯看一下,果然訊息的大小都不一樣,內容也不一樣。。。真相大白,左邊也不知道是什麼格式,右邊很清楚的看到是xml格式。
如果文章到這裡的話,說明我也就只能看表面現象,因為剛才我已經提出了一個問題,左邊到底是什麼格式???
三:進一步探索
現在我們知道Msmqbinding使用的是自己獨有格式的訊息body,現在是不是有耐心看看wcf這個底層怎麼寫的呢???我通過一系列的除錯跟蹤,
發現MsmqBinding是先建立一個Msmq的通道棧,可以看到這個channel要傳遞的訊息是soap12協議的,不管是什麼樣的,可以確認的是,訊息傳遞
採用的soap訊息的模式。對吧,如下圖:
接下來,這個channel會呼叫wcf自己封裝的訊息佇列MsmqQueue,並且會呼叫其中的send方法,將訊息推送到訊息佇列中,不過要記住,wcf中那
些高層的msmq操作,在底層都是這個類來達到效果的。
好了,探索就到這裡為止了,到現在我們起碼知道以下二點訊息了。
第一: MessageQueue類投送的訊息一般可以指定xml或者binaray,而WCF中的Msmq中的訊息採用的是soap格式。。。這也是為什麼一個內容小,一個大。
第二: WCF中所有的高層訊息操作,都是建立在自己獨有個MsmqQueue之上,包括send,received方法,只是微軟給我們封裝了而已。