程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> C# >> C#入門知識 >> C# 編寫Window服務基礎(一)

C# 編寫Window服務基礎(一)

編輯:C#入門知識

一.Windows服務介紹:
Windows服務以前被稱作NT服務,是一些運行在Windows NT、Windows 2000和Windows XP等操作系統下用戶環境以外的程序。在以前,編寫Windows服務程序需要程序員很強的C或C++功底。然而現在在Visual Studio.Net下,你可以運用C++或Visual C#或Visual Basic.Net很輕松的創建一個Windows服務程序。同樣,你還可以運用其他任何與CLR相容的語言來創建Windows服務程序。本文就向大家介紹如何運用Visual C#來一步一步創建一個文件監視的Windows服務程序,然後介紹如何安裝、測試和調試該Windows服務程序。
在介紹如何創建Windows服務程序以前,我先向大家介紹一些有關Windows服務的背景知識。一個Windows服務程序是在Windows操作系統下能完成特定功能的可執行的應用程序。Windows服務程序雖然是可執行的,但是它不像一般的可執行文件通過雙擊就能開始運行了,它必須有特定的啟動方式。這些啟動方式包括了自動啟動和手動啟動兩種。對於自動啟動的Windows服務程序,它們在Windows啟動或是重啟之後用戶登錄之前就開始執行了。只要你將相應的Windows服務程序注冊到服務控制管理器(Service Control Manager)中,並將其啟動類別設為自動啟動就行了。而對於手動啟動的Windows服務程序,你可以通過命令行工具的NET START 命令來啟動它,或是通過控制面板中管理工具下的服務一項來啟動相應的Windows服務程序(見圖1)。同樣,一個Windows服務程序也不能像一般的應用程序那樣被終止。因為Windows服務程序一般是沒有用戶界面的,所以你也要通過命令行工具或是下面圖中的工具來停止它,或是在系統關閉時使得 Windows服務程序自動停止。因為Windows服務程序沒有用戶界面,所以基於用戶界面的API函數對其是沒有多大的意義。為了能使一個 Windows服務程序能夠正常並有效的在系統環境下工作,程序員必須實現一系列的方法來完成其服務功能。Windows服務程序的應用范圍很廣,典型的 Windows服務程序包含了硬件控制、應用程序監視、系統級應用、診斷、報告、Web和文件系統服務等功能。
圖1

二.創建Windows服務程序:
在介紹如何創建Windows服務程序以前,我先向大家介紹一下.Net框架下與Windows服務相關的命名空間和其中的類庫。.Net框架大大地簡化了Windows服務程序的創建和控制過程,這要歸功於其命名空間中的功能強大的類庫。和Windows服務程序相關的命名空間涉及到以下兩個:System.ServiceProcess和System.Diagnostics。
要創建一個最基本的Windows服務程序,我們只需要運用.Net框架下的System.ServiceProcess命名空間以及其中的四個類:ServiceBase、ServiceInstaller、ServiceProcessInstaller以及 ServiceController,其體系結構可見圖2。
圖2

其中ServiceBase類定義了一些可被其子類重載的函數,通過這些重載的函數,服務控制管理器就可以控制該Windows服務程序了。這些函數包括:OnStart()、OnStop()、OnPause()以及OnContinue()等四個。而且ServiceBase類的子類還可以重載 OnCustomCommand()函數來完成一些特定的操作。通過重載以上的一些函數,我們就完成了一個Windows服務程序的基本框架,這些函數的重載方法如下:

protected override void OnStart(string[] args)

{

}

protected override void OnStop()

{

}

protected override void OnPause()

{

}

protected override void OnContinue()

{

}

ServiceBase類還為我們提供了一些屬性,而這些屬性是任何Widnows服務程序所必須的。其中的ServiceName屬性指定了 Windows服務的名稱,通過該名稱系統就可以調用Windows服務了,同時其它應用程序也可以通過該名稱來調用它的服務。而 CanPauseAndContinue和CanStop屬性顧名思義就是允許暫停並恢復和允許停止的意思。
要使得一個Windows服務程序能夠正常運行,我們需要像創建一般應用程序那樣為它創建一個程序的入口點。在Windows服務程序中,我們也是在 Main()函數中完成這個操作的。首先我們在Main()函數中創建一個Windows服務的實例,該實例應該是ServiceBase類的某個子類的對象,然後我們調用由基類ServiceBase類定義的一個Run()方法。然而Run()方法並不就開始了Windows服務程序,我們必須通過前面提到的服務控制管理器調用特定的控制功能來完成Windows服務程序的啟動,也就是要等到該對象的OnStart()方法被調用時服務才真正開始運行。如果你想在一個Windows服務程序中同時啟動多個服務,那麼只要在Main()函數中定義多個ServiceBae類的子類的實例對象就可以了,方法就是創建一個ServiceBase類的數組對象,使得其中的每個對象對應於某個我們已預先定義好的服務。

{

System.ServiceProcess.ServiceBase[] MyServices;

MyServices = new System.ServiceProcess.ServiceBase[] { new Service1(), new Service2() };

System.ServiceProcess.ServiceBase.Run(MyServices);

}

static void Main()
三.添加文件監視服務:
了解了Windows服務的基本體系結構和創建方法後,我們就可以試著往服務中添加一些實際的功能了。下面我將向大家介紹一個能監視本地文件系統的文件監視服務-FileMonitorService。該服務能根據預先設定的本地目錄路徑監視其中的文件包括子文件夾中的任何變化:文件創建、文件刪除、文件改名、文件修改。同時,該服務還為每種變化創建了一個相對應的計數器,計數器的作用就是反映該種變化的頻度。
首先,我們打開Visual Studio.Net,新建一個Visual C#的Windows服務的項目,如圖3所示:
圖3

在重載Windows服務的OnStart()函數之前,我們先給其類添加一些計數器對象,這些計數器分別對應了文件的創建、刪除、改名以及修改等變化。一旦指定目錄中的文件發生以上的某種變化,與其相對應的計數器就會自動加1。所有的這些計數器都是定義為PerformanceCounter類型的變量的,該類是包含在System.Diagnostics命名空間中的。

private System.Diagnostics.PerformanceCounter fileCreateCounter;

private System.Diagnostics.PerformanceCounter fileDeleteCounter;

private System.Diagnostics.PerformanceCounter fileRenameCounter;

private System.Diagnostics.PerformanceCounter fileChangeCounter;

之後我們便在類的InitializeComponent()方法中創建以上定義的各個計數器對象並確定其相關屬性。同時我們將該Windows服務的名稱設置為“FileMonitorService”,設定其即是允許暫停並恢復的又是允許停止的。

private void InitializeComponent()

              {

                     this.components = new System.ComponentModel.Container();

                     this.fileChangeCounter = new System.Diagnostics.PerformanceCounter();

                     this.fileDeleteCounter = new System.Diagnostics.PerformanceCounter();

                     this.fileRenameCounter = new System.Diagnostics.PerformanceCounter();

                     this.fileCreateCounter = new System.Diagnostics.PerformanceCounter();

                     fileChangeCounter.CategoryName = "File Monitor Service";

                     fileDeleteCounter.CategoryName = "File Monitor Service";

                     fileRenameCounter.CategoryName = "File Monitor Service";

                     fileCreateCounter.CategoryName = "File Monitor Service";

                     fileChangeCounter.CounterName = "Files Changed";

                     fileDeleteCounter.CounterName = "Files Deleted";

                     fileRenameCounter.CounterName = "Files Renamed";

                     fileCreateCounter.CounterName = "Files Created";

                     this.ServiceName = "FileMonitorService";

                     this.CanPauseAndContinue = true;

                     this.CanStop = true;

                     servicePaused = false;

              }

接著就是重載OnStart()函數和OnStop()函數,OnStart()函數完成了一些必要的初始化工作。在.Net框架下,文件的監視功能可以由FileSystemWatcher類來完成,該類是包含在System.IO命名空間下的。該Windows服務所要完成的功能包括了監視文件的創建、刪除、改名和修改等變化,而FileSystemWatcher類包含所有了對應於這些變化的處理函數。

protected override void OnStart(string[] args)

              {    

                     FileSystemWatcher curWatcher = new FileSystemWatcher();

                     curWatcher.BeginInit();

                     curWatcher.IncludeSubdirectories = true;

                     curWatcher.Path =

System.Configuration.ConfigurationSettings.AppSettings

["FileMonitorDirectory"];

                     curWatcher.Changed += new FileSystemEventHandler(OnFileChanged);

                     curWatcher.Created += new FileSystemEventHandler(OnFileCreated);

                     curWatcher.Deleted += new FileSystemEventHandler(OnFileDeleted);

                     curWatcher.Renamed += new RenamedEventHandler(OnFileRenamed);

                     curWatcher.EnableRaisingEvents = true;

                     curWatcher.EndInit();

              }

注意其中被監視的目錄是存放在一個應用程序配置文件中的,該文件是一個XML類型的文件。這種做法的好處就是我們不必重新編譯並發布該Windows服務而只要直接修改其配置文件就可以達到更改所要監視的目錄的功能了。
當該Windows服務啟動後,一旦被監視的目錄中的文件發生某種變化,與其相對應的計數器的值便會相應的增加,方法很簡單,只要調用計數器對象的IncrementBy()即可。

private void OnFileChanged(Object source, FileSystemEventArgs e)

              {

                     if( servicePaused == false )

                     {

                            fileChangeCounter.IncrementBy(1);

                     }

              }

              private void OnFileRenamed(Object source, RenamedEventArgs e)

              {

                     if( servicePaused == false )

                     {

                            fileRenameCounter.IncrementBy(1);

                     }

              }

              private void OnFileCreated(Object source, FileSystemEventArgs e)

              {

                     if( servicePaused == false )

                     {

                            fileCreateCounter.IncrementBy(1);

                     }

              }

              private void OnFileDeleted(Object source, FileSystemEventArgs e)

              {

                     if( servicePaused == false )

                     {

                            fileDeleteCounter.IncrementBy(1);

                     }

              }

OnStop()函數即是停止Windows服務的,在該Windows服務中,服務一旦停止,所有的計數器的值都應歸零,但是計數器並不提供一個Reset()方法,所以我們只好將計數器中的值減去當前值來達到這個目的。

protected override void OnStop()

              {

                     if( fileChangeCounter.RawValue != 0 )

                     {

                            fileChangeCounter.IncrementBy(-fileChangeCounter.RawValue);

                     }

                     if( fileDeleteCounter.RawValue != 0 )

                     {

                            fileDeleteCounter.IncrementBy(-fileDeleteCounter.RawValue);

                     }

                     if( fileRenameCounter.RawValue != 0 )

                     {

                            fileRenameCounter.IncrementBy(-fileRenameCounter.RawValue);    

                     }

                     if( fileCreateCounter.RawValue != 0 )

                     {

                            fileCreateCounter.IncrementBy(-fileCreateCounter.RawValue);

                     }

              }

同時,因為我們的Windows服務是允許暫停並恢復的,所以我們還得重載OnPause()函數和OnContinue()函數,方法很簡單,只要設定前面定義的布爾值servicePaused即可。

protected override void OnPause()

              {

                     servicePaused = true;

              }

             protected override void OnContinue()

              {

                     servicePaused = false;

             }

這樣,該Windows服務的主體部分已經完成了,不過它並不有用,我們還必須為其添加安裝文件。安裝文件為Windows服務的正確安裝做好了工作,它包括了一個Windows服務的安裝類,該類是重System.Configuration.Install.Installer繼承過來的。安裝類中包括了Windows服務運行所需的帳號信息,用戶名、密碼信息以及Windows服務的名稱,啟動方式等信息。

[RunInstaller(true)]

       public class Installer1 : System.Configuration.Install.Installer

       {

              /// <summary>

              /// 必需的設計器變量。

              /// </summary>

              private System.ComponentModel.Container components = null;

              private System.ServiceProcess.ServiceProcessInstaller spInstaller;

              private System.ServiceProcess.ServiceInstaller sInstaller;

              public Installer1()

              {

                     // 該調用是設計器所必需的。

                     InitializeComponent();

                    // TODO: 在 InitComponent 調用後添加任何初始化

              }

              #region Component Designer generated code

              /// <summary>

              /// 設計器支持所需的方法 - 不要使用代碼編輯器修改

              /// 此方法的內容。

              /// </summary>

             private void InitializeComponent()

              {

                     components = new System.ComponentModel.Container();

                     // 創建ServiceProcessInstaller對象和ServiceInstaller對象

                     this.spInstaller =

new System.ServiceProcess.ServiceProcessInstaller();

                     this.sInstaller = new System.ServiceProcess.ServiceInstaller();

                     // 設定ServiceProcessInstaller對象的帳號、用戶名和密碼等信息

                     this.spInstaller.Account =

System.ServiceProcess.ServiceAccount.LocalSystem;

                     this.spInstaller.Username = null;

                     this.spInstaller.Password = null;

                    // 設定服務名稱

                     this.sInstaller.ServiceName = "FileMonitorService";

                    // 設定服務的啟動方式

                     this.sInstaller.StartType =

System.ServiceProcess.ServiceStartMode.Automatic;

                     this.Installers.AddRange(

new System.Configuration.Install.Installer[]

{this.spInstaller, this.sInstaller });

              }

              #endregion

       }

同樣,因為該Windows服務中運用到了計數器對象,我們也要為其添加相應的安裝文件,安裝文件的內容和作用與前面的類似。限於篇幅,這裡就不給出相應的代碼了,有興趣的讀者可以參考文後附帶的源代碼文件。
到此為止,整個Windows服務已經構建完畢,不過Windows服務程序和一般的應用程序不同,它不能直接調試運行。如果你直接在IDE下試圖調試運行之,就會報出如圖4所示提示。
圖4

根據其中提示,我們知道安裝Windows服務需要用到一個名為InstallUtil.exe的命令行工具。而運用該工具安裝Windows服務的方法是非常簡單的,安裝該Windows服務的命令如下:

installutil FileMonitorService.exe

而要卸載該Windows服務,你只要輸入如下的命令即可:

installutil /u FileMonitorService.exe

Windows服務安裝成功後,它便會出現在服務控制管理器中,如圖5所示。
圖5

這樣,該文件監視的Windows服務就完成了,一旦我們對被監視的目錄中的文件進行操作,相應的計數器就會運作,起到監視文件變化的作用。不過這個功能對於一般的用戶而言沒多大意義,然而你可以在此基礎上添加新的功能,比如構建一個後台的文件處理系統,一旦被監視的目錄中的文件發生某種變化,Windows服務便對其進行特定的操作,而最終用戶就不必去關心後台處理程序是如何實現的了。
四.總結:
本文向大家介紹了Windows服務的一些基本概念和構建一般的Windows服務所需的方法,同時還向大家展示了一個具有文件監視功能的 Windows服務程序。通過本文,讀者應該能體會到構建Windows服務並不是想象中的那麼復雜,這主要還得歸功於.Net框架為我們所作的大量努力。同時,希望大家能在本文給出的實例的基礎上構建更加完善和更加強大的Windows服務程序。最後希望本文對大家能有不少幫助。

(注:源代碼文件為Source.rar)

三、安裝、卸載window服務

1、輸入cmd(命令行),輸入cd C:\WINDOWS\Microsoft.NET\Framework\v4.0.30319,2.0為cd C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727

2、安裝服務(項目生成的exe文件路徑)

將InstallUtil.exe文件與WindowsService.exe,WindowsService.exe.config放在一個文件夾

創建一個.bat文件: InstallUtil /i WindowsService.exe

InstallUtil "E:\WindowsService1\bin\Debug\WindowsService1.exe"

3、卸載服務

  InstallUtil  /u "E:\WindowsService1\bin\Debug\WindowsService1.exe"

四、查看window服務

    services.msc

控制面板-->管理工具-->服務,可在此手動啟動,停止服務

五、調試window服務

1、通過【事件查看器】查看

2、直接在程序中調試(菜單-->調試-->附加進程-->服務名(這裡的服務名是項目名稱,不是ServiceName屬性自定義的名稱,所以建議自定義名稱和項目名稱保持一致,另外需勾選【顯示所有用戶的進程】才能看到服務名)-->附加

   這裡附加的進程名應該是:WindowsService1.exe 而不是 WindowsService1.vshost.exe。WindowsService1.exe 默認不會出現,必須勾選【顯示所有用戶的進程】【顯示所有會話中的進程】

3. 在程序中打斷點調試即可,另外調試服務時服務必須已啟動(管理工具-->服務)

使用InstallUtil安裝Window服務

InstallUtil 命令的所在目錄:Microsoft.NET/Framework/Vx.x.xxxx

示例:

安裝服務
InstallUtil YourService.exe      

卸載服務
InstallUtil /u YourService.exe
InstallUtil命令幫助

InstallUtil /?

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved