异步Web服务回调 - 如何在服务器端实现两个功能

时间:2012-04-30 07:10:25

标签: .net web-services asynchronous

服务器和客户端都使用.Net 4,

目前正在使用Callbacks进行异步Web服务调用。

但是服务器正在做的工作需要很长时间,我希望能够在服务器上释放请求线程(类似于客户端)。

是否可以使用.Net Callbacks来调用服务器上的功能A.

功能B(在服务器上)将返回客户端回调函数的答案吗?

我正在使用Asynchronous Web Service Calls over HTTP with the .NET Framework(没有WCF)。

由于

圣拉斐尔

1 个答案:

答案 0 :(得分:0)

在此示例代码中,客户端在ECF服务器上调用该函数,服务器也调用客户端函数。

在以下示例中,您还可以找到事件订阅。

示例代码SampleServiceClient:

using System;
using System.Collections.Generic;
using System.ServiceModel;
using System.Text;
using SampleServiceClient.SampleServiceReference;
using System.Windows.Forms;
using System.Threading;
using System.ComponentModel;


namespace SampleServiceClient
{
    /*WCF duplex use a SynchronizationContext by default, which means the callback will happen on UI threadm,  
     * so that you can update UI in your callback.  But your client are calling your server in on the UI thread,  
     * so the callback will never be able to be delivered to your client.  that's the orignal reason why it blocked.
     * 
        Now if you use Synchronization=false,  the callback will be delivered to you by a non-UI thread,  
     * that's why you can receive the callback now.

     * After you receive the callback,  you still want to update the UI in the UI thread,  
     * but the UI thread is still blocking now waiting for server response,  so that's why it is blocking again,  is it right?*/


    [CallbackBehavior(UseSynchronizationContext = false)] 
    class SampleCallback : IService1Callback
    {
        frmClient frm; 
        public SampleCallback()
        {

        }
        public SampleCallback(frmClient  Form1)
        {

            frm = Form1;
        }
        public void ShowCallbackMessage(string message)
        {
            SetText("Callback message --> " + message);
        }

        public void OnPriceChanged(int value)
        {
            SetText("On Price Changed by client number : " + value.ToString());
        }

        private void SetText(String str)
        {
            SendOrPostCallback instance = new SendOrPostCallback(frm.AddItem);
            frm.BeginInvoke(instance, str);
        }

    }
}

服务器端代码:

using System;
using System.Collections.Generic;
using System.ServiceModel;
using System.Text;

namespace SampleService
{
    //No Service Contract Tag for Callback Inteface
    interface ISampleCallback
    {
        [OperationContract(IsOneWay = true)]
        void ShowCallbackMessage(string message);

        [OperationContract(IsOneWay = true)]
        void OnPriceChanged(int value);

    }

 //Name of Callback Contract on the WCF Service Contract which we want to expose to client
    //You can assosiate only one CallBack Interface with a WCF Service Contract
    [ServiceContract(SessionMode = SessionMode.Required, CallbackContract = typeof(ISampleCallback))]
    public interface IService1
    {
        [OperationContract]
        string GetData(int value);

        [OperationContract (IsOneWay=true)]
        void ChangePrice(int value);

        //Code to Show Events Programming
        [OperationContract]
        bool SubscribeToPriceChangedEvent();

        [OperationContract]
        bool UnsubscribeFromPriceChangedEvent();
    }

[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerSession,
                 ConcurrencyMode = ConcurrencyMode.Reentrant)]
    public class Service1 : IService1
    {
        static List<ISampleCallback> clients = new List<ISampleCallback>();
        private ISampleCallback callback=null;
        internal ISampleCallback Callback
        {
            get { return callback; }
            set { callback = value; }
        }

        public string  GetData(int value)
        {
            //Invoke the callback operation in the client operation
            callback = OperationContext.Current.GetCallbackChannel<ISampleCallback>();
            //All WCF channels implements the ICommunicationObject interface.
            //If State is not opened then the service should not attempt to use callback.
            if (((ICommunicationObject)callback).State == CommunicationState.Opened)
            {

                 Callback.ShowCallbackMessage("You are the client number " + value.ToString());
            }
            return string.Format("Callback message sent to client number " + value.ToString());
        }

        public void ChangePrice(int value)
        {
            raisePriceChangedEvent(value);
        }

        //Event Programming
        public bool SubscribeToPriceChangedEvent()
        {
            try
            {
                Callback = OperationContext.Current.GetCallbackChannel<ISampleCallback>();
                if (!clients.Contains(Callback))
                {
                    clients.Add(Callback);
                }
                return true;
            }
            catch (Exception)
            {
                return false;
            }

        }

        public bool UnsubscribeFromPriceChangedEvent()
        {
            try
            {
                Callback = OperationContext.Current.GetCallbackChannel<ISampleCallback>();
                clients.Remove (Callback);
                return true;
            }
            catch (Exception)
            {
                return false;
            }
        }

        private void raisePriceChangedEvent(int value)
        {
            clients.ForEach(delegate(ISampleCallback oCallback)
               {
                   if (((ICommunicationObject)oCallback).State == CommunicationState.Opened)
                   {
                       oCallback.OnPriceChanged(value);
                   }
                   else
                   {
                       clients.Remove(oCallback);
                   }

                });
        }
    }
}