WCF筆記(8)服務回調

服務器端回調有啥用呢?

比如:

向服務器上傳了一個文件,但是,爲了節約空間或出於其他目的,服務器要對剛上傳的文件進行處理(壓縮或者多媒體文件轉碼),這些操作無法馬上向客戶端回覆,而客戶端也不可能就停在這裏一直在等。我們希望,在客戶端上傳文件後馬上返回,而服務器對文件處理完成後再通知一下客戶端。

這樣就引出一個東東——回調,E文叫Call Back。我估計用E文表述可能更好理解,Call back就是相對於Call to而言的,即調用的方向與Call to相反

在WCF中使用回調,只需要多定義一個接口即可,這個接口的方法和服務協定一樣,要附加OperationContractAttribute特性。

然後在定義服務協定時,在ServiceContractAttribute的CallbackContract中設置一個回調接口的Type。

在服務操作中,通過OperationContext的GetCallbackChannel方法取出回調協定的實例,調用回調的方法,就會在客戶端尋找回調接口的實現類並調用對應的成員。


下面我們做一個搖號程序進行說明

一、服務端

    /// <summary>
    /// 1、定義一個回調接口
    /// </summary>
    public interface ICallback
    {
        [OperationContract(IsOneWay = true)]
        void CallClient(int value);
    }

    /// <summary>
    /// 2、定義服務協定
    /// </summary>
    [ServiceContract(Namespace="MyNamespace",
    CallbackContract=typeof(ICallback),//標註回調協定
    SessionMode=SessionMode.Required //要求會話 
    )]
    public interface IService   
    {
        /// <summary>
        /// 會話從調用該操作開始
        /// </summary>
        [OperationContract(IsOneWay=true,IsInitiating=true,IsTerminating=false)]
        void CallServerOperation();
        /// <summary>
        /// 調用該操作後,會話結束
        /// </summary>
        [OperationContract(IsOneWay = true, IsInitiating = false, IsTerminating = true)]
        void End();
    }

    /// <summary>
    /// 3、實現服務協定
    /// </summary>
    public class MyService : IService,IDisposable 
    {
        private ICallback m_cb = null; //回調接口
        private System.Threading.Timer m_timer = null; //計時器,定時幹活
        private Random m_random = null;//隨機數
        public void CallServerOperation()
        {
            m_cb = OperationContext.Current.GetCallbackChannel<ICallback>();
            m_random = new Random();
            //生成隨機數,並回調到客戶端;每3秒執行一次
            m_timer = new System.Threading.Timer((obj) => m_cb.CallClient(m_random.Next()), null, 10, 3000);  
        }

        public void End()
        {
            Console.WriteLine("會話結束");
        }

        public void Dispose()
        {
            m_timer.Dispose();
            Console.WriteLine("{0}-服務實例已釋放.", DateTime.Now.ToLongTimeString());
        }
    }

 //配置服務器
        static void Main()
        {
            Console.Title = "WCF服務端";
            //服務基地址
            Uri baseUri = new Uri("http://localhost:3000/Service");
            //聲明服務器主機
            using (ServiceHost host = new ServiceHost(typeof(MyService), baseUri))
            {
                /*既支持會話傳輸速度又快的非TCP莫屬了,所以這裏我選擇NetTcpBinding;
                 * 這樣在默認行爲下,每啓動一個會話就創建一個服務實例,而當會話結束時就會釋放。
                 */
                //添加綁定和終結點
                NetTcpBinding binding = new NetTcpBinding();
                binding.Security.Mode = SecurityMode.None;
                host.AddServiceEndpoint(typeof(IService), binding, "net.tcp://localhost:1211/rr");
                //添加服務描述
                host.Description.Behaviors.Add(new ServiceMetadataBehavior { HttpGetEnabled = true });
                //啓動服務
                try
                {
                    host.Open();
                    Console.WriteLine("服務已啓動");
                }
                catch (Exception ex)
                {
                    Console.WriteLine(ex.Message);
                }
                Console.ReadKey();
                //關閉服務
                host.Close();
            }
        }

二、客戶端

在客戶端實現回調接口

    /// <summary>
    /// 實現回調接口
    /// </summary>
    public class MyCallback : WS.IServiceCallback
    {
        /// <summary>
        /// 回調引發該事件
        /// </summary>
        public event EventHandler<int> ValueCallback;

        /// <summary>
        /// 因爲該方法是由服務器調用的
        /// 如果希望在客戶端能及時作出響應,應當使用事件
        /// </summary>
        /// <param name="value">value</param>
        public void CallClient(int value)
        {
            if (ValueCallback != null)
            {
                ValueCallback(this, value);
            }
        }
    }
 public partial class Form1 : Form
    {
        WS.ServiceClient m_sc;
        readonly MyCallback m_mcallback;
        public Form1()
        {
            InitializeComponent();
            m_mcallback = new MyCallback();
            m_mcallback.ValueCallback += mc_ValueCallback;
            labNum.Text = "";
            btnStop.Enabled = false;
        }

        void mc_ValueCallback(object sender, int e)
        {
            labNum.Text = e.ToString();
        }

        private void btnStart_Click(object sender, EventArgs e)
        {
            m_sc = new WS.ServiceClient(new System.ServiceModel.InstanceContext(m_mcallback));
            m_sc.CallServerOperation();
            btnStart.Enabled = false;
            btnStop.Enabled = true;
        }

        private void btnStop_Click(object sender, EventArgs e)
        {
            m_sc.End();
            btnStart.Enabled = true;
            btnStop.Enabled = false;
        }
    }

效果如下:



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章