Pull to refresh

Comments 34

Спасибо большое, как раз мучился, вставляя Sleep в OnStart.
А почему не вставить MessageBox? ИМХО удобнее чем вначале успевать подключиться дебаггером, а потом ждать окончания Sleep.
А у вас давно NT-services имеют доступ к user-session?
Если выставить флаг MB_SERVICENOTIFICATION — все пучком.
MS говорит, что надо отказываться от этой практики, потому что в будущем она будет совсем отменена.
Возможно :). Но пока что работает.
А дайте ссылочку на эти рекомендации от MS, пожалуйста. А то что-то не найти мне подобных предостережений.
Чтобы долго не читать вам, скопирую важное:

Under Windows Vista RTM, this does not work however, in the sense that instead of the message box being redirected to the interactive desktop of a session with a user on it, or taken care of by UI0Detect as one could hope, the functions returns IDOK immediately with no user interaction whatsoever. It behaves that way even for services that are configured as interactive services and whose interactions are normally handled by UI0Detect. If your service uses MessageBox(MB_SERVICE_NOTIFICATION) to ask for user approval for some operation, it may need to be modified.
Поправлюсь: MB_SERVICE_NOTIFICATION
Ну так и все остальные способы лучше, просто нужно было отвлечься от непосредственно отладки и подумать :)
Спасибо за статью, действительно удобный способ отладки.
P.S. С Праздником! ))
Есть еще способ — предусматривать возможность запуска службы как консольного приложения. Например, в командной строке передавать /console, и если этот флаг установлен, стартовать приложение как консольное, если нет — как службу.

Преимущества такого подхода:
очень просто отлаживать, по сути дела, как обычное консольное приложение
в консоль можно выводить отладочную информацию
как альтернатива — запись сообщений в файл. Именно так дебажил. Щас попробую аттачиться к процессу.
По-хорошему, альтернативой должен слушить log4net :)
А его уж настраиваешь по своему вкусу, в консоль выводить, в файл, Event Log или еще куда.
=) у нас все сервисы содержат Program.cs который запускает консольное приложение. Внутри скопипэйсчен вызов из сервиса. по F5 сразу отлаживается
Отладка по F5 — это же мечта! Поподробнее, пожалуйста, расскажите.
Завтра ладно? как доберусь до рабочей машины…
Опоздал я немного, внизу adontz уже привел аналогичный правильный пример.
Удобно выставить сервису тип Console Application (по умолчанию Win Application стоит. с консолькой отлаживать удобнее =) )

В Program.cs в методе main код типа такого ( это поправленный копипаст. Черт, блочное выделение в студии рулит)

if (!Environment.UserInteractive)
{
ServiceBase[] servicesToRun = new ServiceBase[]
{
new Service1()
};
ServiceBase.Run(servicesToRun);
}
else
{
//Если интерактивный режим — запустим ручками конкретный сервис
Console.WriteLine(«Press any key to start Service1 interactively...»);
Console.ReadLine();

var interactivelyMailService = new Service1();
interactivelyMailService.StartInteractively();

Console.WriteLine(«Press any key to stop Service1 and exit...»);
Console.ReadLine();
interactivelyMailService.StopInteractively();
}
У сервиса определяем публичные методы для вызова его интерактивно (так понятней и красивей имхо).
И после этого F5 на проекте (если стоит запускать выделенный проект) будет работать в обчном режиме. Просто в if будете проваливаться в другую ветку и пойдете по тому же самому коду сервиса.
А как из-под отладчика запускать приложение под LоcalSystem'ом?
Не знаю, у нас такое запрещено (для сервисов заводятся определенные пользователи с нужным набором привилегий). Хотя в общем правильный вопрос — как запускать приложение по F5 не под собой, а под другим аккаунтом. Вот коллеги по цеху говорят что нельзя, но у меня есть некоторые сомнения.
Как вариант — имперсонация перед запуском, если сервис однопоточный. Что, конечно, редко бывает :(
ну вообще, стандартный код main, а-ля
    static void Main()
    {
      ServiceBase[] ServicesToRun;
      ServicesToRun = new ServiceBase[] 
			{ 
				new Service1() 
			};
      ServiceBase.Run(ServicesToRun);
    }

можно заменить на
    static void Main()
    {
#if !DEBUG
      ServiceBase[] ServicesToRun;
      ServicesToRun = new ServiceBase[] 
			{ 
				new Service1() 
			};
      ServiceBase.Run(ServicesToRun);
#else
      new Service1().Run();
#endif
    }

где Run основной метод вашего сервиса.
Тогда в конфигурации debug вы сможите отлаживаться по F5, а в релизной конфигурации собрать сервис.
Делал так же, только моя служба была на WinApi.
А разве не проще в Visual Studio выбрать пункт в меню Debug -> Attach to Process… по моему идеальный вариант?
Пользуюсь только вторым методом, все-таки он более приближен к реальным условиям. К тому же это единственный метод, с помощью которого можно отлаживать сервис удалённо.
Ты, наверное, хотел сказать первый?
if (Environment.UserInteractive)
{
using (DownloadService service = new DownloadService())
{
service.StartDownloading();
}
}
else
{
ServiceBase.Run(new DownloadService());
}
Выносил логику в обычное консольное приложение и там дебажил, всё работало на «Ура!», удобная отладка по F5 и никаких танцев с бубнами. Затем просто переносится всё в сервис.
Аналогично можно запускать код сервиса из тестового консольного приложения и тоже удобный дебаг.
А так, ваш пост собственно «ниочём».
ЗЫ кстати Remote debugger в Visual Studio шикарнейшая вещь!
Спасибо за пост и интересные комментарии!
Sign up to leave a comment.

Articles