Как настроить WCF ServiceHost в службе Windows, которая может получать доступ к информации о состоянии в службе Windows

У меня есть написанная служба Windows на С#. Он работает и работает хорошо. Я добавил службу WCF в службу Windows, чтобы клиентские приложения могли подключаться к службе Windows и получать информацию о состоянии от службы Windows.

Я настроил службу WCF как одноэлементную, чтобы один и тот же экземпляр службы использовался для обработки всех запросов от всех клиентов следующим образом:
[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)]

Все клиенты могут подключаться и иметь доступ к одной и той же информации о состоянии в службе WCF. Однако я сталкиваюсь со следующим своеобразным поведением.

Пересмотрено:
я создаю экземпляр контракта службы WCF в своей службе Windows. Любая информация о состоянии, назначенная во время создания экземпляра, доступна для всех клиентов, подключающихся к службе.

Однако любая информация о состоянии, добавленная в экземпляр контракта службы позже непосредственно из службы Windows (не клиентами), не видна клиентам, подключающимся к службе. Как будто существует два экземпляра контракта службы: один для службы Windows и один для клиентов, которые подключаются к службе WCF.

Каков рекомендуемый (наилучший) способ создания экземпляра службы WCF и предоставления ему доступа к информации о состоянии, доступной в службе Windows?


person Elan    schedule 14.08.2009    source источник


Ответы (3)


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

person Steven Sudit    schedule 14.08.2009

Почему служба WCF должна иметь информацию о состоянии? Разве это не может быть сохранено в базе данных и доступно при необходимости?

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

ОБНОВЛЕНИЕ:
Хорошо, еще одна идея: в любом случае у вас всегда будет только один ServiceHost. Если вы выберете режим экземпляра «за вызов» (как это рекомендуется всеми ведущими экспертами), ServiceHost выделит пул рабочих потоков, которые затем будут обслуживать входящие запросы.

Почему служба WCF должна быть одноэлементной? Не могли бы вы использовать «за вызов» и по-прежнему получать информацию о состоянии в службе NT?

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

Если у вас есть информация с отслеживанием состояния, хранящаяся в службе NT, вам необходимо убедиться, что любой одновременный доступ будет правильно обрабатываться — это совершенно не зависит от того, является ли ваш класс обслуживания WCF одноэлементным или нет.

ОБНОВЛЕНИЕ 2:
Используя «OperationContext.Current.Host», вы можете получить доступ к ServiceHost, на котором размещается данный экземпляр службы внутри выполняемого метода службы — не уверен, что вы можете получить доступ к фактическому NT экземпляр службы. Но если вы создадите свой собственный потомок ServiceHost, который имеет дополнительное свойство «ListOfClients», вы сможете получить доступ к этому списку в любое время из любого работающего экземпляра службы.

ПОМНИТЕ ВНИМАНИЕ: поскольку в любой момент времени может обрабатываться любое количество запросов на обслуживание, чтение списка должно быть потокобезопасным, а обновление списка из службы Windows NT еще более «рискованно». и должен учитывать эти проблемы параллелизма! Заблокируйте список, если вам нужно его обновить, иначе вы получите непредсказуемые результаты.

Марк

person marc_s    schedule 14.08.2009
comment
Мне действительно не нужно, чтобы служба WCF сохраняла состояние. У меня уже есть информация о состоянии в службе Windows. Именно эту информацию я хочу, чтобы служба WCF могла предоставлять клиентам, которые ее запрашивают. Как я могу это решить? - person Elan; 14.08.2009
comment
Конечно, я мог бы решить эту проблему, сохранив информацию в базе данных. Это просто кажется излишним накладным расходом, когда информация уже доступна в службе Windows, особенно когда служба WCF размещена в контексте службы Windows. Кажется, теперь мне не нужно дополнительно хранить его и извлекать из базы данных, чтобы сделать его доступным для клиентов. В идеале я хотел бы, чтобы служба WCF предоставляла доступ к данным с отслеживанием состояния в службе Windows. - person Elan; 14.08.2009
comment
Чтобы ответить на ваш вопрос, я изначально начал назначать ссылку на список экземпляру хоста службы WCF, но теперь отойду от этого подхода, поскольку он не работает, кроме требования Singleton. - person Elan; 14.08.2009
comment
Я понимаю. Я планирую использовать позвонки, так как согласен, что это лучший подход. В основном у меня есть список клиентов, которые обнаружили сервер. Что, если бы я сделал этот список статическим в службе Windows, к которому могла бы получить доступ служба WCF? - person Elan; 14.08.2009
comment
Элан: Я думаю, у вас неправильное представление: экземпляр ServiceHost всегда будет существовать только как один экземпляр — для начала существует только ОДИН! Это НЕ то, чем вы управляете с помощью параметра InstanceContextMode. - person marc_s; 14.08.2009
comment
Спасибо за указание на это. Я пересмотрел свой первоначальный вопрос - я должен был сказать контракт на обслуживание, а не ServiceHost. При фактическом тестировании я обнаружил два экземпляра создаваемого контракта службы: члены экземпляра содержали разные данные при доступе к службе Windows по сравнению с клиентами, подключающимися к службе WCF. - person Elan; 14.08.2009

Установка InstanceContextMode.Single приведет к тому, что ServiceHost создаст один экземпляр вашей службы и будет использовать его для всех вызовов. Но похоже, что вы хотели бы создать экземпляр самостоятельно и заполнить его ссылкой на какое-то общее состояние. Если это так, это называется шаблоном «известный экземпляр» и может быть выполнено путем передачи экземпляра в конструкцию ServiceHost, например:

var svc = new MyServiceClass(state);
var host = new ServiceHost(svc, new Uri(..), ...);
...

ServiceHost будет использовать переданный вами экземпляр для всех вызовов.

Важным соображением при использовании режима одного экземпляра (независимо от того, является ли объект «общеизвестным» или созданным ServiceHost), является многопоточность. По умолчанию WCF разрешает одновременное выполнение только одного потока для каждого экземпляра службы. Таким образом, в режиме экземпляра PerCall, поскольку у вас будет несколько экземпляров службы, вы можете поддерживать несколько параллельных потоков, что улучшит пропускную способность в обычных условиях. Но в режиме одного экземпляра у вас есть только один экземпляр службы, поэтому вы можете запускать только один поток за раз. Это зависит от службы, но часто имеет смысл переключить режим параллелизма на множественный, что позволит использовать несколько одновременных потоков в экземпляре службы, но требует, чтобы реализация службы была потокобезопасной.

Несколько хороших документов здесь: http://msdn.microsoft.com/en-us/library/ms731193.aspx

person alexdej    schedule 17.10.2009