簡體   English   中英

WCF 回調服務訂閱\\取消訂閱

[英]WCF Callback service Subscribe\Unsubscribe

我試圖了解如何使用 WCF 的回調。 我正在創建下一個接口:

public interface INotifierCallback : IEquatable<INotifierCallback>
{
    /// <summary>
    /// Send notification.
    /// </summary>
    /// <param name="notification">Notification.</param>
    [OperationContract(IsOneWay = true)]
    void SendNotificationBack(string notification);
}

[ServiceContract(Namespace = "http://MyWCFLearning.com/NorthwindCallbackService",
    CallbackContract = typeof(INotifierCallback))]
public interface INorthwindCallbackService
{
    /// <summary>
    /// Subscribe to notifications.
    /// </summary>
    [OperationContract]
    void Subscribe();

    /// <summary>
    /// Unsubscribe from notifications.
    /// </summary>
    [OperationContract]
    void Unsubscribe();

    /// <summary>
    /// Send notification.
    /// </summary>
    /// <param name="notification">Notification.</param>
    [OperationContract(IsOneWay = true)]
    void SendNotification(string notification);
}

我通過下一個方式實現這個接口:

public class NorthwindCallbackService : INorthwindCallbackService
    {
        /// <summary>
        /// Callbacks to clients.
        /// </summary>
        protected static IDictionary<INotifierCallback, byte> mCallbacks { get; set; }

        static NorthwindCallbackService()
        {
            NorthwindCallbackService.mCallbacks = new ConcurrentDictionary<INotifierCallback, byte>();
        }

        public void Subscribe()
        {
            INotifierCallback callbackForClient;

            callbackForClient = OperationContext.Current.GetCallbackChannel<INotifierCallback>();
            if (NorthwindCallbackService.mCallbacks.ContainsKey(callbackForClient) == false)
            {
                NorthwindCallbackService.mCallbacks.Add(callbackForClient, default(byte));
            }
        }

        public void Unsubscribe()
        {
            INotifierCallback callbackForClient;

            callbackForClient = OperationContext.Current.GetCallbackChannel<INotifierCallback>();
            if (NorthwindCallbackService.mCallbacks.ContainsKey(callbackForClient))
            {
                NorthwindCallbackService.mCallbacks.Remove(callbackForClient);
            }
        }

        public void SendNotification(string notification)
        {
            foreach (var currentCallback in NorthwindCallbackService.mCallbacks)
            {
                try
                {
                    currentCallback.Key.SendNotificationBack(notification);
                }
                catch (ObjectDisposedException)
                {
                    //TODO: When client of NorthwindCallbackService call Dispose() method, we should remove callback of him from NorthwindCallbackService.mCallbacks, but I do not know how to make it.
                }
            }
        }
    }

然后我創建了 UnitTest 項目,在其中添加了下一個測試方法:

[TestMethod]
public void SubscribeAndUnsubscribeTest()
{
    INorthwindCallbackServiceCallback callbackHandler;
    InstanceContext instanceContext;

    callbackHandler = new FakeINorthwindCallbackServiceCallback();
    instanceContext = new InstanceContext(callbackHandler);

    using (var callbackServiceClient = new NorthwindCallbackServiceClient(instanceContext))
    {
        callbackServiceClient.Subscribe();
        callbackServiceClient.Unsubscribe();
    }
}

在執行 WCF 服務的下一行時,我有 NotSupportedException for Equals 方法:

if (NorthwindCallbackService.mCallbacks.ContainsKey(callbackForClient))

我知道這個問題的原因沒有實現 IEquatable,但是如何在服務器端實現它,以及使用回調的最佳方法是什么?

這個答案是關於問題的最后一部分:

使用回調的最佳方法是什么?

您已經了解了這個想法,但為什么不使用ConcurrentDictionarybyte值? 首先,沒有“最好的方法”。 但是我建議更改ConcurrentDictionary的方式,您可以將客戶端 ID 與回調信息一起存儲到ConcurrentDictionary以便您可以更輕松地查詢並存儲有關客戶端的更多信息:

public class NorthwindCallbackService : INorthwindCallbackService
{
    /// <summary>
    /// Callbacks to clients.
    /// </summary>
    protected static IDictionary<Guid, INotifierCallback> mCallbacks { get; set; }

    static NorthwindCallbackService()
    {
        NorthwindCallbackService.mCallbacks = new ConcurrentDictionary<Guid, INotifierCallback>();
    }

    public void Subscribe(Guid clientId)
    {
        INotifierCallback callbackForClient;

        callbackForClient = OperationContext.Current.GetCallbackChannel<INotifierCallback>();
        if (NorthwindCallbackService.mCallbacks.ContainsKey(clientId) == false)
        {
            NorthwindCallbackService.mCallbacks.Add(clientId, callbackForClient);
        }
    }

    public void Unsubscribe(Guid clientId)
    {
        INotifierCallback callbackForClient;

        callbackForClient = OperationContext.Current.GetCallbackChannel<INotifierCallback>();
        if (NorthwindCallbackService.mCallbacks.ContainsKey(clientId))
        {
            NorthwindCallbackService.mCallbacks.Remove(clientId);
        }
    }

    public void SendNotification(string notification)
    {
        foreach (var currentCallback in NorthwindCallbackService.mCallbacks)
        {
            try
            {
                currentCallback.Value.SendNotificationBack(notification);
            }
            catch (ObjectDisposedException)
            {
                //TODO: When client of NorthwindCallbackService call Dispose() method, we should remove callback of him from NorthwindCallbackService.mCallbacks, but I do not know how to make it.
            }
        }
    }
}

現在,由於您可以識別客戶端,如果您使用Guid參數擴展SendNotification方法,您還可以向特定客戶端發送通知。

您甚至可以將ConcurrentDictionary<Guid, INotifierCallback>替換為自定義類的實例,該實例包含有關客戶端的更多信息,例如 Id、它喜歡接收的通知類型、IP 地址或使用ConcurrentDictionary<Guid, ClientCallbackInfo>任何您想要的信息ConcurrentDictionary<Guid, ClientCallbackInfo>構造:

public class ClientCallbackInfo
{
    public INotifierCallback Callback { get; set; }
    public string SomeOtherClientInfo { get; set; } 
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM