按微軟的定義,服務是一個長時間啟動並執行可執行檔,它不支援使用者介面,並運行在特殊的使用者賬戶之下,也可以在沒有任何使用者登入電腦的情況下運行。預設情況下,服務運行在System賬戶之下。與一般的應用程式相比,服務自動啟動並執行,並且無需與使用者互動。
在.Net Framework中,與Windows服務相關的類位於System.ServiceProcess命名空間之下,其中,ServiceBase類提供Windows服務的基類,我們編寫的服務必須從該類派生。
ServiceBase包含四個可被重載的方法:OnStart、OnStop、OnPause以及OnContinue,顧名思義,這四個方法在服務啟動、停止、暫停以及繼續動作時被調用(對服務的控制可以通過控制台中,管理工具下的服務控制管理員實現(或直接在運行裡面輸入services.msc))。
一個承載服務的可執行檔可以包含多個服務,每一個服務對應一個從ServiceBase派生的類。應注意,運行可執行檔與啟動服務並不相同,運行可執行檔時,將調用服務類的建構函式,完成成將調用服務的OnStart方法。而啟動服務僅僅是調用服務的OnStart方法。
通過服務控制管理員(services.msc)可以實現與服務的互動,相應的,在ServiceBase中提供兩個屬性用於向管理器表明服務支援的控制動作:CanStop以及CanPauseAndContinue,當設定為True時,在管理器中服務的停止、暫停和繼續菜單可用,反之,則不可用。
另外,CanShutdown使用者表明在系統關閉時,是否向服務發送一個通知。
與Windows服務相關的另一個重要類名為:ServiceInstaller,該類用於安裝一個服務。一個ServiceBase應該對應一個ServiceInstaller。注意,服務的安裝是通過工具installutil來進行的,該工具將會調用服務可執行檔中的Install類,用於實現服務的安裝。
一般情況下,我們從Install類中派生出我們自己的安裝類,然後在建構函式中執行個體化服務對應的ServiceInstaller類(一個或多個)以及一個表示安裝進程的ServiceProcessInstaller類(該類用於控制安裝進程,如指定運行安裝進程的賬戶)。在安裝類中,我們應該指定RunInstallerAttribute屬性,這樣installutil工具才能通過反射技術找出可執行檔中存在的安裝類。
下面給出一個簡單的服務,它每隔5秒鐘嚮應用程式事件記錄中寫入一條資訊(目前時間),通過該樣本可瞭解服務的編寫及調試方法:
1、建立一個項目,名稱為TestService,項目類型為Windows Service
2、將服務代碼檔案名稱修改為TestService
3、切換到TestService的程式碼檢視,編寫代碼如下:
隱藏行號 複製代碼 ? TestService.cs
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.ServiceProcess;
using System.Text;
using System.Threading;
namespace TestService
{
public partial class TestService : ServiceBase
{
Thread thread;
public TestService()
{
InitializeComponent();
this.ServiceName = ".Net Test Service";
}
protected override void OnStart(string[] args)
{
Console.WriteLine("The Service Is Runing!");
if (thread == null)
{
this.thread = new Thread(this.ThreadRun);
}
this.thread.IsBackground = true;
this.thread.Start();
}
protected override void OnStop()
{
if (this.thread != null)
{
if (this.thread.ThreadState == System.Threading.ThreadState.Running)
{
this.thread.Abort();
}
}
}
private void ThreadRun()
{
while (true)
{
Thread.Sleep(5000);
EventLog.WriteEntry(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"));
}
}
}
}
4、建立一個類,檔案名稱為TestInstall.cs,代碼如下:
隱藏行號 複製代碼 ? TestInstall.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ServiceProcess;
using System.Configuration.Install;
using System.ComponentModel;
namespace TestService
{
[RunInstaller(true)]
public class TestInstall : Installer
{
ServiceProcessInstaller processInstall;
ServiceInstaller serviceInstall;
public TestInstall()
{
this.processInstall = new ServiceProcessInstaller();
this.serviceInstall = new ServiceInstaller();
processInstall.Account = ServiceAccount.LocalSystem;
this.serviceInstall.ServiceName = ".Net Test Service";
this.Installers.Add(this.serviceInstall);
this.Installers.Add(this.processInstall);
}
}
}
5、編譯整個解決方案
6、通過installutil命令安裝服務:
1)、進入Visual Studio 2008命令提示
2)、切換當前路徑到項目路徑的Debug目錄,如:
cd D:\Others\Develop\CSharp\TestService\TestService\bin\Debug
3)、安裝服務,命令:
installutil TestService.exe
4、啟動服務,開始 運行 輸入services.msc,我們將看到服務列表中已經存在我們的服務,名稱為.Net Test Service
5、在名稱上單擊右鍵,啟動服務
6、如何調試服務呢?確保服務啟動後,返回Visual Studio,選擇調試菜單中的Attach To Process命令,在快顯視窗中勾選Show processes from all users,然後尋找我們的服務進程:TestService.exe,選擇它,然後點擊Attach按鈕。Attach後,如果我們在ThreadRun過程中加入斷點,則下一個迴圈到達後服務將會掛起,進入調試狀態。
7、在本例中我們是不斷地嚮應用程式日記中寫入記錄,要查看此結果可通過以下方式:啟動事件檢視器(開始 運行 輸入eventvwr.msc),選擇應用程式,在右方列表中會存在來源為.Net Test Service的記錄,它既是我們的服務進程寫入的。雙擊進入可看到事件描述(運行時得目前時間)
8、卸載服務,通過如下命令(先通過服務控制管理員停止服務):
installutil /u TestService.exe