Windows Service開發日誌(轉載csdn)

來源:互聯網
上載者:User
Windows Service開發日誌一(Win服務的一些技巧與出錯處理)

最近要幫公司系統增加一個類似於QQ機器人的功能,通過聊天人員發送相關指令(特殊字元),自動到資料庫中取相關資訊返回聊天人員,由於功能單一而且要長期執行,所以我想起用Windows服務的方式處理,同時也可以學習一下相關知識.在開發中遇到的問題和處理方法,我都記錄在其中,希望能協助有相同困難要處理的朋友.

一.Windows服務中的時鐘問題.

要在服務中實現定時詢問,一般有兩種做法,其一是用時鐘定時執行,其二是用線程,如果用時鐘來處理的話就要注意了,從工具箱中取出的控制項預設都是繼承於類System.Windows.Forms.Timer,但這種控制項在服務中是不會被執行的,如果要在服務中用,一定要用繼承於類System.Timers.Timer的控制項才行,

如果你想保持用可視化的方式來開發,你可以開啟服務對應的設計檔案(舉例,服務檔案名稱叫AlarmService,那麼就開啟AlarmService.Desinger.cs),將裡面的System.Windows.Forms.Timer改為System.Timers.Timer(注意,有兩個地方要改),儲存後,你雙擊服務中的Timer控制項就會發現建立的事件已經不同了,但其它地方大致還是一樣的.

你也可以用代碼同態建立,然後定義一個方法,再將方法綁到對象的Elapsed事件中,代碼如下

Timer Timer1=new Timer()

protected override void OnStart(string[] args)
{
     Timer1.Elapsed +=this.timer1_Elapsed;       //動態綁定事件
}

private void timer1_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
    //中間省略
}

即可

 二.建立好服務好啟動服務時出錯,提示#1083

由於我同一個項目中建立了兩個服務,但C#很笨,我裝服務改名時,他不會為新的服務重新建立一個新的對象,舉例:我建立一個Windows服務項目時,系統會自動建立一個叫Service1的服務,如果我裝其它檔案重新命名為AlarmService後,開啟Program.cs發現裡面建立的服務物件還是Service1,要手工進行修改,不然註冊服務後運行就會報1083,還有一點,同一項目如果建立了兩個或以上服務時,新建立的服務系統也不會為其建立對象,也是要手工在Program.cs檔案中添加,否則啟動服務時也會報1083錯

文法如下:

ServiceBase[] ServicesToRun;
ServicesToRun = new ServiceBase[] 
   { 
    new AMIService(),new AlarmService()    //假設兩個服務的名分別為AMIService和AlarmService
   };
ServiceBase.Run(ServicesToRun);

Windows Service開發日誌二(安裝與調試)

要運行這個service我們還要做下邊的幾個步驟:

1.為我們的Service添加Installer,右鍵點擊設計檢視,選擇Add Installer,VS將會為我們添加ProjectInstaller.cs,並在ProjectInstaller中添加組件serviceInstaller1和serviceProcessInstaller1,現在我們來修改他們的屬性來控制Service的安裝和啟動選項。在ProjectInstaller得設計檢視中選中serviceProcessInstaller1,將它得Account屬性選為LocalSystem,這樣以這個帳號服務啟動。如果你希望系統啟動時自動啟動服務得話,將serviceInstaller1的StartType的屬性選為Automatic,如果手動啟動的話,選為manaul。

 

2.安裝service,我們要用到IntallUtil.exe這個程式,這個程式位於C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727。點擊開始菜單,選擇“運行”,在運行對話方塊中輸入cmd,進入到命令列視窗,輸入cd :\WINDOWS\Microsoft.NET\Framework\v2.0.50727,進入到這個目錄,然後輸入installutil F:\Programs\C#\TestService\TestService\bin\Debug\testserveice.exe, installutil後邊的內容就是我們的工程產生的可執行程式的路徑,情根據需要修改。

如果你給ServiceInstaller1的StartType設為Automatic的話,安裝完服務,服務已經運行起來了,如果StartType是Manual的話,你需要手動啟動。現在我們進入“服務”,要開啟“服務”,請單擊“開始”,指向“設定”,然後單擊“控制台”。依次單擊“效能和維護”、“管理工具”,然後雙擊“服務”。在裡邊你應該能夠看到我們製作的Service MyFirstService。在這裡邊,我們可以啟動,關閉服務,還可以設定服務的啟動類型。然後,我們看看服務有沒有正確的寫入日誌,我們需要進入到事件檢視器,要開啟“事件檢視器”,請單擊“開始”,指向“設定”,然後單擊“控制台”。單擊“效能和維護”,單擊“管理工具”,然後雙擊“事件檢視器”。如所示,我們的訊息已經成功的寫到了系統日誌裡了。

 

3.如果你不需要這個Service了,仍然使用InstallUtil這個程式來卸載,不過在InstallUtil後跟參數 –u,比如installutil –u F:\Programs\C#\TestService\TestService\bin\Debug\testserveice.exe。

 

Service的調試方法與普通的程式調試方法是不一樣的。我來介紹一下。
1. Build你的項目

 

2. 設定斷點,因為我們的Service非常的簡單,沒有什麼執行邏輯,所以設定斷點沒有任何意義,大家可以自己寫一些代碼來實踐。一般來說,我們服務裡需要用到一個另外的線程來執行任務,你需要線上程的執行代碼中來設定斷點。

 

3. 安裝service,我們前邊有介紹如何安裝。

 

4. 如果你的Service啟動類型是手動(Manual),你需要到“服務”裡啟動你的Service。一般來說,如果你的service在開發階段,我推薦你將Service的啟動類型設定為Manual,這樣便於調試,因為如果service在運行過程中,你將無法build工程。

 

5. 在VS中,從菜單中選擇Debug->Attach Process….,將會出現:

 

裡邊列出了正在啟動並執行進程,如果你找不到自己的service,請選中Show processes from all users。在Available processes列表中選中我們的service所在的進程TestService,然後點擊Attach按鈕,如果你設定的斷點合理的話,那麼,程式就會停在斷點處,接下來你就可以進行調試了。、

 using System;
 using System.Collections.Generic;
 using System.ComponentModel;
 using System.Data;
 using System.Diagnostics;
 using System.ServiceProcess;
 using System.Text;

 namespace TestService
  {
     public partial class MyFirstService : ServiceBase
      {
         public MyFirstService()
          {
             InitializeComponent();
         }

         protected override void OnStart(string[] args)
          {
             // TODO: Add code here to start your service.
             eventLog1.WriteEntry("Service start");
         }

         protected override void OnStop()
          {
             // TODO: Add code here to perform any tear-down necessary to stop your service.
             eventLog1.WriteEntry("Service stop");
         }
     }
 }

windows Service開發日誌三(製作安裝包)

windows service沒有辦法雙擊就運行.它需要一個安裝類來輔助.接下來我們要做的,就是給這個服務添加一個安裝輔助類.
在project名上右鍵,添加新項目,選擇installer class.vs會自動給我們建立一個安裝類.
實際上,你也可以添加一個新類,然後讓這個類繼承自System.Configuration.Install.Installer.所以,實際上,用c#寫一個安裝類,實際上就是要寫一個繼

承自Installer的類.
說到這裡打斷一下,雖然你可以自己建立windows service類和install類,但是還是建議讓vs來給你建立,因為這樣除了有清晰的層次關係,還會得到很多自

動產生的程式碼段.比如說重寫的Dispose方法.
安裝windows service類,首先需要一個service安裝進程,然後在進程中有service的安裝,所以,我們需要在這個安裝類中建立這兩個類.
this.serviceProcessInstaller1 = new System.ServiceProcess.ServiceProcessInstaller();
this.serviceInstaller1 = new System.ServiceProcess.ServiceInstaller();
你可以這樣想:ServiceInstaller負責安裝windows service,而ServiceProcessInstaller是包裹在外面的一層.
this.serviceProcessInstaller1.Account = System.ServiceProcess.ServiceAccount.LocalSystem;
this.serviceProcessInstaller1.Password = null;
this.serviceProcessInstaller1.Username = null;
這個來設定安裝時的許可權,一般選擇本地系統賬戶的,話,就不需要使用者名稱和密碼了
this.serviceInstaller1.ServiceName = "notus";
this.serviceInstaller1.Description = "a sample";

serviceInstaller1.StartType = ServiceStartMode.Automatic;
而ServiceInstaller設定的都是和服務本身相關的一些參數,比如啟動方式,名字,描述等.
這裡的ServiceName要和前面你寫的windows service的名字相同.否則會出麻煩.
如果你想在安裝的前後做點什麼,那就需要進入到事件的操作.ServiceInstaller提供了安裝時的一些事件供你使用,比如下面這個:
serviceInstaller1.BeforeUninstall += new System.Configuration.Install.InstallEventHandler(serviceInstaller1_BeforeUninstall);
我們可以給這個事件加個代碼,就是確保你在刪除服務的時候,該服務是停止的.(如果服務正在運行,而你要刪除它,那就會出問題)
 void serviceInstaller1_BeforeUninstall(object sender, System.Configuration.Install.InstallEventArgs e)
        {
            ServiceController con = new ServiceController(serviceInstaller1.ServiceName);
            if (con.Status == ServiceControllerStatus.Running || con.Status == ServiceControllerStatus.StartPending)
            {
                    con.Stop();
            }
        }
還有一點要注意的是,如果要使用那些環境變數,需要按照下面的方法取得:
this.serviceProcessInstaller1.Context.Parameters["SURL"];
這個安裝類麻煩了些,因為出現了三個帶install的類,最後應該類似於這個樣子:
 [RunInstaller(true)]

 public partial class ProjectInstaller : Installer

{
 this.serviceProcessInstaller1 = new System.ServiceProcess.ServiceProcessInstaller();
 this.serviceInstaller1 = new System.ServiceProcess.ServiceInstaller();
 //......
}
如此這般,完成你的安裝類.

這樣,工作就基本完成了.如果你是用vs自動添加的這兩個類,可能會有些小迷惑,因為點擊view code,和到裡面在點擊,會有很多個名字一樣的類出現,然後

有的繼承了基類,有的沒有繼承,有的又引用什麼的...其實安靜下來看,這幾個類都是partial的,也就是局部類.不要被vs弄暈.

2.widnows service的安裝

vs命令提示字元

一種是在vs命令提示字元下(注意不是cmd敲出來的那個,而是在開始菜單的vs安裝目錄下那個)用命令操作
使用這個安裝 installutil myservice1.exe
這樣刪除 installutil /u myservice1.exe
當然,在運行前,你得先定位到myservice1.exe所在的檔案夾.

windows安裝項目

也可以使用vs提供的製作安裝程式的功能,把你的project添加到主輸出,就可以安裝.
建立peject,在其他那一類中選擇setup project,vs會給你建立一個安裝項目.
在項目名上右鍵,add,peojet output(輸出),把你的服務project添加進來.然後再在項目名上右鍵,view,custom action,你會看到有四個類別,分別

是install,commit,rollback,uninstall,在上面右鍵,add custom action,然後在application folder中找到你的服務project,添加進來.
如此這般(...),完成.
編譯,運行,看看效果 :)如果不出意外,你的服務就可以在控制台的"服務"視窗中找到.

 Windows Service開發日誌四(用程式設定服務的運行狀態及啟動方式)

開發了服務,總要開發一個設定介面來開啟或停止服務.

服務的啟動方式有兩種:

1.手動運行:手動運行,則每次都要手動去開啟服務,開啟了服務後,只要重啟電腦,服務又會被停止.

2.自動運行:當服務被設定以自動運行方式安裝,安裝後服務是不會自動啟動的(無論選擇自動或手動,服務剛安裝完時,狀態都是停止的),但重啟後服務就會自動啟運,就算停止了服務,只要啟動狀態是自動,那麼重啟電腦後,服務又會自動啟動並執行.

由於開發的需要,我的設定程式要實現幾項功能:

1.可以開啟或停止服務.

2.如果選擇開啟,那麼啟動類型就要設為自動.

3.如果選擇停止,那麼啟動類型就要設為手動,以免重啟後又自動執行.

這也是我寫這篇目章的目的.

1.其實要實現這幾個功能一點都不難,難就難在相關的資料少.

首先講講設定服務運行狀態:

用C#的ServiceProcess. ServiceController就可以實現,以下是實現代碼

view plaincopy to clipboardprint?
using System.ServiceProcess;  
ServiceController AlarmCon=new ServiceController("AlarmService");  
//擷取要控制的服務物件  
 
if (AlarmCon.Status==ServiceControllerStatus.Running)  
{  
   butAlStart.Enabled = false;  
   butAlStop.Enabled = true;  
}  
else 
{  
   butAlStart.Enabled = true;  
   butAlStop.Enabled = false;  

using System.ServiceProcess;
ServiceController AlarmCon=new ServiceController("AlarmService");
//擷取要控制的服務物件

if (AlarmCon.Status==ServiceControllerStatus.Running)
{
   butAlStart.Enabled = false;
   butAlStop.Enabled = true;
}
else
{
   butAlStart.Enabled = true;
   butAlStop.Enabled = false;
}
 

如果要設定運行狀態只要如下即可

view plaincopy to clipboardprint?
AlarmCon.Start();  
AlarmCon.WaitForStatus(ServiceControllerStatus.Running);  
//等到服務的狀態起效才往下執行  
GetAlarmServiceState(); 
AlarmCon.Start();
AlarmCon.WaitForStatus(ServiceControllerStatus.Running);
//等到服務的狀態起效才往下執行
GetAlarmServiceState();

2.如何改變服務的啟動方式呢,原來是要通過修改註冊表來實現

view plaincopy to clipboardprint?
using Microsoft.Win32;  
string keyPath = @"SYSTEM\CurrentControlSet\Services\AlarmService";   
RegistryKey key = Registry.LocalMachine.OpenSubKey(keyPath, true);  
key.SetValue("Start", 2);  
//2:自動啟動,3:手動啟動,4:禁用 

 

 

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.