Мой EventWaitHandle говорит, что доступ к пути запрещен, но это не так.

Краткое резюме того, что я теперь знаю

У меня есть EventWaitHandle, который я создал, а затем закрыл. Когда я пытаюсь воссоздать его с помощью этого ctor< /strong> возникает исключение "Доступ к пути... запрещен". Это исключение встречается редко, в большинстве случаев оно просто отлично воссоздает EventWaitHandle. С ответом, опубликованным ниже (мной), я могу успешно вызвать EventWaitHandle.OpenExisting и продолжить работу в случае, если было выбрано исключение, однако ctor для EventWaitHandle должен был сделать это для меня, верно? Разве это не то, что параметр out , createdNew для?


Начальный вопрос

У меня есть следующая архитектура, служба Windows и веб-служба на одном сервере. Веб-служба сообщает службе Windows, что она должна выполнить работу, открывая и устанавливая дескриптор ожидания, которого ожидает служба Windows.

Обычно все безупречно, и я могу запускать / останавливать службу Windows без каких-либо проблем. Однако иногда, когда я останавливаю веб-службу, а затем запускаю ее снова, она совершенно не может создать дескриптор ожидания, что нарушает всю архитектуру.

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

ОБНОВЛЕНИЕ: выдано исключение и журнал проблем

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

12:00:41,250 [7] - Stopping execution due to a ThreadAbortException
System.Threading.ThreadAbortException: Thread was being aborted.
   at System.Threading.Thread.SleepInternal(Int32 millisecondsTimeout)
   at OurCompany.OurProduct.MyClass.MyClassCore.MonitorRequests()

12:00:41,328 [7] - Closing Event Wait Handle
12:00:41,328 [7] - Finally block reached


12:00:42,781 [6] - Application Start
12:00:43,031 [6] - Creating EventWaitHandle: Global\OurCompany.OurProduct.MyClass.EventWaitHandle
12:00:43,031 [6] - Creating EventWaitHandle with the security entity name of : Everyone

12:00:43,078 [6] - Unhandled Exception 
System.UnauthorizedAccessException: Access to the path 'Global\OurCompany.OurProduct.MyClass.EventWaitHandle' is denied.
   at System.IO.__Error.WinIOError(Int32 errorCode, String maybeFullPath)
   at System.Threading.EventWaitHandle..ctor(Boolean initialState, EventResetMode mode, String name, Boolean& createdNew, EventWaitHandleSecurity eventSecurity)
   at OurCompany.OurProduct.MyClassLibrary.EventWaitHandleFactory.GetNewWaitHandle(String handleName, String securityEntityName, Boolean& created)
   at OurCompany.OurProduct.MyClassLibrary.EventWaitHandleFactory.GetNewEventWaitHandle()
   at OurCompany.OurProduct.MyClass.MyClassCore..ctor()

Приблизительный график:

  • 11:53:09,937: Последний поток в веб-службе, открывающий существующий дескриптор ожидания, ЗАВЕРШИЛ свою работу (как при разрыве соединения с клиентом).

  • 12:00:30,234: веб-служба получает новое соединение, еще не используя дескриптор ожидания. Идентификатор потока для этого соединения совпадает с идентификатором потока для последнего соединения в 11:53.

  • 12:00:41,250: служба Windows останавливается

  • 12:00:42,781: Служба Windows запускается

  • 12:00:43,078: служба Windows завершила сбой.

  • 12:00:50,234: веб-служба фактически смогла открыть вызов Set() дескриптора ожидания без каких-либо исключений и т. д.

  • 12:02:00,000: я попытался перезагрузить службу Windows, то же самое исключение

  • 12:36:57,328: После произвольного ожидания 36 минут я смог запустить службу Windows без полной перезагрузки системы.


Код службы Windows

Инициализация:

// I ran into security issues so I open the global EWH
//    and grant access to Everyone
var ewhSecurity = new EventWaitHandleSecurity();

ewhSecurity.AddAccessRule(
 new EventWaitHandleAccessRule(
  "Everyone",
  EventWaitHandleRights.Synchronize | EventWaitHandleRights.Modify,
  AccessControlType.Allow));

this.ewh = new EventWaitHandle(
 false,
 EventResetMode.AutoReset,
 @"Global\OurCompany.OurProduct.MyClass.EventWaitHandle",
 out created,
 ewhSecurity);

// the variable "created" is logged

Использование:

// wait until the web service tells us to loop again
this.ewh.WaitOne();

Утилизация/закрытие:

try
{
    while (true)
    {
        // entire service logic here
    }
}
catch (Exception e)
{
    // should this be in a finally, instead?
    if (this.ewh != null)
    {
        this.ewh.Close();
    }
}

Код веб-службы

Инициализация:

// NOTE: the wait handle is a member variable on the web service
this.existing_ewh = EventWaitHandle.OpenExisting(
    @"Global\OurCompany.OurProduct.MyClass.EventWaitHandle");

Использование:

// wake up the windows service
this.existing_ewh.Set();

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


Оглядываясь назад, я, вероятно, должен был поместить Close() из блока catch в блок finally. Я, вероятно, должен был сделать то же самое для веб-сервиса, но я не думал, что это нужно.

В любом случае, может ли кто-нибудь увидеть, делаю ли я что-то конкретно неправильно? Критически важно помещать операторы close в блок finally? Нужно ли мне вручную управлять Close() из existing_ewh в веб-службе?

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

Справочный материал


person Allen Rice    schedule 23.11.2009    source источник
comment
Код ошибки? Вы имеете в виду исключение? Как только я смогу воссоздать его (я пытался, это происходит только тогда, когда я этого не хочу!) Я опубликую исключение. До тех пор я могу добавить дополнительные журналы, если кто-то хочет   -  person Allen Rice    schedule 24.11.2009


Ответы (2)


В коде, который создает дескриптор ожидания в службе Windows, в случае сбоя (как при отказе в доступе) вы можете попытаться «открыть существующий дескриптор ожидания» через

EventWaitHandle.OpenExisting(
    @"Global\OurCompany.OurProduct.MyClass.EventWaitHandle",
    EventWaitHandleRights.Synchronize | EventWaitHandleRights.Modify);

Хотя я не совсем уверен, что поведение останется прежним в этот момент.

Примечание. Буду признателен за обратную связь. Это потенциальный ответ, поэтому я отвечаю на свой вопрос, опять же, множество комментариев приветствуется!

Примечание 2. Удивительно, но применение EventWaitHandleRights.FullControl вместо указанных выше флагов (Synchronize + Modify) не работает. Вы должны использовать приведенный выше образец.

person Allen Rice    schedule 24.11.2009
comment
ВАУ! После обновления кода я смог снова продублировать проблему, и это исправило ее. Однако последующие перезагрузки службы Windows всегда приводили к тому, что служба Windows не могла создать дескриптор ожидания и всегда должна была открывать существующий. Пока функциональность не потеряна. Я подожду 30 минут и попытаюсь перезагрузить сервис, чтобы увидеть, сможет ли он его создать или ему ВСЕ ЕЩЕ нужно открыть существующий. - person Allen Rice; 24.11.2009
comment
Через 30 минут я перезагрузил службу Windows, и она смогла создать EventWaitHandle, как если бы она была новой. Параметр out в ctor указывал, что он был создан заново. - person Allen Rice; 25.11.2009

MSDN говорит:

UnauthorizedAccessException — именованное событие существует и имеет безопасность управления доступом, но у пользователя нет EventWaitHandleRights.FullControl.

а также

Вызывающий объект имеет полный контроль над вновь созданным объектом EventWaitHandle, даже если eventSecurity запрещает или не может предоставить некоторые права доступа текущему пользователю.

У вашего сервиса нет прав на получение существующего события через конструктор EventWaitHandle. (EventWaitHandleRights.FullControl не указан. И ваше именованное событие существует, пока на нем открыты дескрипторы.) Вы можете открыть существующее событие, используя EventWaitHandle.OpenExisting.

person Sergey Podobry    schedule 25.11.2009
comment
хм, интересно, я читал документацию, но просмотрел ту часть, где говорится, что названное событие существует... Так что, очевидно, оно может существовать и по замыслу будет генерировать исключение. Не совсем уверен, насколько это полезно (за исключением вашего ответа) :) Спасибо, чувак. - person Allen Rice; 25.11.2009