[NET] Message Queuing (MSMQ) : Sender/Receiver 範例

1.何時需要使用Message Queuing (MSMQ):
2.使用C#撰寫MSMQ範例注意事項
3.實務應用注意事項 

[應用情境]
MSMQ讓發送訊息端與接收端可以不是同時運作,如同Email的傳送與接收一樣
甚至允許傳送與接收端的網路是可以暫時中斷的
適用於以下類型的交易
1.重要的金融交易 如電子商務(保證成功)
2.外出的業務代表使用的銷售系統(離線交易)
3.工作流程(work flow): MQ讓你可以建立一個流程可以更新各個系統, 此方法可讓各系統鬆散偶合(Loose Coupling) 互相不被影響
    讓你可以更安心的升級各系統     

[實作]
1.開始動手寫程式之前: 安裝MSMQ:程式集/安裝Windows功能/Microsft Message Queue(MSMQ) 伺服器
2.git上的本專案範例:https://github.com/michaelfangtw/MyMSMQ
   傳送端:MyMSMQSender
   接收端:MyMSMQReceiver
   參考引用: Microsoft.Messaging
   參考引用: MyEntity.Customer (傳送接收此物件)
   
   傳送端:MyMSMQSender Sample Code
   MSMQ 傳送路徑: .\Private$\MyQueue  


        public static void SendMessage()
        {
            MessageQueue myQueue;
            string path = "";
            //local private
            //path = ".\\private$\\MyQueue"; //本機
            //path = @"FormatName:Direct=OS:fij-nb\private$\MyQueue"; //遠端主機名稱
            path = @"FormatName:Direct=TCP:192.168.0.103\private$\MyQueue";//遠端主機IP
            if (path.StartsWith(@".\"))// path=@".\Private$\MyQueue"
            { 
                if (MessageQueue.Exists(path))
                {
                    myQueue = new MessageQueue(path);
                }
                else
                {
                    myQueue = MessageQueue.Create(path);
                }
            }
            else
            {
                myQueue = new MessageQueue(path);
            }
           
            
            List<Customer> customerList = new List<Customer>();
            customerList.Add(new Customer { CustomerID = "1", CustomerName = "Mike", Birthday = DateTime.Parse("1973/07/27"), Email = "yingchih.fang@gmail.com", CreateTime = DateTime.Now });
            customerList.Add(new Customer { CustomerID = "2", CustomerName = "Dan", Birthday = DateTime.Parse("1973/08/19"), Email = "danise0819@gmai.com", CreateTime = DateTime.Now });

            Message MyMessage = new Message();
            //set formatter for Message
            MyMessage.Formatter = new BinaryMessageFormatter();
            MyMessage.Body = customerList;
            MyMessage.Label = "customerList," + DateTime.Now.ToString("yyyyMMddHHmmss");
            MyMessage.Priority = MessagePriority.High;
            myQueue.Send(MyMessage);
            Console.WriteLine("path:{0}", path);
        }


   
   接收端:MyMSMQReceiver SampleCode

        public static int ReceiveMessage()
        {
            MessageQueue myMessageQueue;
            string path = "";
            //path = ".\\private$\\MyQueue"; //本機
            //path = @"FormatName:Direct=OS:fij-nb\private$\MyQueue"; //遠端主機名稱
            path = @"FormatName:Direct=TCP:192.168.0.103\private$\MyQueue";//遠端主機IP
            myMessageQueue = new MessageQueue(path);

            myMessageQueue.Formatter = new BinaryMessageFormatter();
            Message[] messages = myMessageQueue.GetAllMessages();

            int messageCount = 0;
            Console.WriteLine("Receive MessageQueue from {0}", path);
            Console.WriteLine("messages size:{0}", messages.Length);
            foreach (Message message in messages)
            {
                messageCount++;
                Message MyMessage = myMessageQueue.Receive();
                List<Customer> customerList = (List<Customer>)MyMessage.Body;
                Console.WriteLine("Message #{0}", messageCount);
                Console.WriteLine("customerList.count:{0}", customerList.Count);
                int count = 0;
                foreach (Customer customer in customerList)
                {
                    Console.WriteLine("Customer[{0}],CustomerID:{1},CustomerName:{2},CreateDate:{3} \r\n", count, customer.CustomerID, customer.CustomerName, customer.CreateTime.ToString("yyyy/MM/dd HH:mm:ss.fff"));
                    count++;
                }
                Console.WriteLine("");

            }

            return messageCount;
        }


[後記]
注意事項:
1.參考引用: 若要傳送物件(e.g MyEntity.Customer) , 該物件需Sender/Receiver都要引用
2.path 的遠端主機格式注意,e.g  path="FormatName:Direct=TCP:192.168.0.103\private$\MyQueue";
3.發送時Formatter 要設定為BinaryMessageFormatter , e.g:  MyMessage.Formatter = new BinaryMessageFormatter();
4.接收物件後 要轉型: List<Customer> customerList = (List<Customer>)MyMessage.Body;
5.接收所有訊息: Message[] messages = myMessageQueue.GetAllMessages();   

[參考]
1.Message Queuing (MSMQ) 
https://msdn.microsoft.com/en-us/library/ms711472(VS.85).aspx
2.MSMQ remote queue path format
http://www.infosysblogs.com/microsoft/2007/05/msmq_receiving_messages_from_r.html