现在的位置: 首页 > 综合 > 正文

WCF笔记(8)服务回调

2013年03月11日 ⁄ 综合 ⁄ 共 3225字 ⁄ 字号 评论关闭

服务器端回调有啥用呢?

比如:

向服务器上传了一个文件,但是,为了节约空间或出于其他目的,服务器要对刚上传的文件进行处理(压缩或者多媒体文件转码),这些操作无法马上向客户端回复,而客户端也不可能就停在这里一直在等。我们希望,在客户端上传文件后马上返回,而服务器对文件处理完成后再通知一下客户端。

这样就引出一个东东——回调,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;
        }
    }

效果如下:

抱歉!评论已关闭.