1

サーバーとクライアントの両方が.Net 4を使用し、

現在、コールバックを使用して非同期 Web サービス呼び出しを行っています。

しかし、サーバーが行っている作業には時間がかかるため、サーバー上のリクエスト スレッドを解放できるようにしたいと考えています (クライアントと同様)。

.Net Callbacks を使用してサーバー上の関数 A を呼び出すことは可能ですか?

関数 B (サーバー上) は、クライアントのコールバック関数に応答を返しますか?

.NET Framework (WCF なし)で HTTP 経由の非同期 Web サービス呼び出しを使用しています。

ありがとう

ラファエル

4

1 に答える 1

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);
                   }

                });
        }
    }
}
于 2012-04-30T07:23:51.123 に答える