Более простой способ отладки службы Windows
есть ли более простой способ пройти через код, чем запустить службу через диспетчер управления службами Windows, а затем подключить отладчик к потоку? Это довольно громоздко, и мне интересно, есть ли более простой подход.
29 ответов
если я хочу быстро отладить службу, я просто падаю в Debugger.Break()
там. Когда эта линия будет достигнута, она вернет меня к VS. Не забудьте убрать эту линию, когда закончите.
обновление: в качестве альтернативы #if DEBUG
прагмы, вы также можете использовать .
[Conditional("DEBUG_SERVICE")]
private static void DebugMode()
{
Debugger.Break();
}
на OnStart
, просто вызовите этот метод:
public override void OnStart()
{
DebugMode();
/* ... do the rest */
}
там код будет включен только во время сборки отладки. В то время как вы на это, это может быть полезно создать отдельную конфигурацию сборки для отладки службы.
Я также думаю, что наличие отдельной "версии" для нормального выполнения и в качестве службы-это путь, но действительно ли необходимо выделять отдельный переключатель командной строки для этой цели?
не могли бы вы просто сделать:
public static int Main(string[] args)
{
if (!Environment.UserInteractive)
{
// Startup as service.
}
else
{
// Startup as application
}
}
это будет иметь "преимущество", что вы можете просто запустить приложение через doubleclick (ОК, Если вам это действительно нужно) и что вы можете просто нажать Ф5 в Visual Studio (без необходимости изменять параметры проекта, чтобы включить это ).
технически Environment.UserInteractive
проверяет, является ли WSF_VISIBLE
флаг установлен для текущей станции окна, но есть ли другая причина, по которой он вернется false
, помимо запуска в качестве (неинтерактивной) службы?
когда я создал новый проект службы несколько недель назад я нашел этот пост. Хотя есть много отличных предложений, я все еще не нашел решение, которое хотел: возможность вызова классов обслуживания"OnStart
и OnStop
методы без каких-либо изменений к классам обслуживания.
решение, которое я придумал, использует Environment.Interactive
выберите режим работы, как предложено другими ответами на этот пост.
static void Main()
{
ServiceBase[] servicesToRun;
servicesToRun = new ServiceBase[]
{
new MyService()
};
if (Environment.UserInteractive)
{
RunInteractive(servicesToRun);
}
else
{
ServiceBase.Run(servicesToRun);
}
}
The RunInteractive
helper использует отражение для вызова защищен OnStart
и OnStop
методы:
static void RunInteractive(ServiceBase[] servicesToRun)
{
Console.WriteLine("Services running in interactive mode.");
Console.WriteLine();
MethodInfo onStartMethod = typeof(ServiceBase).GetMethod("OnStart",
BindingFlags.Instance | BindingFlags.NonPublic);
foreach (ServiceBase service in servicesToRun)
{
Console.Write("Starting {0}...", service.ServiceName);
onStartMethod.Invoke(service, new object[] { new string[] { } });
Console.Write("Started");
}
Console.WriteLine();
Console.WriteLine();
Console.WriteLine(
"Press any key to stop the services and end the process...");
Console.ReadKey();
Console.WriteLine();
MethodInfo onStopMethod = typeof(ServiceBase).GetMethod("OnStop",
BindingFlags.Instance | BindingFlags.NonPublic);
foreach (ServiceBase service in servicesToRun)
{
Console.Write("Stopping {0}...", service.ServiceName);
onStopMethod.Invoke(service, null);
Console.WriteLine("Stopped");
}
Console.WriteLine("All services stopped.");
// Keep the console alive for a second to allow the user to see the message.
Thread.Sleep(1000);
}
это все, что требуется код, но я также написал прохождение с объяснениями.
обычно я инкапсулирую логику службы в отдельный класс и запускаю ее из класса "runner". Этот класс runner может быть фактическим сервисом или просто консольным приложением. Таким образом, ваше решение имеет (по крайней мере) 3 проекта:
/ConsoleRunner
/....
/ServiceRunner
/....
/ApplicationLogic
/....
иногда важно проанализировать, что происходит во время запуска сервиса. присоединение к процессу здесь не помогает, потому что вы недостаточно быстры, чтобы подключить отладчик во время запуска службы.
короткий ответ, я использую следующие 4 строки кода для этого:
#if DEBUG
base.RequestAdditionalTime(600000); // 600*1000ms = 10 minutes timeout
Debugger.Launch(); // launch and attach debugger
#endif
они вставляются в OnStart
метод следующим образом:
protected override void OnStart(string[] args)
{
#if DEBUG
base.RequestAdditionalTime(600000); // 10 minutes timeout for startup
Debugger.Launch(); // launch and attach debugger
#endif
MyInitOnstart(); // my individual initialization code for the service
// allow the base class to perform any work it needs to do
base.OnStart(args);
}
для тех, кто не делал этого раньше, я включил подробные подсказки ниже, потому что вы можете легко застрять. Следующие подсказки относятся к Windows 7x64 и Visual Studio 2010 Team Edition, но должен быть действителен и для других сред.
важно: разверните службу в "ручном" режиме (используя InstallUtil
утилита из командной строки VS или запустить проект установщика служб вы подготовились). Откройте Visual Studio до запустите службу и загрузите решение, содержащее исходный код службы-настройте дополнительные точки останова по мере необходимости в Visual Studio - затем запустите службу через Панель Управления.
из-за Debugger.Launch
код, это вызовет диалоговое окно " необработанное исключение Microsoft .NET Framework произошло в Servicename.exe." казаться. Щелчок да, debug Servicename.exe как показано на скриншоте:
после этого, escpecially в Windows 7 UAC может предложить вам ввести учетные данные администратора. Введите их и нажмите да:
после этого появляется хорошо известное окно отладчика Visual Studio Just-In-Time. Он спрашивает вас, Хотите ли вы отлаживать с помощью delected отладчика. Прежде чем нажать да, выберите, что вы не хотите открывать новый экземпляр (2 - й вариант) - новый экземпляр не будет полезен здесь, потому что исходный код не будет отображаться. Таким образом, вы выбираете экземпляр Visual Studio, который вы открыли ранее:
после нажатия да, через некоторое время Visual Studio покажет желтую стрелку прямо в строке, где Debugger.Launch
оператор и вы можете отлаживать свой код (метод MyInitOnStart
, который содержит вашу инициализацию).
клавишей Ф5 продолжает выполнение немедленно, пока не будет достигнута следующая точка останова, которую вы подготовили.
подсказка: чтобы служба продолжала работать, выберите Debug - > отсоединить все. Это позволяет запускать клиент, взаимодействующий со службой после ее правильного запуска и завершения отладки кода запуска. Если нажать Shift+Ф5 (остановить отладку), это завершит работу службы. Вместо этого, вы должны использовать Панель Управления чтобы остановить его.
Примечание это
если вы создаете выпуск, то код отладки автоматически удаляется, и служба работает нормально.
я использую
Debugger.Launch()
, который начинается и присоединяет отладчик. Я проверилDebugger.Break()
, который не работает, потому что при запуске службы еще нет отладчика (вызывающего "ошибка 1067: процесс был неожиданно завершен.").RequestAdditionalTime
устанавливает более длительный тайм-аут для запуска службы (он не задерживает сам код, но сразу же продолжит работу сDebugger.Launch
заявления). В противном случае по умолчанию для запуска службы слишком короткий и запуск службы завершается неудачей, если вы не вызываетеbase.Onstart(args)
достаточно быстро из отладчика. Практически, тайм-аут 10 минут позволяет избежать того, что вы видите сообщение"служба не отвечает..." сразу после запуска отладчика.как только вы привыкнете к нему, этот метод очень прост, потому что он просто требует от вас добавить 4 строки к существующему коду обслуживания, позволяющ вам быстро усиление контроля и отладки.
этой YouTube видео Фабио Скопел объясняет, как отлаживать службу Windows довольно красиво... фактический способ сделать это начинается в 4:45 в видео...
вот код, объясненный в видео... в вашей программе.cs-файл, добавьте материал для раздела отладки...
namespace YourNamespace
{
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
static void Main()
{
#if DEBUG
Service1 myService = new Service1();
myService.OnDebug();
System.Threading.Thread.Sleep(System.Threading.Timeout.Infinite);
#else
ServiceBase[] ServicesToRun;
ServicesToRun = new ServiceBase[]
{
new Service1()
};
ServiceBase.Run(ServicesToRun);
#endif
}
}
}
в свой файл service1.cs-файл, добавьте метод OnDebug ()...
public Service1()
{
InitializeComponent();
}
public void OnDebug()
{
OnStart(null);
}
protected override void OnStart(string[] args)
{
// your code to do something
}
protected override void OnStop()
{
}
обновление
этот подход, безусловно, самый простой:
http://www.codeproject.com/KB/dotnet/DebugWinServices.aspx
Я оставляю свой первоначальный ответ ниже для потомков.
мои службы, как правило, имеют класс, который инкапсулирует таймер, поскольку я хочу, чтобы служба регулярно проверяла, есть ли для нее какая-либо работа.
мы создаем новый класс и вызываем StartEventLoop () во время запуск службы. (Этот класс также можно легко использовать из консольного приложения.)
хороший побочный эффект этой конструкции заключается в том, что аргументы, с которыми вы настраиваете таймер, могут использоваться для задержки до того, как служба фактически начнет работать, так что у вас есть время, чтобы прикрепить отладчик вручную.
п.С. как подключить отладчик вручную к запущенному процессу...?
using System;
using System.Threading;
using System.Configuration;
public class ServiceEventHandler
{
Timer _timer;
public ServiceEventHandler()
{
// get configuration etc.
_timer = new Timer(
new TimerCallback(EventTimerCallback)
, null
, Timeout.Infinite
, Timeout.Infinite);
}
private void EventTimerCallback(object state)
{
// do something
}
public void StartEventLoop()
{
// wait a minute, then run every 30 minutes
_timer.Change(TimeSpan.Parse("00:01:00"), TimeSpan.Parse("00:30:00");
}
}
также я делал следующее (уже упоминалось в предыдущих ответах, но с флагами условного компилятора [#if], чтобы помочь избежать его запуска в сборке выпуска).
Я перестал делать это таким образом, потому что иногда мы забывали строить в выпуске и иметь перерыв отладчика в приложении, работающем на демо-версии клиента (embarrasing!).
#if DEBUG
if (!System.Diagnostics.Debugger.IsAttached)
{
System.Diagnostics.Debugger.Break();
}
#endif
static void Main()
{
#if DEBUG
// Run as interactive exe in debug mode to allow easy
// debugging.
var service = new MyService();
service.OnStart(null);
// Sleep the main thread indefinitely while the service code
// runs in .OnStart
Thread.Sleep(Timeout.Infinite);
#else
// Run normally as service in release mode.
ServiceBase[] ServicesToRun;
ServicesToRun = new ServiceBase[]{ new MyService() };
ServiceBase.Run(ServicesToRun);
#endif
}
вы также можете запустить службу через командную строку (СК.исполняемый.)
лично я бы запустил код как автономную программу на этапе отладки, и когда большинство ошибок будут устранены, перейдите к запуску как службы.
раньше я использовал переключатель командной строки, который запускал бы программу либо как службу, либо как обычное приложение. Затем в моей IDE я бы установил переключатель, чтобы я мог пройти через свой код.
с некоторыми языками вы можете фактически определить, работает ли он в среде IDE, и выполнить этот переключатель автоматически.
какой язык вы используете?
Я думаю, что это зависит от того, какую ОС вы используете, Vista намного сложнее подключить к службам из-за разделения между сеансами.
два варианта, которые я использовал в прошлом:
- используйте GFlags (в инструментах отладки для Windows) для настройки постоянного отладчика для процесса. Это существует в разделе реестра "параметры выполнения файла изображения" и невероятно полезно. Я думаю, вам нужно настроить параметры службы, чтобы включить "взаимодействие с рабочим столом". Я использую это для всех типов отладки, а не только услуги.
- другой вариант-немного отделить код, чтобы сервисная часть была взаимозаменяема с обычным запуском приложения. Таким образом, вы можете использовать простой флаг командной строки и запускать как процесс (а не Службу), что значительно упрощает отладку.
надеюсь, что это помогает.
использовать TopShelf библиотека.
создайте консольное приложение, затем настройте настройку в Main
class Program
{
static void Main(string[] args)
{
HostFactory.Run(x =>
{
// setup service start and stop.
x.Service<Controller>(s =>
{
s.ConstructUsing(name => new Controller());
s.WhenStarted(controller => controller.Start());
s.WhenStopped(controller => controller.Stop());
});
// setup recovery here
x.EnableServiceRecovery(rc =>
{
rc.RestartService(delayInMinutes: 0);
rc.SetResetPeriod(days: 0);
});
x.RunAsLocalSystem();
});
}
}
public class Controller
{
public void Start()
{
}
public void Stop()
{
}
}
чтобы отладить службу, просто нажмите F5 в visual studio.
чтобы установить службу, введите cmd " console.exe установки"
затем можно запустить и остановить службу в диспетчере служб windows.
когда я пишу службу, я помещаю всю логику службы в проект dll и создаю два "хоста", которые вызывают эту dll, один из которых является службой Windows, а другой-приложением командной строки.
Я использую приложение командной строки для отладки и прикрепляю отладчик к реальной службе только для ошибок, которые я не могу воспроизвести в приложении командной строки.
Я использую этот подход, просто помните, что вы должны проверить весь код во время работы в реальном сервисе, хотя инструмент командной строки является хорошей отладкой, это другая среда, и она не ведет себя точно так же, как реальная служба.
мне нравится иметь возможность отлаживать каждый аспект моей службы, включая любую инициализацию в OnStart (), все еще выполняя ее с полным поведением службы в рамках SCM... нет режима" консоль "или" приложение".
я делаю это, создавая вторую службу в том же проекте, чтобы использовать ее для отладки. Служба отладки при запуске как обычно (т. е. в плагине MMC служб) создает процесс хоста службы. Это дает вам процесс для присоединения отладчика, хотя ты еще не начал свою настоящую службу. После присоединения отладчика к процессу запустите свою реальную службу, и вы можете ворваться в нее в любом месте жизненного цикла службы, включая OnStart().
поскольку это требует очень минимального вторжения кода, служба отладки может быть легко включена в проект настройки службы и легко удалена из вашего производственного выпуска, комментируя одну строку кода и удаляя один проект установщик.
детали:
1) предполагая, что вы реализуете MyService
создать MyServiceDebug
. Добавьте оба в ServiceBase
массив Program.cs
вот так:
/// <summary>
/// The main entry point for the application.
/// </summary>
static void Main()
{
ServiceBase[] ServicesToRun;
ServicesToRun = new ServiceBase[]
{
new MyService(),
new MyServiceDebug()
};
ServiceBase.Run(ServicesToRun);
}
2) Добавьте реальную службу и службу отладки в установщик проекта для проекта службы:
обе службы (real и debug) включаются при добавлении выходных данных проекта службы в проект установки для службы. После установки, обе службы появятся в сервисе.MSC MMC плагин.
3) запустите службу отладки в MMC.
4) в Visual Studio присоедините отладчик к процессу, запущенному службой отладки.
5) Начните реальное обслуживание и насладитесь отладкой.
при разработке и отладке службы Windows я обычно запускаю ее как консольное приложение, добавляя параметр запуска / console и проверяя это. Делает жизнь намного проще.
static void Main(string[] args) {
if (Console.In != StreamReader.Null) {
if (args.Length > 0 && args[0] == "/console") {
// Start your service work.
}
}
}
для отладки служб Windows я объединяю GFlags и a .файл reg, созданный regedit.
- запустите GFlags, указав exe-имя и vsjitdebugger
- запустите regedit и перейдите в место, где GFlags устанавливает свои параметры
- выберите "Экспорт ключа" из меню Файл
- Сохраните этот файл где-нибудь с помощью.расширением reg
- в любое время, когда вы хотите отладить службу: дважды щелкните по .reg file
- если вы хотите, чтобы остановить отладки, запускаем второй .reg file
или сохраните следующие фрагменты и замените servicename.exe с желаемым именем исполняемого файла.
debugon.Рег:
Windows Registry Editor Version 5.00 [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\servicename.exe] "GlobalFlag"="0x00000000" "Debugger"="vsjitdebugger.exe"
debugoff.Рег:
Windows Registry Editor Version 5.00 [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\servicename.exe] "GlobalFlag"="0x00000000"
для рутинного программирования мелких вещей я сделал очень простой трюк, чтобы легко отладить мой сервис:
при запуске службы я проверяю параметр командной строки "/ debug". Если служба вызывается с этим параметром, я не делаю обычный запуск службы, а вместо этого запускаю все прослушиватели и просто отображаю messagebox "Debug in progress, нажмите ok, чтобы закончить".
поэтому, если моя служба запускается обычным способом, она начнется как Служба, если она запускается с параметр командной строки / debug он будет действовать как обычная программа.
в VS я просто добавлю / debug в качестве параметра отладки и сразу же запущу служебную программу.
таким образом, я могу легко отлаживать большинство небольших проблем. Конечно, некоторые вещи все равно нужно будет отлаживать как сервис, но для 99% этого достаточно.
Я использую вариант ответа JOP. С помощью параметров командной строки можно задать режим отладки в среде IDE со свойствами проекта или через Диспетчер служб Windows.
protected override void OnStart(string[] args)
{
if (args.Contains<string>("DEBUG_SERVICE"))
{
Debugger.Break();
}
...
}
Это довольно много после вопроса, но может быть полезно для дальнейшего использования.
Если вы можете, я бы предложил использовать отличный TopShelf. Это делает разработку и отладку службы Windows намного проще и добавляет делает развертывание несколько проще.
проверьте это: http://topshelf-project.com/
для устранения неполадок в существующей программе Службы Windows используйте отладчик.Break ()', как предлагали другие ребята.
для новой программы обслуживания Windows я бы предложил использовать метод Джеймса Майкла Хараhttp://geekswithblogs.net/BlackRabbitCoder/archive/2011/03/01/c-toolbox-debug-able-self-installable-windows-service-template-redux.aspx
просто поместите обед отладчика в любом месте и прикрепите Visualstudio при запуске
#if DEBUG
Debugger.Launch();
#endif
Также вам нужно запустить VS как Administatrator, и вам нужно разрешить, чтобы процесс мог автоматически отлаживаться другим пользователем (как объяснено здесь):
reg add "HKCR\AppID{E62A7A31-6025-408E-87F6-81AEB0DC9347}" /v AppIDFlags /t REG_DWORD /d 8 /f
используйте проект Windows Service Template C# для создания нового приложения-службыhttps://github.com/HarpyWar/windows-service-template
автоматически обнаруживаются режим консоли/службы, автоматический установщик / деинсталлятор вашей службы и несколько наиболее часто используемых функций.
вот простой метод, который я использовал для тестирования службы, без каких-либо дополнительных методов "отладки" и с интегрированными модульными тестами VS.
[TestMethod]
public void TestMyService()
{
MyService fs = new MyService();
var OnStart = fs.GetType().BaseType.GetMethod("OnStart", BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static);
OnStart.Invoke(fs, new object[] { null });
}
// As an extension method
public static void Start(this ServiceBase service, List<string> parameters)
{
string[] par = parameters == null ? null : parameters.ToArray();
var OnStart = service.GetType().GetMethod("OnStart", BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static);
OnStart.Invoke(service, new object[] { par });
}
static class Program
{
static void Main()
{
#if DEBUG
// TODO: Add code to start application here
// //If the mode is in debugging
// //create a new service instance
Service1 myService = new Service1();
// //call the start method - this will start the Timer.
myService.Start();
// //Set the Thread to sleep
Thread.Sleep(300000);
// //Call the Stop method-this will stop the Timer.
myService.Stop();
#else
ServiceBase[] ServicesToRun;
ServicesToRun = new ServiceBase[]
{
new Service1()
};
ServiceBase.Run(ServicesToRun);
#endif
}
}
У вас есть два варианта для отладки.
- создать файл журнала: лично я предпочитаю отдельный файл журнала, как текстовый файл, а не с помощью журнала приложений или журнала событий.Но это будет стоить Вам большое от имени времени, потому что его все еще трудно понять, где точное местоположение ошибки
- преобразование приложения в консольное приложение : это позволит вам, все инструменты отладки, которые мы можем использовать в VS.
см. этой сообщение в блоге, которое я создал для этой темы.
просто вставить
Debugger.Break();
где-либо в вас код.
Например ,
internal static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
private static void Main()
{
Debugger.Break();
ServiceBase[] ServicesToRun;
ServicesToRun = new ServiceBase[]
{
new Service1()
};
ServiceBase.Run(ServicesToRun);
}
}
Он ударил Debugger.Break();
при запуске программы.
лучший вариант-использовать''.
заключите код в блок if else для режима отладки и режима выпуска, как показано ниже, чтобы переключаться между режимом отладки и выпуска в visual studio,
#if DEBUG // for debug mode
**Debugger.Launch();** //debugger will hit here
foreach (var job in JobFactory.GetJobs())
{
//do something
}
#else // for release mode
**Debugger.Launch();** //debugger will hit here
// write code here to do something in Release mode.
#endif