WCF Callback тупик - PullRequest
       3

WCF Callback тупик

3 голосов
/ 31 октября 2011

Я столкнулся с проблемой со службой WCF, которая вызывает метод обратного вызова на клиенте.Сначала служба:

[ServiceContract(
SessionMode = SessionMode.Required,
CallbackContract = typeof(IMarketObserver))]
public interface IServer
{
  ...
  [OperationContract]
  [FaultContractAttribute(typeof(WCFFaultDetail))]
  bool NotifyOnMarket(EnumMarkets marketID);
  ...
}

Реализация службы:

[ServiceBehavior(
InstanceContextMode = InstanceContextMode.Single,
ConcurrencyMode = ConcurrencyMode.Multiple,
UseSynchronizationContext = false)]
public sealed class Platform : IServer
{
 ...
 public bool NotifyOnMarket(EnumMarkets marketID)
 {
    try
    {
        IMarketObserver callback = OperationContext.Current.GetCallbackChannel<IMarketObserver>();
        if (subscribers.Contains(callback) == false)
        {
            subscribers.Add(callback);
        }
    }
    catch
    {
        return false;
    }
    //This call may cause a call to the callback method SendMarketData()!!
    callSomeMethod();
    return exchangeProxy.IsMarketIDValid();
}

Контракт обратного вызова:

public interface IMarketObserver
{
  [OperationContract(IsOneWay = true)]
  void SendMarketData(MarketData marketData);
}

Клиентская реализация этого обратного вызова:

[CallbackBehavior(
    ConcurrencyMode = ConcurrencyMode.Multiple,
    UseSynchronizationContext = false)]
public class MarketBase : 
    IServerCallback
{
  protected IService serviceProxy;
  public void SendMarketData(MarketData marketData)
  {
      //Do something
  }
  private void NotifyOnMarkets()
  {
      foreach (EnumMarkets item in observedMarkets)
      {
          try
          {
              bool res = serviceProxy.NotifyOnMarket(item);
          }
          catch (Exception e)
          {
             ...
          }
      }
  }

Проблема возникает при вызове NotifyOnMarkets () с циклом foreach.

Если в списке наблюдаемых маркеров есть только один элемент, то есть точно один метод метода NotifyOnMarket () службы и всеработает нормально.

Но если наблюдаемый рынок содержит более одного элемента, то NotifyOnMarket () будет вызываться много раз с высокой частотой для сервера.

Реализация NotifyOnMarket () на серверевызывает метод, который, в свою очередь, вызывает метод обратного вызова SendMarketData (я прокомментировал этот факт).

В следах я вижу, что serviceProxy.NotifyOnMarket (item);не возвращает второй элемент, возникает тайм-аут.

На стороне сервера правильные обращения к NotifyOnMarket () обрабатываются правильно, и метод завершается.Но, как сказано выше, логический результат не будет отображаться на клиенте (тайм-аут).

Кроме того, можно видеть, что на стороне сервера вызывается обратный вызов (он односторонний, поэтому ответ не будетвозвращается), но на стороне клиента ничего не происходит, так как реализация обратного вызова не вызывается.

Мой вывод состоит в том, что произошла какая-то тупиковая ситуация, и это может быть связано с тем, что экземпляр клиента блокирует себя, и поэтому серверне вызывать метод обратного вызова.

Лучше ли отделить контекстный класс экземпляра от класса, который также выполняет сервисные вызовы?Если да, то почему?

Спасибо за совет,

Юрген

Ответы [ 2 ]

4 голосов
/ 31 октября 2011

На ваш вопрос: почему он должен быть в другой ветке? Прочитайте конец WCF Duplex Messaging :

WCF добавляет сложности в микс, применяя правило, которое говорит «Если вы не скажете мне иначе, я позволю только одну нить за раз в объект, который я контролирую ». Вы видите это с одноразовыми услугами это позволит только один вызов за раз по умолчанию. То же самое также Значение true для объекта реализации обратного вызова - поэтому WCF будет разрешать только один активный поток в клиенте за один раз. Так что пока WCF выполняет Исходящий вызов не разрешит входящий вызов в объект. Это вызывает первоначальную проблему с тупиком, который служба обратный вызов не может быть отправлен, пока исходящий вызов клиента находится в прогресс. Для решения этой проблемы мы используем часть «если вы не скажете мне иначе» вышеуказанного правила. Вы делаете это, комментируя обратный вызов класс реализации с атрибутом [CallbackBehavior], например:

[CallbackBehavior(ConcurrencyMode=ConcurrencyMode.Reentrant)]
0 голосов
/ 11 июля 2016

Вы делаете это правильно, устанавливая для него значение Multiple или Re-entrant (оба работают, но повторный вход будет вызывать 1 поток за раз, а множественный позволит нескольким потокам одновременно входить в ваш сервис).Лично я бы установил его как «повторно входящий», если только вам не нужно, чтобы в ваш сервис входили сразу несколько потоков.

Я просто написал тестовый пример на моей машине, следуя вашему примеру, и он работал просто отлично.,Я думаю, что в вашей реализации IIS (еще в 11 году) была ошибка.Невозможно проверить, сейчас.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...