简体   繁体   English

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

[英]WCF Callback service Subscribe\Unsubscribe

I trying to understand how to work with callbacks of WCF.我试图了解如何使用 WCF 的回调。 I was create next interfaces:我正在创建下一个接口:

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

I implement this interface by the next way:我通过下一个方式实现这个接口:

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.
                }
            }
        }
    }

Then I create UnitTest project where I added next method for test:然后我创建了 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();
    }
}

And I have NotSupportedException for Equals method when execute next line of WCF service:在执行 WCF 服务的下一行时,我有 NotSupportedException for Equals 方法:

if (NorthwindCallbackService.mCallbacks.ContainsKey(callbackForClient))

I understand that reason of this problem is not implemented IEquatable, but how to implement it on server side, and what is the best way to use callbacks?我知道这个问题的原因没有实现 IEquatable,但是如何在服务器端实现它,以及使用回调的最佳方法是什么?

This answer is about the last part of the question:这个答案是关于问题的最后一部分:

what is the best way to use callbacks?使用回调的最佳方法是什么?

You got the idea covered, but why are you not using the byte value of the ConcurrentDictionary ?您已经了解了这个想法,但为什么不使用ConcurrentDictionarybyte值? First of all, there is no 'best way'.首先,没有“最好的方法”。 But I propose to change the ConcurrentDictionary in such a way that you can store a client id together with the callback info into the ConcurrentDictionary so you can query easier and you can store more info about the client:但是我建议更改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.
            }
        }
    }
}

Now since you can identify the clients you can also send notifications to specific clients if you extend the SendNotification method with a Guid parameter.现在,由于您可以识别客户端,如果您使用Guid参数扩展SendNotification方法,您还可以向特定客户端发送通知。

You could even replace the ConcurrentDictionary<Guid, INotifierCallback> with an instance of a custom class that contains more information about the client like Id, type of notifications it likes to receive, ip-address or whatever you want using a ConcurrentDictionary<Guid, ClientCallbackInfo> construct:您甚至可以将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