Как отлаживать службы Windows в Visual Studio?


можно ли отлаживать службы Windows в Visual Studio?

я использовал код типа

System.Diagnostics.Debugger.Break();

но это дает ошибка в коде типа:

Я получил два события ошибка: eventID 4096 VsJITDebugger и " сервис сделал не реагировать на запуск или управление запрос своевременно."

16 69

16 ответов:

используйте следующий код в сервисе OnStart способ:

System.Diagnostics.Debugger.Launch();

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

Примечание: чтобы использовать его только в режиме отладки, a #if DEBUG директива компилятора может быть использована следующим образом. Это предотвратит случайную или отладку в режиме выпуска на рабочем сервере.

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

вы также можете попробовать это.

  1. создайте свою службу Windows и установите и запустите.... То есть службы Windows должны быть запущены в вашей системе.
  2. пока ваша служба работает, перейдите в Debug, нажмите кнопку Прикрепить Процесс (или процесс в старой Visual Studio)
  3. найдите свою запущенную службу, а затем убедитесь, что Отображать процессы всех пользователей и показать процессы во всех сеансах is выбран, если нет, то выберите его.

enter image description here

  1. выберите прикрепить
  2. клик ОК
  3. клик закрыть
  4. установите точку останова в нужное место и дождитесь выполнения. Он будет отлаживать автоматически всякий раз, когда ваш код достигает этой точки.
  5. помните, поставьте точку останова на доступном месте, если onStart(), тогда остановите и запустите службу снова

(после многих поисковых запросов я нашел это в разделе "как отлаживать службы Windows в Visual Studio".)

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

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

либо это, как предложил Лассе В. Карлсен, либо настроить цикл в вашем сервисе, который будет ждать подключения отладчика. Самый простой -

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

... continue with code

таким образом, вы можете запустить службу и внутри Visual Studio выбрать "прикрепить к процессу...- и присоединитесь к своей службе, которая затем возобновит нормальное существование.

учитывая, что 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 по умолчанию является потоком переднего плана. returning от Main в то время как потоки faux-service выполняются, процесс не завершается.

в статье 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 " при отладке, перекомпилируйте и установите свою службу.

Enter image description here

вы можете сделать консольное приложение. Я использую это 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).

вы также можете попробовать

Я просто добавил этот код в свой класс обслуживания, чтобы я мог косвенно вызвать OnStart, аналогичный для OnStop.

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

Я использую /Console параметр в проекте Visual Studio DebugПараметры Запускааргументы командной строки:

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() {....}
}

к сожалению, если вы пытаетесь отладить что-то в самом начале операции Службы Windows, "прикрепление" к запущенному процессу не будет работать. Я попытался использовать отладчик.Break() в onStart procecdure, но с 64-разрядным скомпилированным приложением Visual Studio 2010, команда break просто выдает такую ошибку:

System error 1067 has occurred.

в этот момент вам нужно настроить параметр "выполнение файла изображения" в вашем реестре для вашего исполняемого файла. Это займет пять минут, чтобы настроить, и это работает очень хорошо. Вот статья Microsoft, где подробности:

как запустить отладчик автоматически

попробуйте Visual Studio очень собственный командная строка события после сборки.

попробуйте добавить это в post-build:

@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 должно быть достаточно, чтобы отладить его.

на 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

Я нашел этот вопрос, но я думаю, что четкий и простой ответ отсутствует.

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

Я нашел эти блестящие руководства, которые делают это:

начните с изменения проектов Output type до Console Application.

Enter image description here

изменить 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);
}

отладка службы Windows через http (протестировано с обновлением VS 2015 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();
    }
}

а это код для программы.класс ЗС:

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

конфигурации, такие как connectionstrings должны быть скопированы в приложении.конфигурационный файл Консольный проект.

чтобы запустить консоль, щелкните righ-проект консоли и выберите Debug -> Start new instance.

Я использую большой пакет Nuget под названием ServiceProcess.Прислуга.

и я цитирую...

Он помогает отладке служб windows путем создания пользовательского интерфейса play/stop/pause при запуске с подключенным отладчиком, но также позволяет устанавливать и запускать службу в среде windows server.

все это с одной строкой кода.

http://windowsservicehelper.codeplex.com/

после установки и подключения всего, что вам нужно do-это настройка проекта службы windows в качестве проекта запуска и нажмите кнопку Пуск на отладчике.