2017-01-22 3 views
1

Я пытаюсь понять, как работать с обратными вызовами WCF. Я был создать следующие интерфейсы:Служба обратного вызова 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(); 
    } 
} 

И У меня есть метод NotSupportedException для Equals при выполнении следующей строки службы WCF:

if (NorthwindCallbackService.mCallbacks.ContainsKey(callbackForClient)) 

Я понимаю, что причина этой проблемы не реализована IEquatable, но как ее реализовать на стороне сервера и как лучше всего использовать обратные вызовы?

ответ

1

Этот ответ о последней части вопроса:

, что это лучший способ, чтобы использовать обратные вызовы?

Вы получили идея покрыты, но почему вы не используете значение ConcurrentDictionarybyte? Во-первых, нет «лучшего способа». Но я предлагаю изменить ConcurrentDictionary таким образом, что вы можете хранить идентификатор клиента вместе с информацией обратного вызова в 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.

Можно даже заменить ConcurrentDictionary<Guid, INotifierCallback> с экземпляром пользовательского класса, который содержит больше информации о клиенте, как Id, тип уведомлений он любит получать IP-адрес или что вы хотите, используя ConcurrentDictionary<Guid, ClientCallbackInfo> конструкцию:

public class ClientCallbackInfo 
{ 
    public INotifierCallback Callback { get; set; } 
    public string SomeOtherClientInfo { get; set; } 
} 
Смежные вопросы