WCF入门(六)——回调
在上篇文章中介紹了一下WCF中的客戶端到服務器端的單向通知,在實際應用中,還經常使用服務器端到客戶端的單向通知。例如,在聊天室里,我們需要把某人的發言廣播給每一個人。對于這種單向通知,我們一般稱為回調。本文就以一個簡單的聊天室為例,介紹一下如何實現回調。
1. 定義一個回調接口????interface IMessageCallback
????{
????????[OperationContract(IsOneWay = true)]
????????void OnMessageAdded(string message, DateTime timestamp);
????}
這個接口并不是服務,因此沒有ServiceContract標志,但其回調函數形式需要被公布,因此接口函數有OperationContract標志,另外,這個也是一個單向通知,因此有IsOneWay = true設置(注:這里的IsOneWay不是必須的,可以獲取回調函數的返回值的)。
2. 在服務契約上加上回調通知接口聲明????[ServiceContract(CallbackContract = typeof(IMessageCallback))]
????public interface IService1
????{
????????[OperationContract]
????????void AddMessage(string message);
????????[OperationContract]
????????void Subscribe();
????????[OperationContract]
????????void Unsubscribe();
????}
除了客戶端上報消息的接口外,這里也加了兩個接口函數Subscribe和Unsubscribe,用來注冊回調和刪除回調,實現了一個典型的觀察者模式。(PS:這兩個接口并不是必須的,主要是為了方便演示回調的實現過程)
3. 實現回調接口聲明完成后,給了一個簡單的實現(這個只是示例代碼,線程安全,最佳實踐神馬的都沒有考慮,不要用于實際項目中)。
????public class Service1 : IService1
????{
????????static List<IMessageCallback> subscribers = new List<IMessageCallback>();
????????public void AddMessage(string message)
????????{
????????????subscribers.ForEach(callback =>
????????????{
????????????????if (((ICommunicationObject)callback).State == CommunicationState.Opened)
????????????????????callback.OnMessageAdded(message, DateTime.Now);
????????????????else
????????????????????subscribers.Remove(callback);
????????????});
????????}
????????public void Subscribe()
????????{
????????????var callback = OperationContext.Current.GetCallbackChannel<IMessageCallback>();
????????????subscribers.Add(callback);
????????}
????????public void Unsubscribe()
????????{
????????????var callback = OperationContext.Current.GetCallbackChannel<IMessageCallback>();
????????????subscribers.Remove(callback);
????????}
????}
從上述代碼中可以發現,回調的基本使用方式如下:
- 從OperationContext.GetCallbackChannel中獲取回調通道對象,該對象實現了回調接口和ICommunicationObject接口。
- 根據IcommunicationObject.State屬性查看其是否可用,也可以注冊IcommunicationObject. Closed事件主動響應客戶端退出。
- 調用回調對象的回調函數接口即可實現回調通知
編譯并運行上述服務后,會發現一個服務無法啟動的錯誤。
原因說得很清楚,要使用CallbackContract,則需要底層協議支持雙工(因為需要從服務器端主動通知客戶端)。但目前使用的BasicHttpBinding由于是基于Http協議,不支持雙工(另外一個基于Http協議的WSHttpBinding也不支持雙工),要改成支持雙工的協議。目前WCF中支持雙工的協議有如下幾種:
- 基于TCP協議的NetTcpBinding
- 基于管道的NetNamedPipeBinding
- 基于Http協議的wsDualHttpBinding,雖然Http協議本身不支持雙工,但是wsDualHttpBinding通過創建兩個不同方向的Http連接來實現了雙向傳輸。
為了簡單,我這里就改成了wsDualHttpBinding。
5. 實現客戶端代碼由于WCF測試客戶端不支持回調的測試,因此這里我們就需要手動實現客戶端代碼:
????????static void Main(string[] args)
????????{
????????????var context = new System.ServiceModel.InstanceContext(new Callback());
????????????var client = new WcfClient.Service.Service1Client(context);
????????????client.Subscribe();
????????????while (true)
????????????{
????????????????var input = Console.ReadLine();
????????????????if (string.IsNullOrWhiteSpace(input))
????????????????????break;
????????????????client.AddMessage(input);
????????????}
????????????client.Unsubscribe();
????????????client.Close();
????????}
????????class Callback:IService1Callback
????????{
????????????public void OnMessageAdded(string message, DateTime timestamp)
????????????{
????????????????Console.WriteLine(">>> Receive Message {0} {1}", message, timestamp);
????????????}
????????}
編寫這個代碼時就會發現:現在Client的構造函數需要傳入一個參數了,在這個參數中就可以指定實現了回調接口的對象,從而響應回調通知。運行客戶端多個實例,發送消息,每個消息都會通知到所有客戶端,與我們預期結果一致。
總結
以上是生活随笔為你收集整理的WCF入门(六)——回调的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 可可肉的奋斗(第一天)2012-12-2
- 下一篇: UBUNTU下的中文输入法:fcitx