Visual Studio에서 Windows 서비스를 어떻게 디버깅합니까?


85

Visual Studio에서 Windows 서비스를 디버깅 할 수 있습니까?

나는 다음과 같은 코드를 사용했다.

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를 실행해야합니다. 그러면 목록에서 사용할 수 있습니다.
Michael

1
누군가가 팝업 메시지의 의미를 명확히 할 수 있습니까? 언제 / 어떻게 나타 납니까?
Mike

@Mike, 서비스를 설치하고 시작하면 나타납니다.
Harshit

@Mike는 대화 형 (로그인 된) 데스크톱에 팝업되고 프로세스를 디버깅 할 앱을 선택할 것인지 묻는 Windows 대화 상자입니다. 당신은 VS를 선택하면 디버거를 시작하고 프로세스에 연결됩니다
크리스 존슨에게

63

이것을 시도 할 수도 있습니다.

  1. Windows 서비스를 만들고 설치하고 시작합니다…. 즉, Windows 서비스가 시스템에서 실행되고 있어야합니다.
  2. 서비스가 실행되는 동안 디버그 메뉴 로 이동하여 프로세스 연결 (또는 이전 Visual Studio의 프로세스)을 클릭 합니다.
  3. 실행중인 서비스를 찾은 다음 모든 사용자의 프로세스 표시모든 세션의 프로세스 표시 가 선택 되어 있는지 확인한 다음 선택합니다.

여기에 이미지 설명 입력

  1. 첨부 버튼을 클릭 합니다
  2. 클릭 OK
  3. 닫기 클릭
  4. 원하는 위치에 중단 점을 설정하고 실행을 기다립니다. 코드가 해당 지점에 도달 할 때마다 자동으로 디버그됩니다.
  5. onStart () 인 경우 중단 점을 도달 가능한 위치에 놓은 다음 서비스를 중지하고 다시 시작하십시오.

(많은 인터넷 검색 끝에 "Visual Studio에서 Windows 서비스를 디버그하는 방법"에서이를 발견했습니다.)


2
VS2013 업데이트 5에서이 옵션을 볼 수 없습니다. :(
sandeep talabathula

1
하지만 당신은 관리자로 VS-2017를 실행해야
chozha의 라잔

1
나는 이것을 시도했다. 서비스가 디버거가 연결되지 않은 얻을 정지 할 때 때문에 중지시에 있지만 ONSTART에 중단 점과 일
KansaiRobot

22

서비스 프로젝트에서 작업을 수행 할 모든 코드를 별도의 프로젝트로 분리 한 다음 정상적으로 실행하고 디버그 할 수있는 테스트 애플리케이션을 만들어야합니다.

서비스 프로젝트는 서비스 부분을 구현하는 데 필요한 셸일뿐입니다.


아야 !! ctrl + C 다음 ctrl + V, 새 프로젝트를 의미합니다. 그래 나만하고있어. 별도의 프로젝트가 아닌 디버그 또는 다른 옵션에 프로세스를 연결할 수 없습니까?
PawanS 2011 년

1
물론 가능하지만 개발 과정에서 서비스 부분을 빼면 윈도우 서비스 개발이 훨씬 쉽습니다.
Lasse V. Karlsen 2011 년

음 ... 그게 좋은 방법이지만 단순히 작업을 두 배로 늘립니다. 나는 다른 방법이 존재할 것이라고 생각했습니다.
PawanS 2011 년

9
나는 그것이 어떻게 일을 "두 배로"증가 시킬지 모르겠다. 물론 추가 프로젝트를 만들고 서비스의 코드를 세 번째 프로젝트로 분리하는 데 약간의 오버 헤드가 추가되지만 그 외에는 코드 사본을 만들지 않고 이동하고, 해당 프로젝트를 참조하십시오.
Lasse V. Karlsen 2011 년

3
^ + 1. 개발 시간 측면에서 거의 제로인 서비스 관리 작업을 두 배로 늘리고 한 번만 수행하면됩니다. serice 디버깅은 고통 스럽습니다. 오히려 명령 줄로 이중 시작하도록 만드십시오. Google에서이를 허용하는 사전 정의 된 래퍼 클래스를 확인하십시오 (서비스 클래스 시작 / 중지시 리플렉션 사용). 1 시간 작업, 엄청난 절약, 순 손실 : 부정적-시간이 생깁니다.
TomTom 2011 년

14

Lasse V. Karlsen이 제안한대로 또는 디버거가 연결될 때까지 대기하는 서비스 루프를 설정합니다. 가장 간단한 것은

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

... continue with code

이렇게하면 서비스를 시작할 수 있으며 Visual Studio 내에서 "Attach to Process ..."를 선택하고 서비스에 연결하면 정상적인 배출이 재개됩니다.


어디 위의 코드를 넣어 ... 그리고에서 것은 내 서비스가 비활성화 이름이 무엇입니까 과정을 첨부해야한다
PawanS

3
우리는 또한 다음과 같은 코드를 사용했습니다 if (Environment.UserInteractive) { InteractiveRun(args); } else { Service instance = new Service(); ServiceBase[] servicesToRun = new ServiceBase[] { instance }; ServiceBase.Run(servicesToRun); }
Kirill Kovalenko 2011 년

해당 코드는 디버그하려는 코드가 실행되기 전에 가능한 한 빨리 이루어져야합니다.
Pauli Østerø 2011 년

@Pawan :에서 Start/ OnStart()같아요
abatishchev

@Kirill : 물결표를 사용하여 주석 내부의 코드를 강조 표시합니다. 예foo(bar)
abatishchev 2011 년

7

그 주어 ServiceBase.OnStartprotected가시성을, 나는 디버깅을 달성하기 위해 반사 경로를 내려 갔다.

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는 빠르게 반환되어야하므로 다른 스레드에서 수행 할 필요가 없습니다. 그러나 서비스가 다른 스레드를 시작하지 않으면 프로세스가 즉시 종료됩니다.
매트 코놀리

@MattConnolly 후자의 경우 : 필요한 경우 위의 코드를 변경하여 (정상 처리 전에) 영원히 잠자는 포 그라운드 스레드를 시작합니다.
ta.speot.is

이것은 진정한 대답이어야합니다. 아름답게 작동합니다!
lentyai

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 응용 프로그램"을 선택하고 서비스를 다시 컴파일하고 설치합니다.

여기에 이미지 설명 입력


릴리스에서 디버그 및 창 응용 프로그램의 콘솔 응용 프로그램에 출력을 설정하는 방법이 있습니까?
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클래스는 상속 ( ServiceBase)을 제외하고 내 Windows 서비스의 응용 프로그램과 정확히 동일 합니다.


같은 프로젝트에
있습니까 아니면

비슷한 클래스를 가진 2 개의 다른 프로젝트입니다. 제 경우에는 ImportFileService 클래스 만 중복되는 간단한 서비스입니다. 개발 / 테스트를 원할 때는 consoleapp을 사용하고 복사 / 붙여 넣기를합니다. Lasse V. Karlsen이 말했듯이, 이것은 디버그 프로그램이며 모든 로직 (비즈니스)은 세 번째 프로젝트에 있습니다.
kerrubin 2011 년

OnStart가 보호되지 않습니까?
Joe Phillips

네, 그렇습니다. 그래서 "상속 ( ServiceBase) 제외"라고 말한 것 입니다. 콘솔 앱에서 디버그하는 것이 더 쉽다는 것을 알지만 그것이 모든 사람을 설득하지 못하는 경우 이해합니다.
kerrubin

3

ServiceProcess.Helpers라는 훌륭한 Nuget 패키지를 사용합니다.

그리고 나는 인용한다 ...

디버거가 연결된 상태에서 실행할 때 재생 / 중지 / 일시 중지 UI를 생성하여 Windows 서비스 디버깅을 지원할뿐만 아니라 Windows 서버 환경에서 서비스를 설치하고 실행할 수도 있습니다.

이 모든 것이 한 줄의 코드로.

http://windowsservicehelper.codeplex.com/

설치 및 연결이 완료되면 Windows 서비스 프로젝트를 시작 프로젝트로 설정하고 디버거에서 시작을 클릭하기 만하면됩니다.


공유해 주셔서 감사합니다! 그것은 가장 간단한 해결책이었습니다!
Wellington Zanelli

2

System.Diagnostics.Debugger.Launch () 메서드를 사용해 볼 수도 있습니다 . 디버거 포인터를 지정된 위치로 가져가는 데 도움이되며 코드를 디버깅 할 수 있습니다.

이 단계 전에 Visual Studio 명령 프롬프트의 명령 줄 -installutil projectservice.exe를 사용 하여 service.exe를 설치하십시오.

그런 다음 제어판-> 관리 도구-> 컴퓨터 관리-> 서비스 및 응용 프로그램-> 서비스-> 서비스 이름에서 서비스를 시작합니다.


2

이 코드를 내 서비스 클래스에 추가하여 OnStop과 유사한 OnStart를 간접적으로 호출 할 수 있습니다.

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

2

/ConsoleVisual 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

이 질문을 찾았지만 명확하고 간단한 대답이 누락 된 것 같습니다.

디버거를 프로세스에 연결하고 싶지 않지만 여전히 서비스 OnStartOnStop메서드 를 호출 할 수 있기를 원합니다 . 또한 NLog의 정보를 콘솔에 기록 할 수 있도록 콘솔 응용 프로그램으로 실행되기를 원합니다 .

이 작업을 수행하는 훌륭한 가이드를 찾았습니다.

프로젝트 Output typeConsole 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. 하지만 쉽게 Forms 앱으로 만들었습니다. 저는 콘솔 앱을 정말 싫어합니다. 또한 각 서비스 이벤트에 대해 Forms Button을 쉽게 구현할 수 있습니다.
Roland

1

안타깝게도 Windows 서비스 작업을 시작할 때 디버깅을 시도하는 경우 실행중인 프로세스에 "연결"이 작동하지 않습니다. OnStart 절차 내에서 Debugger.Break ()를 사용해 보았지만 64 비트 Visual Studio 2010 컴파일 된 응용 프로그램에서 break 명령은 다음과 같은 오류를 발생시킵니다.

System error 1067 has occurred.

이 시점에서 실행 파일에 대한 레지스트리에서 "이미지 파일 실행"옵션을 설정해야합니다. 설정하는 데 5 분이 걸리며 매우 잘 작동합니다. 자세한 내용은 다음과 같은 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

http를 통해 Windows 서비스 디버그 (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();
    }
}

다음은 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 파일에 복사해야합니다.

콘솔을 시작하려면 콘솔 프로젝트를 마우스 오른쪽 버튼으로 클릭하고 디버그-> 새 인스턴스 시작을 클릭합니다.


0

서비스 클래스에 생성자를 추가하기 만하면됩니다 (아직없는 경우). 아래에서 Visual Basic .net을 확인하고 예제를 볼 수 있습니다.

Public Sub New()
   OnStart(Nothing) 
End Sub

그런 다음 프로젝트를 마우스 오른쪽 버튼으로 클릭하고 " 디버그-> 새 인스턴스 시작 "을 선택 합니다.

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