[C#] 보다 쉬운 Windows 서비스 디버깅 방법
Windows 서비스 제어 관리자를 통해 서비스를 시작한 다음 디버거를 스레드에 연결하는 것보다 코드를 단계별로 쉽게 수행 할 수 있습니까? 그것은 번거롭고 더 직접적인 접근법이 있는지 궁금합니다.
답변
서비스를 빠르게 디버깅하려면 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 */
}
이 코드는 디버그 빌드 중에 만 활성화됩니다. 그 동안 서비스 디버깅을 위해 별도의 빌드 구성을 만드는 것이 유용 할 수 있습니다.
답변
또한 정상적인 실행을 위해 별도의 “버전”이 있고 서비스가 진행되는 방법이라고 생각하지만 실제로는 해당 목적을 위해 별도의 명령 줄 스위치를 사용해야합니까?
당신은 단지 할 수 없습니다 :
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
(비 대화식) 서비스로 실행되는 것 외에 다른 이유가 있습니까?
답변
몇 주 전에 새로운 서비스 프로젝트를 시작했을 때이 게시물을 찾았습니다. 많은 훌륭한 제안이 있지만 여전히 원하는 해결책을 찾지 못했습니다 . 서비스 클래스를 수정하지 않고 서비스 클래스 OnStart
및 OnStop
메소드 를 호출 할 가능성 .
내가 Environment.Interactive
제안한 솔루션은 이 게시물에 대한 다른 답변에서 제안한대로 선택 실행 모드 를 사용합니다 .
static void Main()
{
ServiceBase[] servicesToRun;
servicesToRun = new ServiceBase[]
{
new MyService()
};
if (Environment.UserInteractive)
{
RunInteractive(servicesToRun);
}
else
{
ServiceBase.Run(servicesToRun);
}
}
RunInteractive
도우미는 보호 호출 반사를 사용 OnStart
및 OnStop
방법 :
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);
}
이것은 필요한 모든 코드이지만 설명과 함께 연습 을 작성했습니다 .
답변
때로는 서비스를 시작하는 동안 무슨 일이 일어나고 있는지 분석하는 것이 중요합니다 . 서비스를 시작하는 동안 디버거를 연결하기에 충분히 빠르지 않기 때문에 프로세스에 연결해도 도움이되지 않습니다.
짧은 대답은 다음과 같은 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 7×64 및 Visual Studio 2010 Team Edition에 대한 힌트 이지만 다른 환경에서도 유효합니다.
중요 : VS 명령 프롬프트 의 유틸리티를 사용하거나 준비한 서비스 설치 프로그램 프로젝트를 실행 하여 “수동”모드로 서비스를 배포하십시오 InstallUtil
. 서비스를 시작 하기 전에 Visual Studio 를 열고 서비스 소스 코드가 포함 된 솔루션을로드하고 (Visual Studio에서 필요에 따라 추가 중단 점을 설정 한 후) 서비스 제어판을 통해 서비스를 시작하십시오 .
의 때문에 Debugger.Launch
코드,이 대화 상자의 원인이됩니다 “는 마이크로 소프트 .NET 프레임 워크 예외에 발생 처리되지 않은 Servicename.exe .” 표시하는. 스크린 샷에 표시된대로 클릭하십시오 . Yes, debug Servicename.exe
그 후 Windows 7 UAC에서 특히 관리자 자격 증명을 입력하라는 메시지가 표시 될 수 있습니다. 그것들을 입력하고 진행하십시오 Yes:
그런 다음 잘 알려진 Visual Studio Just-In-Time 디버거 창이 나타납니다. 선택한 디버거를 사용하여 디버깅 할 것인지 묻습니다. 를 클릭하기 전에 Yes, 당신이 것을 선택 새 인스턴스를 열고 싶지 않아 (2 옵션) – 소스 코드를 표시 할 수 없습니다 때문에 새로운 인스턴스가 여기에 도움이되지 것입니다. 따라서 앞에서 연 Visual Studio 인스턴스를 대신 선택하십시오.
당신이 클릭 한 후 Yes, 어디에 후 Visual Studio를하는 동안 줄에 노란색 화살표를 오른쪽으로 표시됩니다 Debugger.Launch
문이며 (방법 코드를 디버깅 할 수있는 MyInitOnStart
귀하의 초기화를 포함).
F5준비한 다음 중단 점에 도달 할 때까지를 누르면 즉시 실행이 계속 됩니다.
힌트 : 서비스를 계속 실행하려면 디버그-> 모두 분리를 선택하십시오 . 이를 통해 올바르게 시작된 서비스와 통신하는 클라이언트를 실행할 수 있으며 시작 코드 디버깅이 완료됩니다. Shift+F5 (디버깅 중지) 를 누르면 서비스가 종료됩니다. 이를 수행하는 대신 서비스 제어판 을 사용하여 중지해야합니다.
참고 그
-
릴리스 를 빌드 하면 디버그 코드가 자동으로 제거 되고 서비스가 정상적으로 실행됩니다.
-
내가 사용하고
Debugger.Launch()
있는 시작하고 디버거를 연결합니다 . 내가 테스트 한Debugger.Break()
어떤 잘으로 작업하지 않았다 더에 부착 디버거 아직 서비스의 시작이 없기 때문에,합니다 (원인 “오류 1067 : 프로세스가 예기치 않게 종료되었습니다.” ). -
RequestAdditionalTime
더 이상 설정 서비스의 시작을위한 타임 아웃을 (가되어 있지 코드 자체를 지연하지만, 즉시로 계속Debugger.Launch
문). 그렇지 않으면 서비스를 시작하기위한 기본 시간 초과가 너무 짧아base.Onstart(args)
디버거에서 빠르게 호출하지 않으면 서비스 시작에 실패합니다 . 실제로 10 분의 시간 초과 는 디버거가 시작된 직후에 “서비스가 응답하지 않습니다 …”라는 메시지 가 표시되지 않도록 합니다. -
일단 익숙해지면이 방법은 기존 서비스 코드 에 4 줄만 추가 하면되므로 제어 및 디버그를 빠르게 수행 할 수 있으므로 매우 쉽습니다 .
답변
내가 일반적으로하는 일은 서비스의 논리를 별도의 클래스로 캡슐화하고 ‘주자’클래스에서 시작하는 것입니다. 이 러너 클래스는 실제 서비스이거나 콘솔 응용 프로그램 일 수 있습니다. 따라서 솔루션에는 3 가지 프로젝트가 있습니다.
/ConsoleRunner
/....
/ServiceRunner
/....
/ApplicationLogic
/....
답변
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
섹션은 논리를 트리거합니다.
답변
최신 정보
이 방법은 가장 쉬운 방법입니다.
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