보다 쉬운 Windows 서비스 디버깅 방법


325

Windows 서비스 제어 관리자를 통해 서비스를 시작한 다음 디버거를 스레드에 연결하는 것보다 코드를 단계별로 쉽게 수행 할 수 있습니까? 그것은 번거롭고 더 직접적인 접근법이 있는지 궁금합니다.


이 사용자 음성 티켓을 만들었습니다. 그것을 위해 투표를 고려하십시오 : visualstudio.uservoice.com/forums/121579-visual-studio-ide/…
David

답변:


271

서비스를 빠르게 디버깅하려면 Debugger.Break()거기에 들어갑니다. 그 라인에 도달하면 VS로 돌아갑니다. 완료되면 해당 줄을 제거하는 것을 잊지 마십시오.

업데이트 :#if DEBUG pragma 의 대안으로 Conditional("DEBUG_SERVICE")attribute 를 사용할 수도 있습니다 .

[Conditional("DEBUG_SERVICE")]
private static void DebugMode()
{
    Debugger.Break();
}

당신에 OnStart, 그냥이 메소드를 호출

public override void OnStart()
{
     DebugMode();
     /* ... do the rest */
}

이 코드는 디버그 빌드 중에 만 활성화됩니다. 그 동안 서비스 디버깅을 위해 별도의 빌드 구성을 만드는 것이 유용 할 수 있습니다.


45
또는 Debugger.Launch ()를 사용하여 Systems.Diagnostics 네임 스페이스에 대한 using 문을 포함해야합니다.
Omar Kooheji

1
귀하의 블로그 게시물이 제대로 작동하고 하루를 저장했습니다 :) 그러나 Debugger.Break ()는 저에게 효과적이지 않았습니다. .Net은 일부 최적화 관련 이유로 DebugMode 함수를 건너 뜁니다.
비잔

3
Debugger.Break ()가 작동하지 않으면 Debugger.Launch ()가 작동합니다. (코드 255로 프로세스가 종료됩니다.)
Oliver Bock

어떻게 작동합니까? 아무 반응이 없습니다. Break () 및 Launch ()를 시도했습니다.
4thSpace

13
@ 4thSpace : 1. 서비스 용 설치 프로그램을 생성하여 서비스를 설치할 수 있습니다. 2. Debugger.Launch (); 라인을 추가하십시오. Main ()의 시작 부분에. 3. 디버그 모드에서 코드를 작성하십시오. 4. 설치된 dll을 debug-dll로 덮어 씁니다. 5. Windows 서비스 패널에서 서비스를 시작하십시오. 이제 디버거에 연결하라는 팝업 창이 나타납니다. 이 방법은 저에게 효과적이었습니다. 잘하면 당신도.
ffonz

210

또한 정상적인 실행을 위해 별도의 "버전"이 있고 서비스가 진행되는 방법이라고 생각하지만 실제로는 해당 목적을 위해 별도의 명령 줄 스위치를 사용해야합니까?

당신은 단지 할 수 없습니다 :

public static int Main(string[] args)
{
  if (!Environment.UserInteractive)
  {
    // Startup as service.
  }
  else
  {
    // Startup as application
  }
}

그것은 "이점"을 가질 것이고, 당신은 더블 클릭 (실제로 필요하다면 OK)을 통해 앱을 시작할 수 F5있고 Visual Studio에서 그 /console옵션 을 포함하도록 프로젝트 설정을 수정할 필요없이 히트 할 수 있습니다 .

기술적으로, 현재 윈도우 스테이션에 플래그가 설정 되어 Environment.UserInteractive있는지 확인 WSF_VISIBLE하지만 false(비 대화식) 서비스로 실행되는 것 외에 다른 이유가 있습니까?


큰! 이전에는 "if #debug"메소드를 사용하여 디버깅 할 경우 응용 프로그램으로 시작하고 그렇지 않으면 서비스로 시작했습니다. 이로 인해 앱을 디버깅하려는 경우 앱을 서비스로 실행할 수 없지만 솔루션이이를 해결하여 서비스 / 앱 및 릴리스 / 디버그의 네 가지 조합 모두에서 실행할 수 있습니다.
Jonas

29
두 번 클릭했을 때 프로그램을 실행하지 않으려면 (사용자가 혼란스러워 여러 인스턴스를 실행할 수 있음) System.Diagnostics.Debugger.IsAttached대신 대신 사용할 수 있습니다 Environment.UserInteractive.
Blorgbeard는

5
그러나 (비 대화식) 서비스로 실행되는 것 외에는 false를 반환하는 다른 이유가 있습니까? 콘솔에 연결되지 않은 예약 된 작업입니다.
호건

7
이 경우 명령 줄 매개 변수를 사용합니다. --install을 사용하여 서비스를 설치하고 --uninstall을 사용하여 서비스를 제거하고 --interactive를 사용하여 서비스를 응용 프로그램으로 실행하십시오. 프로젝트 옵션에 --interactive를 추가합니다 (Debugging> Command Arguments). 그래서 VS에서 쉽게 디버깅 할 수 있습니다. --interactive가 필요하므로 더블 클릭해도 원하지 않는 실행중인 인스턴스가 생성되지 않습니다. 내 2 센트 만.
Emir Akaydın

@ EmirAkaydın 예, 실제로 "backup"과 같은 명령 줄 매개 변수가 있습니다. 그러나, 나는 실제로 원했던 사실에 대해 두 번 클릭하지 및 오류 메시지가 서비스 방식 것을 시작 할 수없는 경우에 "대화"인스턴스를 가지고. 내가 생각하는 다양한 목표 ;-)
Christian.

123

몇 주 전에 새로운 서비스 프로젝트를 시작했을 때이 게시물을 찾았습니다. 많은 훌륭한 제안이 있지만 여전히 원하는 해결책을 찾지 못했습니다 . 서비스 클래스를 수정하지 않고 서비스 클래스 OnStartOnStop메소드 를 호출 할 가능성 .

내가 Environment.Interactive제안한 솔루션은 이 게시물에 대한 다른 답변에서 제안한대로 선택 실행 모드 를 사용합니다 .

static void Main()
{
    ServiceBase[] servicesToRun;
    servicesToRun = new ServiceBase[] 
    {
        new MyService()
    };
    if (Environment.UserInteractive)
    {
        RunInteractive(servicesToRun);
    }
    else
    {
        ServiceBase.Run(servicesToRun);
    }
}

RunInteractive도우미는 보호 호출 반사를 사용 OnStartOnStop방법 :

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

이것은 필요한 모든 코드이지만 설명과 함께 연습 을 작성했습니다 .


이것은 ServiceBase []를위한 좋은 확장 방법을 만듭니다. 솔루션에 여러 서비스가 있으므로 Program.cs에 대한 공통 기본 클래스를 사용하지 않고 servicesToRun.RunInteractive (args)를 호출하면됩니다. 멋진 솔루션 @Anders!
David Keaveny

3
실제로 훌륭한 솔루션입니다. David가 제안한 것처럼 ServiceBase []에 대한 간단한 확장을 만들었습니다.이 코드는 한 줄의 코드로 서비스를 실행할 수 있습니다. pastebin.com/F0fhhG2R
Funbit

4
+1 전 동료가 "EasyRunService"기본 클래스 (ServiceProcess를 상속 함)를 만들었습니다.이 클래스는 거의 동일하지만 리플렉션이 필요하지 않습니다 (OnStart가 이제 기본 클래스에 있음). 실제로 Windows 서비스 디버깅이 쉬워집니다.
sondergard

3
@ Chazt3n 프로젝트 출력 유형이 "콘솔 응용 프로그램"으로 설정되어 있는지 확인하십시오. 서비스 설치는 어떤 출력 유형을 선택하더라도 문제가되지 않습니다.
Funbit

2
여전히 훌륭한 솔루션입니다! 에 추가하는 유일한 것은 ()에 표시된 것처럼 컴파일하고 실행하기 전에 walk through프로젝트 속성으로 이동하여 출력 유형을 변경하는 것 Console Application입니다. 에서 찾으십시오 Project Properties -> Application -> Output type -> Console Application. 또한, 이것이 제대로 작동하려면 start명령을 사용하여 응용 프로그램을 실행해야했습니다 . 예 : C:\"my app name.exe" -service나를 위해 작동하지 않습니다. 대신 나는 사용했다C:\start /wait "" "my app name.exe" -service
Arvo Bowen

47

때로는 서비스를 시작하는 동안 무슨 일이 일어나고 있는지 분석하는 것이 중요합니다 . 서비스를 시작하는 동안 디버거를 연결하기에 충분히 빠르지 않기 때문에 프로세스에 연결해도 도움이되지 않습니다.

짧은 대답은 다음과 같은 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 7x64Visual Studio 2010 Team Edition에 대한 힌트 이지만 다른 환경에서도 유효합니다.


중요 : VS 명령 프롬프트 의 유틸리티를 사용하거나 준비한 서비스 설치 프로그램 프로젝트를 실행 하여 "수동"모드로 서비스를 배포하십시오 InstallUtil. 서비스를 시작 하기 전에 Visual Studio 열고 서비스 소스 코드가 포함 된 솔루션을로드하고 (Visual Studio에서 필요에 따라 추가 중단 점을 설정 한 후) 서비스 제어판을 통해 서비스를 시작하십시오 .

의 때문에 Debugger.Launch코드,이 대화 상자의 원인이됩니다 "는 마이크로 소프트 .NET 프레임 워크 예외에 발생 처리되지 않은 Servicename.exe ." 표시하는. 스크린 샷에 표시된대로 클릭하십시오 .Elevate Yes, debug Servicename.exe
FrameworkException

그 후 Windows 7 UAC에서 특히 관리자 자격 증명을 입력하라는 메시지가 표시 될 수 있습니다. 그것들을 입력하고 진행하십시오 Yes:

UAC 프롬프트

그런 다음 잘 알려진 Visual Studio Just-In-Time 디버거 창이 나타납니다. 선택한 디버거를 사용하여 디버깅 할 것인지 묻습니다. 를 클릭하기 전에 Yes, 당신이 것을 선택 새 인스턴스를 열고 싶지 않아 (2 옵션) - 소스 코드를 표시 할 수 없습니다 때문에 새로운 인스턴스가 여기에 도움이되지 것입니다. 따라서 앞에서 연 Visual Studio 인스턴스를 대신 선택하십시오. VSDebugger 프롬프트

당신이 클릭 한 후 Yes, 어디에 후 Visual Studio를하는 동안 줄에 노란색 화살표를 오른쪽으로 표시됩니다 Debugger.Launch문이며 (방법 코드를 디버깅 할 수있는 MyInitOnStart귀하의 초기화를 포함). VSDebugger 브레이크 포인트

F5준비한 다음 중단 점에 도달 할 때까지를 누르면 즉시 실행이 계속 됩니다.

힌트 : 서비스를 계속 실행하려면 디버그-> 모두 분리를 선택하십시오 . 이를 통해 올바르게 시작된 서비스와 통신하는 클라이언트를 실행할 수 있으며 시작 코드 디버깅이 완료됩니다. Shift+F5 (디버깅 중지) 를 누르면 서비스가 종료됩니다. 이를 수행하는 대신 서비스 제어판 을 사용하여 중지해야합니다.

참고

  • 릴리스 를 빌드 하면 디버그 코드가 자동으로 제거 되고 서비스가 정상적으로 실행됩니다.

  • 내가 사용하고 Debugger.Launch()있는 시작하고 디버거를 연결합니다 . 내가 테스트 한 Debugger.Break()어떤 잘으로 작업하지 않았다 더에 부착 디버거 아직 서비스의 시작이 없기 때문에,합니다 (원인 "오류 1067 : 프로세스가 예기치 않게 종료되었습니다." ).

  • RequestAdditionalTime더 이상 설정 서비스의 시작을위한 타임 아웃을 (가되어 있지 코드 자체를 지연하지만, 즉시로 계속 Debugger.Launch문). 그렇지 않으면 서비스를 시작하기위한 기본 시간 초과가 너무 짧아 base.Onstart(args)디버거에서 빠르게 호출하지 않으면 서비스 시작에 실패합니다 . 실제로 10 분의 시간 초과 는 디버거가 시작된 직후에 "서비스가 응답하지 않습니다 ..."라는 메시지 가 표시되지 않도록 합니다.

  • 일단 익숙해지면이 방법은 기존 서비스 코드 에 4 줄만 추가 하면되므로 제어 및 디버그를 빠르게 수행 할 수 있으므로 매우 쉽습니다 .


1
궁금한 점이 있으면 Debugger.Launch () 사용자 프롬프트와의 사용자 상호 작용에 시간 초과가 있는지 알고 있습니까?
Shiv

1
설명 된대로, 해당 시간 범위 내에 base.RequestAdditionalTime(600000)호출하지 않으면 서비스 제어가 10 분 동안 서비스를 종료하지 못하게합니다 base.OnStart(args). 그 외에도, 잠시 후에 관리자 자격 증명을 입력하지 않으면 UAC가 중단된다는 것을 기억합니다 (정확히 몇 초인지는 모르지만 1 분 이내에 입력해야한다고 생각합니다. 그렇지 않으면 UAC가 중단됩니다) 디버그 세션이 종료됩니다.
Matt

2
이것이 CustomCommand 메시지를 디버깅하는 가장 좋은 방법이라는 것을 알았습니다. +1.
Justin

40

내가 일반적으로하는 일은 서비스의 논리를 별도의 클래스로 캡슐화하고 '주자'클래스에서 시작하는 것입니다. 이 러너 클래스는 실제 서비스이거나 콘솔 응용 프로그램 일 수 있습니다. 따라서 솔루션에는 3 가지 프로젝트가 있습니다.

/ConsoleRunner
   /....
/ServiceRunner
   /....
/ApplicationLogic
   /....

1
나는이 접근법을 사용했지만, 이것과 위의 대답의 조합이 대단하다고 생각합니다.
RobS

27

Fabio Scopel 의이 YouTube 비디오 는 Windows 서비스를 매우 훌륭하게 디버깅하는 방법을 설명합니다. 실제 방법은 비디오의 4:45에서 시작합니다.

Program.cs 파일의 비디오에서 설명하는 코드는 다음과 같습니다 .Debug 섹션에 대한 내용을 추가하십시오.

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

작동 원리

기본적으로 보호되고 외부에서 액세스 할 수 없으므로 public void OnDebug()를 호출하는 을 만들어야합니다 OnStart(string[] args). 이 void Main()프로그램은로 #if프리 프로세서를 추가 #DEBUG합니다.

Visual Studio는 DEBUG프로젝트가 디버그 모드에서 컴파일되는지 여부를 정의합니다. 이렇게 하면 조건이 true 일 때 디버그 섹션 (아래)을 실행할 수 있습니다.

Service1 myService = new Service1();
myService.OnDebug();
System.Threading.Thread.Sleep(System.Threading.Timeout.Infinite);

콘솔 응용 프로그램처럼 실행됩니다. 문제가 해결되면 모드를 변경할 수 Release있으며 일반 else섹션은 논리를 트리거합니다.


나는이 답변을 찾고 있었는데 왜 그렇게 낮은 순위에 올랐습니까. 도움말 다른 사람 또는 아마도 많은 의견에 코드를 설명)
비 노드 Srivastav

14

최신 정보

이 방법은 가장 쉬운 방법입니다.

http://www.codeproject.com/KB/dotnet/DebugWinServices.aspx

나는 후손을 위해 원래의 대답을 아래에 둡니다.


내 서비스에는 타이머를 캡슐화하는 클래스가있는 경향이 있습니다. 서비스가 수행 할 작업이 있는지 정기적으로 서비스를 확인하기를 원합니다.

서비스를 시작하는 동안 클래스를 새로 만들고 StartEventLoop ()을 호출합니다. (이 클래스는 콘솔 앱에서도 쉽게 사용할 수 있습니다.)

이 디자인의 좋은 부작용은 서비스를 실제로 시작하기 전에 타이머를 설정하는 인수를 사용하여 지연시킬 수 있으므로 디버거를 수동으로 연결할 시간이 있다는 것입니다.

ps 실행중인 프로세스에 디버거를 수동으로 연결 하는 방법 ...?

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] 플래그 사용).

때로는 릴리스에서 빌드하는 것을 잊고 클라이언트 데모에서 실행되는 앱에서 디버거 중단이 발생하기 때문에이 방법을 중단했습니다 (당황!).

#if DEBUG
if (!System.Diagnostics.Debugger.IsAttached)
{
    System.Diagnostics.Debugger.Break();
}
#endif

// do something완료하는 데 30 분 이상이 걸리면 어떻게됩니까 ?
Vinod Srivastav

13

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
}

[코드에 대한 설명이 없습니다. 죄송합니다. 마크 다운 문제] 디버그 빌드에서 MS Visual Studio (F5)에서 정상적으로 실행해야합니다. 릴리스 빌드에서 여전히 일반 서비스로 실행됩니다.
토마스 브라 트

이를 Christian K.의 위 솔루션과 결합하여 "Environment.UserInteractive"속성을 사용하면 솔루션이 정말 깨끗하고 간단합니다.
Ben Robbins

OnStart입니다 protected. 액세스 수준을 수정할 수 없습니다 :(
Eduard Luca

10

명령 프롬프트 (sc.exe)를 통해 서비스를 시작할 수도 있습니다.

개인적으로 디버깅 단계에서 코드를 독립 실행 형 프로그램으로 실행하고 대부분의 버그가 해결되면 서비스로 실행으로 변경하십시오.


10

내가 사용했던 것은 프로그램을 서비스 또는 일반 응용 프로그램으로 시작하는 명령 줄 스위치를 사용하는 것이 었습니다. 그런 다음 IDE에서 코드를 단계별로 실행할 수 있도록 스위치를 설정했습니다.

일부 언어에서는 실제로 IDE에서 실행 중인지 감지하고이 스위치를 자동으로 수행 할 수 있습니다.

어떤 언어를 사용하고 있습니까?


9

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

        }
    }

서비스를 디버깅하려면 Visual Studio에서 F5를 누르십시오.

서비스를 설치하려면 cmd "console.exe install"을 입력하십시오.

그런 다음 Windows 서비스 관리자에서 서비스를 시작하고 중지 할 수 있습니다.


그들의 라이센싱은 이해하기가 너무 혼란 스러웠습니다
l --''''''--------- '' '' '' '' '' '' ''

그들은 Apache License afaik을 사용합니다. Topshelf는 Windows 서비스를 개발하고 디버깅하는 데 사용한 가장 쉬운 방법입니다. 사용하기 매우 쉽습니다. 콘솔 응용 프로그램으로 개발하십시오. 하나의 명령 행 스위치로 서비스로 설치하십시오. 추천.
robs

TopShelf는 많은 시간을 절약했습니다. Thx
L_7337

8

세션이 분리되어 Vista가 서비스에 연결하기가 훨씬 어렵습니다.

과거에 사용한 두 가지 옵션은 다음과 같습니다.

  • 프로세스의 영구 디버거를 설정하려면 GFlags (Windows 용 디버깅 도구)를 사용하십시오. "Image File Execution Options"레지스트리 키에 있으며 매우 유용합니다. "데스크톱과 상호 작용"을 활성화하려면 서비스 설정을 조정해야한다고 생각합니다. 서비스뿐만 아니라 모든 유형의 디버깅에 이것을 사용합니다.
  • 다른 옵션은 서비스 부분이 정상적인 앱 시작과 교환 될 수 있도록 코드를 약간 분리하는 것입니다. 이렇게하면 간단한 명령 줄 플래그를 사용하고 서비스가 아닌 프로세스로 시작할 수 있으므로 훨씬 쉽게 디버깅 할 수 있습니다.

도움이 되었기를 바랍니다.


GFlags의 경우 +1 소스 코드를 수정할 수없는 경우 (또는없는 경우)에 특히 유용합니다.
Chris Gillum

6

SCM의 프레임 워크 내에서 "콘솔"또는 "앱"모드없이 전체 서비스 동작으로 서비스를 실행하면서 OnStart ()의 초기화를 포함하여 서비스의 모든 측면을 디버깅 할 수 있기를 원합니다.

동일한 프로젝트에서 디버깅에 사용할 두 번째 서비스를 작성하여이를 수행합니다. 디버그 서비스는 평소처럼 시작될 때 (예 : 서비스 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) 서비스 프로젝트의 프로젝트 설치 프로그램에 실제 서비스 및 디버그 서비스를 추가하십시오.

여기에 이미지 설명을 입력하십시오

서비스 프로젝트 출력을 서비스 설정 프로젝트에 추가하면 두 서비스 (실제 및 디버그)가 모두 포함됩니다. 설치 후 service.msc MMC 플러그인에 두 서비스가 나타납니다.

3) MMC에서 디버그 서비스를 시작하십시오.

4) Visual Studio에서 디버거를 디버그 서비스에서 시작한 프로세스에 연결하십시오.

5) 실제 서비스를 시작하고 디버깅을 즐기십시오.


5

서비스를 작성할 때 모든 서비스 로직을 dll 프로젝트에 넣고이 dll을 호출하는 두 개의 "호스트"를 만듭니다. 하나는 Windows 서비스이고 다른 하나는 명령 줄 응용 프로그램입니다.

디버깅을 위해 명령 줄 응용 프로그램을 사용하고 명령 줄 응용 프로그램에서 재현 할 수없는 버그에 대해서만 디버거를 실제 서비스에 연결합니다.

이 접근법을 사용하면 실제 서비스에서 실행하는 동안 모든 코드를 테스트해야한다는 것을 기억하십시오. 명령 줄 도구는 다른 환경이므로 훌륭한 서비스이므로 실제 서비스처럼 정확하게 작동하지는 않습니다.


4

Windows 서비스를 개발하고 디버깅 할 때는 일반적으로 / console 시작 매개 변수를 추가하고이를 확인하여 콘솔 응용 프로그램으로 실행합니다. 인생을 훨씬 쉽게 만듭니다.

static void Main(string[] args) {
    if (Console.In != StreamReader.Null) {
        if (args.Length > 0 && args[0] == "/console") {
            // Start your service work.
        }
    }
}

서비스 별 문제를 디버깅해야합니다.
leppie

사실, 실제 서비스 프로세스에 디버거를 연결해야합니다. 그러나 대부분의 경우 버그는 어느 쪽이든 나타나고 개발이 훨씬 쉽습니다.
모리스

4

첫 번째 줄에서 Debugger.Break ()는 어떻습니까?


2

Windows 서비스를 디버깅하기 위해 GFlags와 regedit로 만든 .reg 파일을 결합했습니다.

  1. exe-name 및 vsjitdebugger를 지정하여 GFlags를 실행하십시오.
  2. regedit를 실행하고 GFlags가 옵션을 설정하는 위치로 이동하십시오.
  3. 파일 메뉴에서 "내보내기 키"를 선택하십시오
  4. 해당 파일을 .reg 확장명으로 어딘가에 저장하십시오.
  5. 서비스를 디버그하려는 경우 : .reg 파일을 두 번 클릭하십시오.
  6. 디버깅을 중지하려면 두 번째 .reg 파일을 두 번 클릭하십시오.

또는 다음 스 니펫을 저장하고 servicename.exe를 원하는 실행 파일 이름으로 바꾸십시오.


debugon.reg :

Windows 레지스트리 편집기 버전 5.00

[HKEY_LOCAL_MACHINE \ SOFTWARE \ Microsoft \ Windows NT \ CurrentVersion \ 이미지 파일 실행 옵션 \ servicename.exe]
"GlobalFlag"= "0x00000000"
"Debugger"= "vsjitdebugger.exe"

debugoff.reg :

Windows 레지스트리 편집기 버전 5.00

[HKEY_LOCAL_MACHINE \ SOFTWARE \ Microsoft \ Windows NT \ CurrentVersion \ 이미지 파일 실행 옵션 \ servicename.exe]
"GlobalFlag"= "0x00000000"

이것은 여전히 ​​Win 7 / Win 2008에서도 작동합니까? support.microsoft.com/kb/824344 의 접근 방식 이지만 대화식 서비스에 의존하고 있는데, 그들이 죽었다고 생각 했습니까? 코드에 Debugger.Break ()를 삽입하는 것이 옵션이 아닌 프로덕션 문제가 발생할 수 있기 때문에 항상 선호하는 옵션이었습니다.
piers7

1

일상적인 작은 물건 프로그래밍을 위해 서비스를 쉽게 디버깅하는 매우 간단한 트릭을 수행했습니다.

서비스를 시작할 때 명령 줄 매개 변수 "/ debug"를 확인합니다. 이 매개 변수를 사용하여 서비스를 호출하면 일반적인 서비스 시작을 수행하지 않고 모든 리스너를 시작하고 "디버그가 진행 중입니다. 확인을 눌러 종료하십시오"라는 메시지 상자 만 표시합니다.

따라서 내 서비스가 일반적인 방식으로 시작되면 서비스로 시작되고 명령 줄 매개 변수 / debug로 시작하면 일반 프로그램처럼 작동합니다.

VS에서는 디버깅 매개 변수로 / debug를 추가하고 서비스 프로그램을 직접 시작합니다.

이렇게하면 가장 작은 종류의 문제를 쉽게 디버깅 할 수 있습니다. 물론 일부는 여전히 서비스로 디버깅해야하지만 99 %면 충분합니다.



1

JOP의 답변에 변형을 사용합니다. 명령 줄 매개 변수를 사용하면 프로젝트 속성 또는 Windows 서비스 관리자를 통해 IDE에서 디버깅 모드를 설정할 수 있습니다.

protected override void OnStart(string[] args)
{
  if (args.Contains<string>("DEBUG_SERVICE"))
  {
    Debugger.Break();
  }
  ...
}


1

디버거 점심을 어디에나 놓고 시작시 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


1

다음은 추가 "디버그"방법없이 통합 된 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 });
}

1
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
    }
}

이것은 더 쉽다. 솔루션 구성 설정을 디버그로 변경하고 프로젝트 / 솔루션을 실행하고 중단 점을 추가하십시오.
Bahamut

0

디버깅을 수행하는 두 가지 옵션이 있습니다.

  1. 로그 파일 만들기 : 개인적으로 응용 프로그램 로그 또는 이벤트 로그를 사용하는 대신 텍스트 파일과 같은 별도의 로그 파일을 선호하지만 정확한 오류 위치가 어디인지 파악하기가 어렵 기 때문에 시간 대신 비용이 많이 듭니다.
  2. 응용 프로그램을 콘솔 응용 프로그램으로 변환 : VS에서 사용할 수있는 모든 디버깅 도구를 사용할 수 있습니다.

주제에 대해 작성한 블로그 게시물을 참조하십시오 .


0

붙여 넣기

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();당신이 당신의 프로그램을 실행할 때.


0

가장 좋은 옵션은 ' System.Diagnostics '네임 스페이스 를 사용하는 것 입니다.

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
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.