WCF NetTCP с фоновым потоком - PullRequest
       4

WCF NetTCP с фоновым потоком

0 голосов
/ 07 февраля 2011

Справочная информация:

У меня есть система, в которой размещаются службы WCF внутри службы Windows с привязкой NetTCP.Чтобы добавить новый сервис в коллекцию, вы просто добавляете стандартные записи конфигурации WCF внутриservices />, а затем добавьте строку внутри пользовательского раздела конфигурации, которая сообщает платформе хостинга, что ей нужно для инициализации службы.Каждая служба инициализируется с собственным фоновым потоком и экземпляром AppDomain, чтобы держать все изолированными.

Вот пример инициализации служб:

Host
  - ServerManager
    - ServiceManager 
      - BaseServerHost

Экземпляр ServerManager имеет коллекциюМенеджеры ServiceManager, каждый из которых соответствует одному экземпляру службы, в котором находится стандартная реализация WCF (ServiceHost.Open/Close и т. Д.).Экземпляр ServiceManager создает экземпляр (на основе конфигурации - он имеет стандартное определение сборки / типа) экземпляр службы с использованием базового класса BaseServerHost (аннотация).Каждый сервис должен наследовать от этого, чтобы инфраструктура могла его использовать. В рамках процесса инициализации BaseServerHost предоставляет пару событий, в частности событие UnhandledException, к которому присоединяется владелец ServiceManager. (Эта часть является критической в ​​отношении вопроса, приведенного ниже.)

Весь этот процесс работает исключительно хорошо для нас (один экземпляр запускает 63 службы), так как я могу привлечь кого-то, кто ничего не знает о WCF, и они могут создавать службы очень быстро.

Вопрос:

Проблема, с которой я столкнулся, связана с фоновым потоком.Большинство открытых методов на наших конечных точках выполняют значительную активность после стандартного вызова метода вставки / обновления / удаления, такого как отправка сообщений в другие системы.Чтобы сохранить производительность (интерфейс является веб-интерфейсом), мы позволяем начальному методу вставки / обновления / удаления делать свое дело, а затем запускаем фоновый поток для обработки всего, что конечному пользователю не нужно ждатьзавершить.Эта опция прекрасно работает до тех пор, пока что-то в этом фоновом потоке не будет обработано и отключит всю службу Windows, что, как я понимаю, разработано (и я в порядке).

На основании всех моих исследований, которые я обнаружилчто нет никакого способа реализовать глобальную попытку / поймать (за исключением использования взломанного конфига, включающего 1.1 обработку фоновых сбоев), поэтому моей команде придется вернуться и получить их в соответствующих местах.Кроме того, то, что я обнаружил, находится на стороне конечной точки хостинга WCF, похоже, в своем собственном потоке при каждом вызове, и заставить этот поток общаться с «родителем» было кошмаром.С точки зрения службы, вот макет:

Endpoint (svc - inherits from BaseServerHost, mentioned above)
  - Business Layer
    - Data Layer

Когда я ловлю исключение в фоновом потоке на бизнес-уровне, я раздуваю его с экземпляром Endpoint (который наследуется от BaseServerHost), который затем пытается запуститьСобытие UnhandledException в BaseServerHost для этой конкретной службы (которая была присоединена владельцем ServiceManager, который его создал).К сожалению, обработчик событий больше не существует, поэтому он вообще ничего не делает.Я пробовал множество вещей, чтобы заставить это работать, и до сих пор все мои усилия были напрасны.

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

Host
 - ServerManager
      - ServiceManager <=====================
           - BaseServerHost                ||
                - Endpoint (svc)           ||
                     - Business Layer <======
                          - Data Layer

Я безуспешно пробовал статические классы и даже зашел до того, что сделал ServerManager статичным и экспортировал свою ранее внутреннюю коллекцию ServiceManager (чтобы их можно было отключить), но эта коллекция также всегда пуста или равна нулю.

Мысли о том, чтобы сделать эту работу?

РЕДАКТИРОВАТЬ: После копания немного дальше, я нашел пример того, как именно я представляю эту работу. На стандартном веб-сайте ASP.NET на любой странице / обработчике и т. Д. Вы можете использовать свойство HttpContext.Current для доступа к текущему контексту для этого запроса. Именно так я и хотел бы, чтобы это работало с ServiceManager.Current, возвращающим владеющий ServiceManager для этой службы. Возможно, это помогает?

1 Ответ

0 голосов
/ 09 февраля 2011

Может быть, вам стоит заняться чем-нибудь с CallContext:

http://msdn.microsoft.com/en-us/library/system.runtime.remoting.messaging.callcontext.aspx

Вы можете использовать SetData / GetData или LogicalSetData / LogicalGetData в зависимости от того, хотите ли вы, чтобы ServiceManager был связан с одним физическим потоком (SetData) или «логическим» потоком (LogicalSetData). С LogicalSetData вы можете сделать один и тот же экземпляр ServiceManager доступным в потоке, а также в «дочерних» потоках этого потока. Попробую опубликовать пару потенциально полезных ссылок позже, когда смогу их найти.

Вот ссылка на «Виртуальный шаблон синглтона» в codeproject.

Вот ссылка на "Синглтон темы"

Вот ссылка на «Окружающий контекст»

Все эти идеи похожи. По сути, у вас есть объект со статическим свойством Current (можно получить или получить / установить). Current помещает свое значение в (и получает его) в CallContext, используя либо SetData (чтобы связать значение "Current" с текущим потоком), либо LogicalSetData (чтобы связать значение "Current" с текущим потоком и передать значение любому "дочерние" темы).

HttpContext реализован аналогичным образом.

System.Diagnostics.CorrelationManager - еще один хороший пример, который реализован аналогичным образом.

Я думаю, что статья Ambient Context довольно неплохо объясняет, чего можно достичь с помощью этой идеи.

Всякий раз, когда я обсуждаю CallContext, я стараюсь также включить эту ссылку в эту запись из блога Джеффри Рихтера.

В конечном счете, я не уверен, поможет ли это вам или нет. Одним из них было бы полезно, если бы у вас было многопоточное серверное приложение (возможно, каждый запрос выполняется потоком, и в разных потоках одновременно может выполняться несколько запросов), у вас может быть ServiceManager для каждого потока. В этом случае у вас может быть статический метод Current в ServiceManager, который всегда будет возвращать правильный экземпляр ServiceManager для определенного потока, поскольку он хранит ServiceManager в CallContext. Примерно так:

public class ServiceManager
{
  static string serviceManagerSlot = "ServiceManager";

  public static ServiceManager Current
  {
    get
    {
      ServiceManager sm = null;
      object o = CallContext.GetData(serviceManagerSlot);
      if (o == null)
      {
        o = new ServiceManager();
        CallContext.SetData(serviceManagerSlot, o);
      }
      sm = (ServiceManager)o;
      return sm;
    }

    set
    {
      CallContext.SetData(serviceManagerSlot, value);
    }
  }
}

В начале вашего процесса вы можете настроить ServiceManager для использования в текущем потоке (или текущем "логическом" потоке), а затем сохранить в свойстве "Текущий":

ServiceManager sm = new ServiceManager(thread specific properties?);
ServiceManager.Current = sm;

Теперь, когда вы извлекаете ServiceManager.Current в своем коде, он будет правильным ServiceManager для потока, в котором вы в данный момент выполняете.

Эта идея может не соответствовать вашим ожиданиям.

В своем комментарии вы говорите, что данные CallContext, которые вы пытаетесь получить в случае исключения, являются нулевыми. Это, вероятно, означает, что исключение возникает и / или перехватывается в потоке, отличном от потока, в котором были установлены данные CallContext. Вы можете попробовать использовать LogicalSetData, чтобы посмотреть, поможет ли это.

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

Удачи.

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