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事件 主動響應客戶端退出。
  • 調用回調對象的回調函數接口即可實現回調通知
4. 服務器端配置

編譯並運行上述服務后,會發現一個服務無法啟動的錯誤。

原因說得很清楚,要使用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的構造函數需要傳入一個參數了,在這個參數中就可以指定實現了回調接口的對象,從而響應回調通知。運行客戶端多個實例,發送消息,每個消息都會通知到所有客戶端,與我們預期結果一致。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM