Як налагодити служби Windows у Visual Studio?


85

Чи можна налагодити служби Windows у Visual Studio?

Я використовував код типу

System.Diagnostics.Debugger.Break();

але це дає деяку помилку коду, наприклад:

Я отримав дві помилки події: eventID 4096 VsJITDebugger та "Служба своєчасно не відповіла на запит запуску або управління".

Відповіді:


124

Використовуйте такий код у OnStartспособі обслуговування :

System.Diagnostics.Debugger.Launch();

Виберіть варіант Visual Studio зі спливаючого повідомлення.

Примітка: Щоб використовувати його лише в режимі налагодження, #if DEBUGможна використовувати директиву компілятора, як показано нижче. Це запобіжить випадковій або налагодженню у режимі випуску на робочому сервері.

#if DEBUG
    System.Diagnostics.Debugger.Launch();
#endif

9
Не забудьте запустити VS як адміністратор. Тоді він буде доступний у списку.
Майкл

1
Хтось може пояснити, що мається на увазі під спливаючим повідомленням? Коли / як це з’являється?
Майк,

@Mike, встановіть і запустіть службу, вона з'явиться.
Harshit

@Mike, це діалогове вікно Windows, яке з’являється на інтерактивному (вхідному) робочому столі та запитує, чи хочете ви вибрати програму для налагодження процесу. Якщо вибрати VS, він запустить налагоджувач і приєднається до процесу
Кріс Джонсон,

63

Ви також можете спробувати це.

  1. Створіть службу Windows і встановіть і запустіть…. Тобто у вашій системі повинні працювати служби Windows.
  2. Поки ваша служба запущена, перейдіть до меню Налагодження , натисніть Прикріпити процес (або процес у старій Visual Studio)
  3. Знайдіть свою працюючу службу, а потім переконайтеся, що вибрано Показувати процес від усіх користувачів та Показувати процеси у всіх сеансах , якщо ні, то виберіть його.

введіть тут опис зображення

  1. Натисніть кнопку Вкласти
  2. Клацніть OK
  3. Клацніть Закрити
  4. Встановіть точку зупинки у бажаному місці та дочекайтеся виконання. Він буде налагоджувати автоматично, коли ваш код доходить до цієї точки.
  5. Пам’ятайте, поставте свою точку зупинки у доступне місце , якщо вона на onStart (), тоді зупиніться та запустіть службу знову

(Після багатого гуглювання я знайшов це в "Як налагодити служби Windows у Visual Studio".)


2
Не бачу цього варіанту у VS2013 Update 5. :(
піщана талабатула

1
Але вам потрібно запустити свій Vs-2017 як адміністратор
chozha rajan

1
Я спробував це. Він працював з точкою зупинки в onStop, але не в onStart, тому що, коли служба зупиняється, налагоджувач стає неприєднаним
KansaiRobot

22

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

Сервісний проект був би просто оболонкою, необхідною для реалізації його службової частини.


ОЙ !! ctrl + C, потім ctrl + V, я маю на увазі новий проект. Я, що роблю тільки я. Чи не можна приєднати будь-який процес до налагодження чи будь-який інший варіант, а не окремий проект.?
PawanS

1
Звичайно, це можливо, але набагато простіше розробити службу Windows, якщо ви взяли службову частину під час розробки.
Лассе В. Карлсен,

мммм ... це хороший спосіб, але це просто подвоює роботу. Я думав, що існуватиме будь-який інший спосіб.
PawanS

9
Не бачу, як це "подвоїло б" роботу. Звичайно, це додасть невелику частину накладних витрат при створенні додаткового проекту та виділенні коду в службі до третього проекту, але крім цього, ви не зробите копію коду, а перемістите його, та посилання на цей проект.
Лассе В. Карлсен,

3
^ + 1. Це подвоює роботу до управління послугою, яка є майже нульовою з точки зору часу розробки, і ви робите це лише один раз. Налагодження сервісу є БОЛЬШИМ - скоріше зробіть його подвійним запуском як командний рядок. Перевірте google на наявність попередньо визначених класів обгортки, що дозволяють це робити (вони використовують відображення для імітації запуску / зупинки без класу обслуговування). одна година роботи, тонни економії, чисті збитки: негативні - ви виграєте час.
TomTom

14

Або те, що запропоновано Лассе В. Карлсеном, або налаштуйте цикл у вашій службі, який буде чекати, поки приєднається налагоджувач. Найпростішим є

while (!Debugger.IsAttached)
{
    Thread.Sleep(1000);
}

... continue with code

Таким чином ви можете запустити службу, а всередині Visual Studio ви оберете "Вкласти до процесу ..." та приєднаєтесь до своєї служби, яка потім відновить нормальне виконання.


куди мені покласти вищевказаний код ... і в процесі приєднання я отримую свою послугу з іменем disable
PawanS

3
ми також використовували такий код if (Environment.UserInteractive) { InteractiveRun(args); } else { Service instance = new Service(); ServiceBase[] servicesToRun = new ServiceBase[] { instance }; ServiceBase.Run(servicesToRun); }
Кирило Коваленко

цей код повинен бути якомога раніше, перш ніж будь-який код зможе запустити той, який ви хочете налагодити.
Pauli Østerø

@Pawan: В Start/ OnStart()я здогадуюсь
абатищев

@Kirill: Використовуйте тильди для виділення коду всередині коментарів, наприкладfoo(bar)
abatishchev

7

Враховуючи те, що ServiceBase.OnStartмає protectedвидимість, я пішов шляхом відображення, щоб досягти налагодження.

private static void Main(string[] args)
{
    var serviceBases = new ServiceBase[] {new Service() /* ... */ };

#if DEBUG
    if (Environment.UserInteractive)
    {
        const BindingFlags bindingFlags =
            BindingFlags.Instance | BindingFlags.NonPublic;

        foreach (var serviceBase in serviceBases)
        {
            var serviceType = serviceBase.GetType();
            var methodInfo = serviceType.GetMethod("OnStart", bindingFlags);

            new Thread(service => methodInfo.Invoke(service, new object[] {args})).Start(serviceBase);
        }

        return;
    }
#endif

    ServiceBase.Run(serviceBases);
}

Зверніть увагу, що Threadза замовчуванням це нитка переднього плану. returnЯкщо Mainпід час запуску потоків фальшивих служб процес не завершиться.


Оскільки OnStart повинен повернутися швидко, вам не потрібно робити це в іншому потоці. Однак якщо служба не запустить інший потік, ваш процес негайно вийде.
Matt Connolly

@MattConnolly Щодо останнього: за необхідності я змінюю наведений вище код, щоб розпочати потік переднього плану, який вічно працює (до звичайної обробки).
ta.speot.is

Це має бути справжньою відповіддю. Працює красиво!
лентяй

4

Стаття Microsoft пояснює , як налагодити службу Windows , тут і то , що частина будь-якого людина може пропустити , якщо вони його налагодження шляхом приєднання до процесу.

Нижче мій робочий код. Я дотримувався підходу, запропонованого Microsoft.

Додайте цей код до program.cs:

static void Main(string[] args)
{
    // 'If' block will execute when launched through Visual Studio
    if (Environment.UserInteractive)
    {
        ServiceMonitor serviceRequest = new ServiceMonitor();
        serviceRequest.TestOnStartAndOnStop(args);
    }
    else // This block will execute when code is compiled as a Windows application
    {
        ServiceBase[] ServicesToRun;
        ServicesToRun = new ServiceBase[]
        {
            new ServiceMonitor()
        };
        ServiceBase.Run(ServicesToRun);
    }
}

Додайте цей код до класу ServiceMonitor.

internal void TestOnStartAndOnStop(string[] args)
{
    this.OnStart(args);
    Console.ReadLine();
    this.OnStop();
}

Тепер перейдіть до Властивості проекту , виберіть вкладку «Програма» та виберіть Тип виводу як «Консольне додаток» під час налагодження або «Застосування Windows», коли закінчите з налагодженням, перекомпілюйте та встановіть свою службу.

Введіть тут опис зображення


1
чи є спосіб встановити вихідні дані для консольної програми у налагодженні та віконної програми у випуску?
kofifus

3

Ви можете зробити консольний додаток. Я використовую цю mainфункцію:

    static void Main(string[] args)
    {
        ImportFileService ws = new ImportFileService();
        ws.OnStart(args);
        while (true)
        {
            ConsoleKeyInfo key = System.Console.ReadKey();
            if (key.Key == ConsoleKey.Escape)
                break;
        }
        ws.OnStop();
    }

Мій ImportFileServiceклас точно такий же, як і в додатку моєї служби Windows, за винятком спадкоємця ( ServiceBase).


це на тому самому проекті, чи я інший проект для цього консольного додатка
PawanS

Це 2 різні проекти з подібними класами. У моєму випадку це простий сервіс із дублікатами лише класу ImportFileService. Коли я хочу розробити / протестувати, я використовую consoleapp, а потім копіюю / вставляю. Як сказав Лассе В. Карлсен, це програма налагодження, вся логіка (бізнес) лежить на третьому проекті.
kerrubin

Чи не захищений OnStart?
Джо Філліпс,

Так, є. Ось чому я сказав "крім спадкоємця ( ServiceBase).". Мені легше налагоджувати в додатку Console, але я розумію, якщо це не переконує всіх.
керрубін

3

Я використовую чудовий пакет Nuget під назвою ServiceProcess.Helpers.

І я цитую ...

Це допомагає налагоджувати служби Windows, створюючи користувальницький інтерфейс відтворення / зупинки / паузи під час роботи з приєднаним налагоджувачем, але також дозволяє встановлювати та запускати службу в середовищі сервера Windows.

Все це з одним рядком коду.

http://windowsservicehelper.codeplex.com/

Після встановлення та підключення все, що вам потрібно зробити, це встановити проект служби Windows як стартовий проект і натиснути кнопку Пуск у вашому налагоджувачі.


Дякую, що поділились! Це було на сьогоднішній день найпростішим рішенням!
Веллінгтон Занеллі,

2

Ви також можете спробувати метод System.Diagnostics.Debugger.Launch () . Це допомагає перевести покажчик налагоджувача у вказане місце, а потім ви зможете налагодити свій код.

Перед цим кроком встановіть службу service.exe за допомогою командного рядка командного рядка Visual Studio - installlutil projectservice.exe

Потім запустіть службу з Панелі керування -> Адміністративні засоби -> Управління комп'ютером -> Служба та додаток -> Послуги -> Ім'я вашої служби


2

Я щойно додав цей код до свого класу обслуговування, щоб я міг побічно викликати OnStart, подібний до OnStop.

    public void MyOnStart(string[] args)
    {
        OnStart(args);
    }

2

Я використовую /Consoleпараметр у налагодженні проекту Visual Studio → Параметри запускуАргументи командного рядка :

public static class Program
{
    [STAThread]
    public static void Main(string[] args)
    {
         var runMode = args.Contains(@"/Console")
             ? WindowsService.RunMode.Console
             : WindowsService.RunMode.WindowsService;
         new WinodwsService().Run(runMode);
    }
}


public class WindowsService : ServiceBase
{
    public enum RunMode
    {
        Console,
        WindowsService
    }

    public void Run(RunMode runMode)
    {
        if (runMode.Equals(RunMode.Console))
        {
            this.StartService();
            Console.WriteLine("Press <ENTER> to stop service...");
            Console.ReadLine();

            this.StopService();
            Console.WriteLine("Press <ENTER> to exit.");
            Console.ReadLine();
        }
        else if (runMode.Equals(RunMode.WindowsService))
        {
            ServiceBase.Run(new[] { this });
        }
    }

    protected override void OnStart(string[] args)
    {
        StartService(args);
    }

    protected override void OnStop()
    {
        StopService();
    }

    /// <summary>
    /// Logic to Start Service
    /// Public accessibility for running as a console application in Visual Studio debugging experience
    /// </summary>
    public virtual void StartService(params string[] args){ ... }

    /// <summary>
    /// Logic to Stop Service
    /// Public accessibility for running as a console application in Visual Studio debugging experience
    /// </summary>
    public virtual void StopService() {....}
}

2

Я знайшов це запитання, але думаю, що чіткої та простої відповіді бракує.

Я не хочу приєднувати свій налагоджувач до процесу, але все одно хочу мати можливість викликати службу OnStartта OnStopметоди. Я також хочу, щоб він працював як консольний додаток, щоб я міг реєструвати інформацію з NLog на консоль.

Я знайшов ці чудові путівники, які роблять це:

Почніть із зміни проектів Output typeна Console Application.

Введіть тут опис зображення

Змініть свій, Program.csщоб виглядати так:

static class Program
{
    /// <summary>
    /// The main entry point for the application.
    /// </summary>
    static void Main()
    {
        // Startup as service.
        ServiceBase[] ServicesToRun;
        ServicesToRun = new ServiceBase[]
        {
            new Service1()
        };

        if (Environment.UserInteractive)
        {
            RunInteractive(ServicesToRun);
        }
        else
        {
            ServiceBase.Run(ServicesToRun);
        }
    }
}

Потім додайте наступний метод, щоб дозволити службам працювати в інтерактивному режимі.

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);
}

Великий кодекс! Простий, ефективний. +1. Але так само просто я зробив це додаток Форми. Я дуже ненавиджу консольні програми. Крім того, ви можете легко застосувати кнопку форми для кожної події служби.
Роланд,

1

На жаль, якщо ви намагаєтеся щось налагодити на самому початку операції служби Windows, "приєднання" до запущеного процесу не буде працювати. Я спробував використовувати Debugger.Break () у процедурі OnStart, але з 64-розрядною програмою, скомпільованою Visual Studio 2010, команда break просто видає таку помилку:

System error 1067 has occurred.

На цей момент вам потрібно встановити опцію "Виконання файлу зображення" у вашому реєстрі для вашого виконуваного файлу. Налаштування займає п’ять хвилин, і це працює дуже добре. Ось стаття Microsoft, де є деталі:

Як: Запустити налагоджувач автоматично


1

Спробуйте власний командний рядок події після побудови Visual Studio .

Спробуйте додати це в післязбірці:

@echo off
sc query "ServiceName" > nul
if errorlevel 1060 goto install
goto stop

:delete
echo delete
sc delete "ServiceName" > nul
echo %errorlevel%
goto install

:install
echo install
sc create "ServiceName" displayname= "Service Display Name" binpath= "$(TargetPath)" start= auto > nul
echo %errorlevel%
goto start

:start
echo start
sc start "ServiceName" > nul
echo %errorlevel%
goto end

:stop
echo stop
sc stop "ServiceName" > nul
echo %errorlevel%
goto delete

:end

Якщо помилка збірки з повідомленням на кшталт Error 1 The command "@echo off sc query "ServiceName" > nulтак далі, Ctrl+ Cто Ctrl+ Vповідомлення про помилку в блокнот і подивитися на останнє речення повідомлення.

Це могло б сказати exited with code x. Шукайте тут код із поширеною помилкою та дізнайтеся, як його вирішити.

1072 -- Marked for deletion → Close all applications that maybe using the service including services.msc and Windows event log.
1058 -- Can't be started because disabled or has no enabled associated devices → just delete it.
1060 -- Doesn't exist → just delete it.
1062 -- Has not been started → just delete it.
1053 -- Didn't respond to start or control → see event log (if logged to event log). It may be the service itself throwing an exception.
1056 -- Service is already running → stop the service, and then delete.

Детальніше про коди помилок тут .

І якщо помилка збірки з таким повідомленням,

Error    11    Could not copy "obj\x86\Debug\ServiceName.exe" to "bin\Debug\ServiceName.exe". Exceeded retry count of 10. Failed.    ServiceName
Error    12    Unable to copy file "obj\x86\Debug\ServiceName.exe" to "bin\Debug\ServiceName.exe". The process cannot access the file 'bin\Debug\ServiceName.exe' because it is being used by another process.    ServiceName

відкрийте cmd, а потім спробуйте вбити його спочатку за допомогою taskkill /fi "services eq ServiceName" /f

Якщо все добре, F5має бути достатньо для його налагодження.


0

У OnStartметоді виконайте наступне.

protected override void OnStart(string[] args)
{
    try
    {
        RequestAdditionalTime(600000);
        System.Diagnostics.Debugger.Launch(); // Put breakpoint here.

        .... Your code
    }
    catch (Exception ex)
    {
        .... Your exception code
    }
}

Потім запустіть командний рядок від імені адміністратора та введіть наступне:

c:\> sc create test-xyzService binPath= <ProjectPath>\bin\debug\service.exe type= own start= demand

У наведеному вище рядку буде створено test-xyzService у списку послуг.

Для запуску служби вам буде запропоновано приєднатися до дебюту у Visual Studio чи ні.

c:\> sc start text-xyzService

Щоб зупинити послугу:

c:\> sc stop test-xyzService

Щоб видалити або видалити:

c:\> sc delete text-xyzService

0

Налагодження служби Windows за допомогою http (перевірено за допомогою VS 2015 Update 3 та .Net FW 4.6)

По-перше, вам потрібно створити проект консолі у своєму рішенні VS (Додати -> Новий проект -> Консольна програма).

У новому проекті створіть клас "ConsoleHost" із таким кодом:

class ConsoleHost : IDisposable
{
    public static Uri BaseAddress = new Uri(http://localhost:8161/MyService/mex);
    private ServiceHost host;

    public void Start(Uri baseAddress)
    {
        if (host != null) return;

        host = new ServiceHost(typeof(MyService), baseAddress ?? BaseAddress);

        //binding
        var binding = new BasicHttpBinding()
        {
            Name = "MyService",
            MessageEncoding = WSMessageEncoding.Text,
            TextEncoding = Encoding.UTF8,
            MaxBufferPoolSize = 2147483647,
            MaxBufferSize = 2147483647,
            MaxReceivedMessageSize = 2147483647
        };

        host.Description.Endpoints.Clear();
        host.AddServiceEndpoint(typeof(IMyService), binding, baseAddress ?? BaseAddress);

        // Enable metadata publishing.
        var smb = new ServiceMetadataBehavior
        {
            HttpGetEnabled = true,
            MetadataExporter = { PolicyVersion = PolicyVersion.Policy15 },
        };

        host.Description.Behaviors.Add(smb);

        var defaultBehaviour = host.Description.Behaviors.OfType<ServiceDebugBehavior>().FirstOrDefault();
        if (defaultBehaviour != null)
        {
            defaultBehaviour.IncludeExceptionDetailInFaults = true;
        }

        host.Open();
    }

    public void Stop()
    {
        if (host == null)
            return;

        host.Close();
        host = null;
    }

    public void Dispose()
    {
        this.Stop();
    }
}

І це код для класу Program.cs:

public static class Program
{
    [STAThread]
    public static void Main(string[] args)
    {
        var baseAddress = new Uri(http://localhost:8161/MyService);
        var host = new ConsoleHost();
        host.Start(null);
        Console.WriteLine("The service is ready at {0}", baseAddress);
        Console.WriteLine("Press <Enter> to stop the service.");
        Console.ReadLine();
        host.Stop();
    }
}

Такі конфігурації, як рядки підключення, слід копіювати у файл App.config проекту Console.

Щоб прискорити роботу консолі, клацніть правою кнопкою миші проект Консолі та натисніть кнопку Налагодження -> Почати новий екземпляр.


0

Просто додайте конструктор до свого класу обслуговування (якщо у вас його ще немає). Нижче ви можете перевірити та приклад для visual basic .net.

Public Sub New()
   OnStart(Nothing) 
End Sub

Після цього клацніть правою кнопкою миші на проекті та виберіть " Налагодження -> Почати новий екземпляр ".

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.