Как вы отлаживаете службу 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 из всплывающего сообщения
Ответ 15
прочитайте 2 статьи, упомянутые здесь:
http://geekswithblogs.net/BlackRabbitCoder/archive/2011/03/01/c-toolbox-debug-able-self-installable-windows-service-template-redux.aspx