Мой EventWaitHandle говорит: "Доступ к пути запрещен", но его не

Краткое резюме с тем, что я сейчас знаю

У меня есть EventWaitHandle, который я создал, а затем закрыл. Когда я пытаюсь воссоздать его с помощью этого ctor, "Доступ к пути... запрещен", исключение. Это исключение встречается редко, в большинстве случаев он просто воссоздает 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: Последний поток в веб-службе, чтобы открыть этот существующий дескриптор wait, COMPLETED его работу (как в завершенном соединении с клиентом)

  • 12: 00: 30,234: веб-служба получает новое соединение, еще не используя дескриптор wait. Идентификатор потока для этого соединения совпадает с идентификатором потока для последнего соединения в 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. Я, вероятно, должен был сделать то же самое для веб-службы, но я не думал, что это необходимо.

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

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

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

Ответы

Ответ 1

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

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

Хотя, я не совсем уверен, будет ли поведение оставаться неизменным в тот момент.

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

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

Ответ 2

MSDN говорит:

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

и

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

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