WCF回调服务订阅\取消订阅

时间:2017-01-22 07:26:34

标签: c# wcf notsupportedexception

我试图了解如何使用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服务的下一行时,我有Equals方法的NotSupportedException:

if (NorthwindCallbackService.mCallbacks.ContainsKey(callbackForClient))

我明白这个问题的原因并没有实现IEquatable,而是如何在服务器端实现它,以及使用回调的最佳方法是什么?

1 个答案:

答案 0 :(得分:1)

这个答案是关于问题的最后部分:

  

使用回调的最佳方式是什么?

您了解了这个想法,但为什么不使用byte的{​​{1}}值?首先,没有“最佳方式”。但我建议以这样的方式更改ConcurrentDictionary,以便将客户端ID与回调信息一起存储到ConcurrentDictionary中,这样您就可以更轻松地查询,并且可以存储有关客户端的更多信息: / p>

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. } } } } 参数扩展SendNotification方法,也可以向特定客户端发送通知。

你甚至可以用自定义类的实例替换Guid,该自定义类包含有关客户端的更多信息,例如Id,它喜欢接收的通知类型,ip地址或任何你想要的{{1构造:

ConcurrentDictionary<Guid, INotifierCallback>