<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      通過實例分析WCF Duplex消息交換

      聊天室實例:點此下載 

          我在《Windows Communication Foundation之旅?三》中詳細介紹了WCF中的Duplex消息交換模式。因為Duplex實現了客戶端與服務端雙向通信的功能,故而我實現了一個簡單的聊天室程序,展現Duplex的特點。有朋友在閱讀了這個例子之后,提出一個問題,即“如何讓服務端向指定的客戶端發送消息?”很高興的是,這位朋友在后來的郵件中說到問題已經解決了,思路是利用Singleton對象保存客戶端的Session。雖然存在一些比較奇怪的問題,然而總算是一種思路。

          我的思路與之相似,需要服務端維護一個Dictionary的集合,用以保存客戶端的信息。服務端在發送消息時,可以通過查找Dictionary對象,識別符合條件的客戶端。當我還在思考這樣的方式能否解決問題時,我在WCF官方網站上偶然發現了一個同樣利用Duplex實現聊天室的Sample。

          仔細閱讀了實例代碼,我恍然發現自己在思考程序設計時,并沒有理解WCF最核心的價值,那就是“服務”。作為實現SOA體系架構的技術框架,WCF最重要的特征就在于能夠定義和提供服務。以聊天室程序為例,雖然服務端會參與消息的交互,但卻不應該參與到聊天中。也就是說,客戶端與服務端的角色任務是不相同的。通過用例圖可以看到兩者之間的區別: 

      chatroom01.gif
      圖1  正確的用例圖            

      chatroom02.gif
      圖二  錯誤的用例圖

          明確了以“服務”為核心的程序結構,我們才能夠更好地利用WCF,定制自己的服務,分清楚服務的邊界,定義好消息的格式。雖然,一個聊天室程序無法體現SOA的核心精神,然而樹立面向服務的思想確實必要的。正如我們在開始面向對象程序設計時,需要樹立面向對象的思想一樣。

          該聊天室程序的實現主要通過Duplex來實現,其中又利用了MulticastDelegate與異步調用。其中,服務接口的定義如下:
          [ServiceContract(SessionMode = SessionMode.Required, CallbackContract = typeof(IChatCallback))]
          interface IChat
          {
              [OperationContract(IsOneWay = false, IsInitiating = true, IsTerminating = false)]
              string[] Join(string name);

              [OperationContract(IsOneWay = true, IsInitiating = false, IsTerminating = false)]
              void Say(string msg);

              [OperationContract(IsOneWay = true, IsInitiating = false, IsTerminating = false)]
              void Whisper(string to, string msg);

              [OperationContract(IsOneWay = true, IsInitiating = false, IsTerminating = true)]
              void Leave();
      }

          回調接口的定義如下:
          interface IChatCallback
          {
              [OperationContract(IsOneWay = true)]
              void Receive(string senderName, string message);

              [OperationContract(IsOneWay = true)]
              void ReceiveWhisper(string senderName, string message);

              [OperationContract(IsOneWay = true)]
              void UserEnter(string name);

              [OperationContract(IsOneWay = true)]
              void UserLeave(string name);
          }

          服務提供了Join、Say、Whisper與Leave等接口方法,向對應的是回調接口的接口方法。在實現IChat服務接口的服務類ChatService中,定義了委托ChatEventHandler與ChatEventHandler類型的事件ChatEvent,正是通過它實現了識別了客戶的消息廣播。方法如下:
           private void BroadcastMessage(ChatEventArgs e)
           {
               ChatEventHandler temp = ChatEvent;

               if (temp != null)
               {
                   foreach (ChatEventHandler handler in temp.GetInvocationList())
                   {
                      handler.BeginInvoke(this, e, new AsyncCallback(EndAsync), null);
                   }
               }
          }

          在客戶端加入聊天室程序之前,該客戶端并沒有訂閱ChatEvent事件,此時調用BroadcastMessage方法,在通過GetInvocationList方法獲取MulticastDelegate時,不存在該客戶端的委托實例。因而,其他客戶在通過聊天室進行聊天時,不會將聊天信息發送到該客戶端。體現在程序中,就是Join方法的如下代碼片斷:
          myEventHandler = new ChatEventHandler(MyEventHandler);
          ……

          callback = OperationContext.Current.GetCallbackChannel<IChatCallback>();
          ChatEventArgs e = new ChatEventArgs();
          e.msgType = MessageType.UserEnter;
          e.name = name;
          BroadcastMessage(e);
          ChatEvent += myEventHandler;
          ……

          注意看,ChatEvent += myEventHandler語句是放在BroadcastMessage方法調用之后。一旦該客戶端加入聊天室程序之后,再調用BroadcastMessage方法,該客戶端就能接收消息了。

          ChatEvent事件指向的方法是MyEventHandler,該方法將執行回調接口的相關方法:
          private void MyEventHandler(object sender, ChatEventArgs e)
          {
              try
              {
                  switch (e.msgType)
                  {
                      case MessageType.Receive:
                          callback.Receive(e.name, e.message);
                          break;
                      case MessageType.ReceiveWhisper:
                          callback.ReceiveWhisper(e.name, e.message);
                          break;
                      case MessageType.UserEnter:
                          callback.UserEnter(e.name);
                          break;
                      case MessageType.UserLeave:
                          callback.UserLeave(e.name);
                          break;
                  }
              }
              catch
              {
                  Leave();
              }
          }

          還需要注意的是Whisper方法。由于它實現了私聊功能,因而向指定客戶發送信息時,不應該采用廣播方式。如何找到指定客戶呢?這需要一個Dictionary集合,保存客戶名和與之對應的ChatEventHandler實例。在執行Whisper方法時,就可以根據客戶名找到對應的ChatEventHandler實例進行調用:
          public void Whisper(string to, string msg)
          {
              ChatEventArgs e = new ChatEventArgs();
              e.msgType = MessageType.ReceiveWhisper;
              e.name = this.name;
              e.message = msg;
              try
              {
                  ChatEventHandler chatterTo;
                  lock (syncObj)
                  {
                      chatterTo = chatters[to];
                  }
                  chatterTo.BeginInvoke(this, e, new AsyncCallback(EndAsync), null);
              }
              catch (KeyNotFoundException)
              {
              }
          }

          在客戶端代碼中,服務接口的調用采用了異步調用的方式,例如客戶端加入聊天室:
          proxy = new ChatProxy(site);
          IAsyncResult iar = proxy.BeginJoin(myNick, new AsyncCallback(OnEndJoin), null);

          運行聊天室程序時,服務端僅需要提供穩定而持續的服務。聊天的參與者均為客戶端用戶。因而服務端的運行代碼如下所示:
          Uri uri = new Uri(ConfigurationManager.AppSettings["addr"]);
          ServiceHost host = new ServiceHost(typeof(NikeSoftChat.ChatService), uri);
          host.Open();
          Console.WriteLine("Chat service listen on endpoint {0}", uri.ToString());
          Console.WriteLine("Press ENTER to stop chat service...");
          Console.ReadLine();
          host.Abort();
          host.Close();

          本文Sample的作者是Nikola Paljetak。鑒于作者本人在代碼所附的許可聲明,為了幫助大家閱讀本文,在此附上Nikola Paljetak的Sample,你可以在WCF官方網站中找到它。Nikola Paljetak的許可聲明如下:
          Permission is granted to anyone to use this software for any purpose, including commercial applications.

      posted @ 2007-03-08 11:50  張逸  閱讀(9671)  評論(18)    收藏  舉報
      主站蜘蛛池模板: 边添小泬边狠狠躁视频| 欧美z0zo人禽交另类视频| 国产成人综合网亚洲第一| 亚洲第一极品精品无码久久| 中文字幕日韩有码一区| 欧美肥老太交视频免费| 亚洲AV成人片不卡无码| 德安县| 免费看黄色亚洲一区久久| 国产精品男女爽免费视频| 伊人久久大香线蕉AV网禁呦| 国产午夜福利精品视频| 在线 欧美 中文 亚洲 精品| 亚洲欧美在线一区中文字幕| 成人午夜电影福利免费| 一边吃奶一边摸做爽视频| 亚洲AV乱码毛片在线播放| 日本精品aⅴ一区二区三区| 无码国模国产在线观看免费| 泸定县| 亚洲色在线v中文字幕| 国产av丝袜熟女一二三| 日韩久久久久久中文人妻| 国产毛a片啊久久久久久保和丸| 丰满岳乱妇久久久| 亚洲天堂激情av在线| 中文字幕日本一区二区在线观看 | 起碰免费公开97在线视频| 久久亚洲精品11p| 人妻精品中文字幕av| 动漫AV纯肉无码AV电影网| 人与禽交av在线播放| 成人3D动漫一区二区三区| 成人国产精品日本在线观看| 成人3D动漫一区二区三区| 开封市| 国产成人综合久久亚洲精品| 伊人中文在线最新版天堂| 欧美亚洲综合成人a∨在线| 公喝错春药让我高潮| 成人中文在线|