Как вы отлаживаете службу Windows?

Я прочитал статью MSDN по этой теме. Цитировать:

Поскольку служба должна запускаться из в контексте Услуг Control Manager, а не в Visual Studio, отладка обслуживание не так прямолинейно, как отладка другой Visual Studio типы приложений. Чтобы отладить службу, вы должны начать обслуживание, а затем присоединить отладчик к процессу в который он запускает. Тогда вы можете отлаживайте свое приложение, используя все стандартная функциональность отладки Visual Studio.

Теперь моя проблема в том, что мой сервис не запускается в первую очередь. Сначала он падает и говорит:

Необработанное исключение (System.Runtime.InteropServices.COMException) произошел в MyServiceName.exe [3596])

и предлагает мне отладить его (экземпляр отладчика мгновенно вылетает, когда я выбираю его). Затем он говорит

Не удалось запустить MyServiceName службы на локальном компьютере. ошибка 1053: служба не ответила запрос запуска или управления в своевременная мода

Итак, как я могу исследовать/отлаживать причину, по которой моя служба не запускается? Дело в том, что я создал консольное приложение, которое ТОЧНО, что делает служба, и работает отлично. (Я имею в виду, что я просто скопировал метод OnStart() и основное содержимое цикла в main).

Любая помощь будет оценена.

Служба написана на С# с интенсивным использованием interop. Я использую VS2008

Ответ 1

Вы можете использовать параметр, позволяющий вашему приложению решать, начинать ли это как сервис или обычное приложение (т.е. в этом случае показывать форму или запускать службу):

static void Main(string[] args)
{
    if ((1 == args.Length) && ("-runAsApp" == args[0]))
    {
        Application.Run(new application_form());
    }
    else
    {
        System.ServiceProcess.ServiceBase[] ServicesToRun;
        ServicesToRun = new ServiceBase[] { new MyService() };
        System.ServiceProcess.ServiceBase.Run(ServicesToRun);
    }
}

Теперь, если вы передадите параметр "-runAsApp", вы можете нормально отлаживать приложение - SCM не будет передавать этот параметр, поэтому вы также можете использовать его как услугу без изменения кода (при условии, что вы выходите из ServiceBase)

Edit:

Другим отличием от служб Windows является идентификация (это может быть особенно важно с InterOp) - вы хотите убедиться, что вы тестируете под тем же именем в режиме "app", а также в сервисном режиме.

Для этого вы можете использовать олицетворение (я могу опубликовать обертку С#, если она помогает, но это может быть легко запущено) в режиме приложения, чтобы использовать тот же идентификатор, что и ваша служба Windows будет работать, например, LocalService или NetworkService.

Если требуется другое удостоверение, вы можете добавить настройки в app.config, которые позволят вам решить, использовать ли учетные данные, и если это так, какой пользователь олицетворяет - эти настройки будут активны при запуске в качестве приложения, но отключены для windows service (поскольку служба уже запущена под желаемым идентификатором):

  <appSettings>
    <add key="useCredentials" value="false"/>
    <add key="user" value="Foo"/>
    <add key="password" value="Bar"/>
  </appSettings>

Ответ 2

Обычно я просто устанавливаю точку останова вручную, а затем указываю ее на текущий открытый проект в С#. Код для установки точки останова:

System.Diagnostics.Debugger.Break();

Это должно заставить вас начать, тогда вы можете просто пройти через свой код и посмотреть, что на самом деле происходит.

Ответ 3

Я украл это у C. Lawrence Wenham, поэтому я не могу взять кредит, но вы можете программно присоединить отладчик к сервису, БЕЗ нарушив выполнение в этой точке, со следующим кодом:

System.Diagnostics.Debugger.Launch();

Поместите это в свой сервис OnStart(), как первую строку, и предложит вам выбрать экземпляр VS для прикрепления его отладчика. Оттуда система остановится в точках останова, которые вы установили, и на исключениях, выброшенных. Я бы поставил предложение #if DEBUG вокруг кода, поэтому сборка Release не будет включать его; или вы можете просто удалить его после того, как найдете эту проблему.

Ответ 4

Вы можете использовать WinDbg/NTSD (другой отладчик из пакета "Отладки для окон" ), чтобы запустить отладчик вместе с вашей службой.

Для этого откройте "gflags" (также доступный в вышеупомянутом пакете) на вкладке "Файл изображения" и установите путь к исполняемому файлу отладчика для вашего файла изображения (службы);

Если ваша служба помечена как интерактивная (возможно, только если она запущена под учетной записью SYSTEM), вы можете сразу запустить WinDbg, просто установите отладчик на что-то вроде "PATH_TO_WINDBG\windbg.exe -g -G" (нужны -g/-G, чтобы отладчик не нарушил выполнение при запуске или завершении приложения - поведение по умолчанию). Теперь при запуске вашего сервиса окно windbg должно всплывать и будет захватывать любое необработанное исключение.

Если ваша служба не является интерактивной, вы можете запустить отладчик NTSD (отладчик командной строки) в удаленном режиме и подключиться к нему из WinDbg (который может даже работать на другом ПК). Для этого установите отладчик в gflags на что-то вроде "PATH_TO_NTSD\ntsd -remote tcp: port = 6666, server = localhost" . Затем подключитесь к удаленному отладчику, запустив windbg с чем-то вроде "windbg -remote tcp: port = 6666, server = localhost" , и вы должны иметь полный контроль над другим сеансом отладки.

Что касается поиска источника самого исключения, руководство по windbg находится по этой теме, но в качестве запуска попытайтесь выполнить команду "! analysis -v" после того, как исключение было поймано - с некоторыми удачи, это вся информация, которая вам понадобится.

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

Ответ 5

Одна вещь, которую я делаю (что может быть вроде взлома), ставится Thread.Sleep(10000) в начале моего метода OnStart(). Это дает мне 10-секундное окно для присоединения моего отладчика к сервису, прежде чем он сделает что-нибудь еще.

Конечно, я удаляю инструкцию Thread.Sleep(), когда я делаю отладку.

Еще одна вещь, которую вы можете сделать, следующая:

public override void OnStart()
{
    try
    {
        // all your OnStart() logic here
    }
    catch(Exception ex)
    {
        // Log ex.Message
        if (!EventLog.SourceExists("MyApplication"))
            EventLog.CreateEventSource("MyApplication", "Application");

        EventLog.WriteEntry("MyApplication", "Failed to start: " + ex.Message);
        throw;
    }
}

При регистрации ex.Message вы можете получить более подробное сообщение об ошибке. Кроме того, вы можете просто зарегистрировать ex.ToString(), чтобы получить всю трассировку стека, и если ваши файлы .pdb находятся в том же каталоге, что и ваш исполняемый файл, он даже скажет вам, в какой строке произошла Исключение.

Ответ 6

Добавить много подробных протоколов в вашем OnStart. Это болезненная и старая школа, но она работает.

Ответ 7

Похоже, проблема связана с контекстом пользователя. Позвольте мне подтвердить, правильны ли мои предположения.

  • Когда вы говорите, что код отлично работает из консольного приложения, я предполагаю, что вы выполняете консольное приложение под тем же пользователем, с которым вы вошли.

  • Когда вы говорите, что один и тот же код сбой при вызове из службы Windows, я предполагаю, что служба запущена в учетной записи "Локальная система" на вашей машине разработки.

Если оба моих предположения верны, попробуйте выполнить следующие шаги.

  • В списке сервисов щелкните правой кнопкой мыши вашу службу, выберите свойства, а затем вкладку "Вход".

  • Выберите опцию "Эта учетная запись" и укажите существующее имя пользователя и пароль.

  • Теперь попробуйте запустить службу. Теперь он должен начинаться без ошибок.

Ниже приведена основная причина вашей ошибки

  • Если вы используете SQL Server, убедитесь, что вы не используете аутентификацию SSPI.

  • Если вы пытаетесь прочитать какую-либо общую папку\ресурс, которой у вас нет разрешения при использовании учетной записи "local system".

  • Если какая-либо из необходимых зависимостей, требуемых приложением, находится в другой папке, к которой пользователь "Локальная система" не имеет доступа к доступу.

  • Если вы используете автоматизацию VBA, которая не работает в учетной записи "Local System".

  • Попробуйте отключить брандмауэр или антивирус.

Ответ 8

Вы можете добавить несколько протоколов между вызовами взаимодействия, чтобы узнать, какой из них не удается.

Также службы по умолчанию не связаны с рабочим столом; если вы откроете апплет панели управления services.msc, получите свойства своей службы, перейдите на вкладку "Вход в систему", вы можете проверить "Разрешить услугу взаимодействовать с рабочим столом". Это может решить проблему для вас в некоторых случаях.

Ответ 9

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

Ответ 10

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

Обычно мы делаем извлечение как можно большей логики для одного класса, который имеет методы запуска и остановки. Эти методы класса - это все, что служба вызывает напрямую. Затем мы создаем приложение WinForm с двумя кнопками: одно для запуска start, другое - для вызова stop. Затем мы можем запустить приложение WinForm непосредственно из отладчика и посмотреть, что происходит.

Не самое элегантное решение, но оно работает для нас.

Ответ 11

Отметьте этот вопрос, в котором обсуждается, как поймать необработанные исключения в службе окна.

Ответ 12

Чтобы подключить отладчик к службе Windows, его необходимо запустить сначала. Причина, по которой служба не запускалась, может быть проверена в журнале событий Windows.

После этого процесс прикрепления отладчика довольно прямолинейный от Visual Studio Debug- > Attach To Process.

Ответ 13

То, что я сделал, реализовано OnStart(), чтобы выглядеть примерно так:

_myBusinessObject = new MyBusinessObject();

После создания бизнес-объекта таймеры и обработчики IPC выполняют всю настоящую (сервисную) работу.

Выполнение такого действия позволяет создать приложение Forms/WPF, которое вызывает тот же код, что и в обработчике Form_Loaded. Таким образом, отладка приложения Forms аналогична отладке службы.

Единственная проблема заключается в том, что если вы используете значения app.config, появится второй файл app.config, который должен быть обновлен.

Ответ 14

Использовать следующий код в методе OnStart:

System.Diagnostics.Debugger.Launch();

Выберите вариант Visual Studio из всплывающего сообщения