调试windows service的OnStart事件及调试service的一些方法汇总

259 篇文章 4 订阅

关于调试windows service, 其实这是一个老生常谈的问题了.

    通常的处理办法是, 在service运行后, 在调试器中选择attach to process.

    然而这种做法也有一定的局限性, 例如在service启动时的OnStart事件中的代码, 基本上很难调试. 往往当attach到我们的service的时候, 这部分代码已经执行过了. 于是, 有人提出, 可以另写一个project来调用这个OnStart方法, 或将OnStart方法中的代码搬到另一个project中测试. 不过, 这些方法终究不是以windows服务的方式调试的, 不能够最真实的反应service运行时的执行状况(如权限问题等环境问题).

    我的做法是, 在OnStart方法的最开始部分加上"Debugger.Launch()"的调用, 当service运行到此处时, 将会弹出一个选择调试器的对话框, 同时暂停在当前位置. 这样, 我们就做到了在代码中手动的启动调试器.

    示例代码如下:

using System.Diagnostics;
 
public partial class MyService : ServiceBase{
public MyService(){
InitializeComponent();
}
 
protected override void OnStart(string[] args){
#if DEBUG
Debugger.Launch();    //Launches and attaches a debugger to the process.
#endif
// TODO: add your initialize code here.
}
 
protected override void OnStop(){
}
}

调试WindowsService的OnStart函数是比较困难的也比较让人头疼的事情,用attach process的方法是不能调试OnStart函数的,在挂载时就已经执行过了。我在网上看了一些方法都是比较麻烦的,有的说是写一个console程序将OnStart函数里的代码先在console程序里调试通了再放到service中,感觉这个方法工作量太大了,^_^我是比较懒的,后来在网上看到一个很简单的方法是这样的

virtual void OnStart(String* args[])

Debugger::Launch();

//TODO: Add code here to start your service.

我试了这个方法后,发现还是不行,我查了msdn说Debugger::Launch()是发动和挂载到相应的进程中,他并没有breadkpoint的功能,我就想啊,要是能动态的加一个breakpoint那问题不是就解决了吗?

virtual void OnStart(String* args[])

Debugger::Launch();

Debugger::Launch();

//TODO: Add code here to start your service.这样就可以跳到这里来调试了

可是我们在程序中设置断点后在运行exe文件时是不会break的。既然Debugger有挂载的功能会不会也有动态设置断点的功能呢,^_^,去msdn看了下它的成员函数果然有一个方法Debugger::Break()可以动态设置断点,问题就轻松解决了。^_^。既然Debugger::Break();可以动态设置断点那么在调试windowsService的其他函数中也可以用到,那调试windowsService程序不是和调试winform程序一样简单了吗?^_^

 

 

virtual void OnStart(String* args[])

中的参数,是在启动服务时可以传入的。

例如:>cmd sc start servicename args[0] args[1] .........

 

 

如何對 [Windows 服務] 與 [安裝專案的自訂動作] 進行除錯

雖然 MSDN 的 HOW TO:偵錯 Windows 服務應用程式 文件有教如何除錯,但是這樣的除錯有個大缺點,就是有時後程式碼是在 OnStart 事件一開始的時候就發生問題的,有時後就會因為來不及 附加 (Attach) 程序導致無法除錯。另外,對於「安裝專案」內的「自訂動作」由於是在專案的 Installer 類別中執行的,所以要對「安裝專案」進行除錯也不太容易。我今天就來分享幾個很簡單又有效的除錯密技。

方法一:透過 System.Diagnostics.Debugger.Launch() 方法

這個方式我個人是比較喜歡,因為在開發時期要加 Code 上去很容易,你只要在想要除錯的程式碼之前加上以下程式片段,就可以要求程式暫停,並讓你選用 Visual Studio 進行除錯!

System.Diagnostics.Debugger.Launch();

當執行程式到這行時,就會出現以下視窗:

Visual Studio Just-In-Time Debugger

相對的要對「安裝專案」中的自訂動作除錯,也可以使用這個技巧,方便又有效!

在啟動 Visual Studio 的 Debugger 之後,你也可以利用 Debugger.Break() 方法自訂中斷點,你可以在希望監看的程式碼片段之前加上這個方法,或是透過一些條件判斷讓 Visual Studio Debugger 執行到這行時自動暫停讓你可以看看當下的物件狀況。

方法二:在 OnStart 事件開始前先睡個 20 秒

來不及附加程序的問題要解決也很簡單,「睡」一下就好了,讓程式在睡覺的時候趕緊利用 Visual Studio 附加該服務的程序。

System.Threading.Thread.Sleep(1000 * 20);

方法三:把 Windows Service 當成 Console Application 來執行

大家應該知道 Windows Service 是沒辦法直接按下 F5 啟動程式的,所以一般的處理方式都是 Windows Service 專案搭配一個 Windows Setup 專案進行安裝,安裝後再啟動,然後再想辦法進行除錯。

但事實上,透過一點點小修改也可以讓 Windows Service 變成 Console Application 來執行,這樣一來你就可以用 F5 啟動程式並直接進入偵錯模式了!

要達成這個目標,有 2 件事必須瞭解,瞭解後就知道我在寫什麼了。

1. 由於 Windows Service 與 Console Appliation 的程式進入點都一樣是 static void Main(),預設的 Main() 內容如下:

static void Main()
{
	ServiceBase[] ServicesToRun;
	ServicesToRun = new ServiceBase[] 
	{ 
		new Service1() 
	};
	ServiceBase.Run(ServicesToRun);
}

2. 在 Windows Service 專案中的啟動點是在 OnStart 方法,但這個方法是屬於 protected 存取層級,無法對外公開使用。

---

接下來,就要正式修改程式了,共有 3 個步驟:

1. 先修改 Service1.cs 程式 ( Windows Service 專案中的主要服務類別 )

    由於 OnStart 與 OnStop 方法被 protected 宣告保護著,無法讓使用此類別的程式直接呼叫,此時必須多寫兩個方法(method)讓使用此類別的程式可以呼叫 OnStart() 方法。

 

public void Start(string[] args)
{
    this.OnStart(args);
}

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

 

2. 接著修改 Program.cs 中的 Main() 方法 ( 也就是整個 Windows Service 專案的程式啟動點 )

 

 

    透過 Environment.UserInteractive 屬性即可得知該組件是執行於使用者互動模式中,若該組件是以 Windows Service 執行時,則此屬性將會回傳 false,我將原本的 Main() 程式改成以下程式碼:

static void Main()
{
	if (Environment.UserInteractive)
	{
		Service1 s = new Service1();

		s.Start(null);

		Console.WriteLine("服務已啟動,請按下 Enter 鍵關閉服務...");
		// 必須要透過 Console.ReadLine(); 先停止程式執行
		// 因為 Windows Service 大多是利用多 Thread 或 Timer 執行長時間的工作
		// 所以雖然主執行緒停止執行了,但服務中的執行緒已經在運行了!
		Console.ReadLine();

		s.Stop();

		Console.WriteLine("服務已關閉");
	}
	else
	{
		ServiceBase[] ServicesToRun;
		ServicesToRun = new ServiceBase[] 
		{ 
			new Service1() 
		};
		ServiceBase.Run(ServicesToRun);
	}
}

3. 變更 Windows Service 專案的 輸出類型 ( Output Type )

    開啟 Windows Service 專案屬性(Properties)視窗,將原本的 Windows Application 切換到 Console Application即可。

Project Properties - Output Type: Console Application

---

如此一來,你就可以讓同一個組件同時可以用來當 Windows Service 的主程式,以及可以直接當成 Console 程式來執行,非常的方便。

 

 

 

Service启动失败,后提示以下错误信息:

 

查了一下资料,应该是服务的逻辑代码出了问题,打开控制面板/管理工具/事件查看器 ->应用程序 里发现了如下信息:

双击错误信息,即可找到服务的错误提示!~!~

根据错误的提示信息,可检查代码。

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值