2010-03-16 145 views
42
protected override void OnStart(string[] args) 
{ 
    AppDomain.CurrentDomain.UnhandledException += 
     new UnhandledExceptionEventHandler(CurrentDomain_UnhandledException); 

    Thread.Sleep(10000); 

    throw new Exception(); 
} 

void CurrentDomain_UnhandledException(object sender, 
             UnhandledExceptionEventArgs e) 
{ 
} 

我在我的windows服務中附加了一個調試器到上面的代碼中,在CurrentDomain_UnhandledException中設置了一個斷點,但它從未被命中。這個異常彈出,說它是未處理的,然後服務停止。我甚至嘗試在事件處理程序中放入一些代碼,以防它進行優化。如何在Windows服務中設置.NET UnhandledException處理?

這不是在Windows服務中設置未處理的異常處理的正確方法嗎?

回答

2

只是好奇,你想完成什麼:避免服務崩潰或報告錯誤?

對於報告,我認爲您最好的選擇是添加頂級try/catch語句。您可以嘗試將它們記錄到Windows事件日誌和/或日誌文件中。

您還可以將ExitCode屬性設置爲非零值,直到您成功停止該服務。如果系統管理員從「服務」控制面板啓動服務,並且服務突然停止並顯示非零退出代碼,則Windows可以顯示錯誤消息和錯誤說明。

+0

調試。我嘗試瞭解所有的例外情況,但其中一個以某種方式逃避我。我認爲這將是一個更易於管理的解決方案。 – 2010-03-16 18:53:58

+0

OnStart或OnStop中發生異常嗎?你有關於異常的其他信息嗎? – 2010-03-22 13:34:03

9

在Windows服務中,您不希望在OnStart方法中運行很多代碼。所有你想要的是啓動你的服務線程然後返回的代碼。

如果你這樣做,你可以處理你的服務線程中發生的異常。

例如

public static void Start() 
{ 
    AppDomain currentDomain = AppDomain.CurrentDomain; 
    currentDomain.UnhandledException += new UnhandledExceptionEventHandler(currentDomain_UnhandledException); 

    running = true; 
    ThreadStart ts = new ThreadStart(ServiceThreadBody); 
    thread = new Thread(ts); 
    thread.Name = "ServiceThread"; 
    thread.Priority = ThreadPriority.BelowNormal; 
    thread.Start(); 
} 
+0

我最近有一個地方,因爲我的服務仍然運行,但沒有任何過程...我開始認爲這可能是由於「吞食」異常。想知道你對我的問題有什麼想法嗎? http://stackoverflow.com/questions/41618324/windows-service-runs-but-stops-processing-after-two-days – 2017-01-13 09:28:00

4

知道這個主題有點舊了,但是認爲根據在.NET中開發Windows服務的個人經驗添加一些評論會很有用。 最好的方法是儘可能避免在服務控制管理器下開發 - 爲此,您需要一個簡單線束,它模仿服務開始的方式 - 可以創建服務類的一個實例(即您已經從ServiceBase派生出來)並調用OnStart,OnStop等方法。這個線束可以是你想要的控制檯應用程序或Windows應用程序。

這幾乎是我發現的在.NET中調試服務啓動問題的唯一方式 - 您的代碼,Visual Studio和真正的服務控制管理器之間的交互只會使該過程無法進行。

HTH。

+0

+1:在一個單獨的庫中實現所有的邏輯,並從你的服務中調用它。從控制檯應用程序調用相同的庫以用於開發/調試目的。 – 2011-02-28 12:21:28

+2

我喜歡你的方法,但它不是調試服務啓動問題的唯一方法。我所做的 - 特別是在生產環境中調試服務時 - 是要將WinDbg設置爲:1.在主機進程啓動時連接到服務,以及2.打開偵聽端口(需要克服服務隔離)。然後,可以使用在您的用戶會話下運行的另一個WinDbg實例開始調試。 (作爲第一條語句的可調參數「RequestAdditionalTime」或註冊表配置有助於克服SCM在服務啓動時間期限內的時間限制) – 2013-09-02 22:06:15

51

我已經來到這個線程比較晚,但我認爲它可能是值得提供一個解釋,其他答案都沒有。

在OP代碼示例中未命中CurrentDomain_UnhandledException處理程序的原因在於調用OnStart方法以響應來自Windows服務控制管理器的啓動命令(該命令通過框架的接收和分派到此方法ServiceBase實現);在基類中處理由OnStart引發的任何異常,並將其記錄到事件日誌中,並轉換成返回給SCM的錯誤狀態代碼。所以這個異常永遠不會傳播到AppDomain的未處理的異常處理程序。

我想你會發現從您的服務中的工作線程拋出的未處理的異常將被CurrentDomain_UnhandledException處理程序捕獲。

+0

看起來像ServiceBase上的ServiceQueuedMainCallback方法會導致此行爲。 – 2014-03-10 02:46:28

2

當我在自己的Windows服務上工作時,它已經足夠奇怪了。我認爲這是因爲不受歡迎的例外。目前我正在捕捉文本文件上的無用例外。首先,您必須在C位置創建新的文件ServiceLog.txt,因爲它會在文本文件上記錄excaptions。通過下面的代碼,我得到了所有的無用的例外與他們的行號。

using System.Security.Permissions; 
using System.IO; 

[SecurityPermission(SecurityAction.Demand, Flags = SecurityPermissionFlag.ControlAppDomain)] 
    protected override void OnStart(string[] args) 
    { AppDomain currentDomain = AppDomain.CurrentDomain; 
     currentDomain.UnhandledException += new UnhandledExceptionEventHandler(MyHandler); 
     ... 
     Your codes... 
     .... 
    } 
    void MyHandler(object sender, UnhandledExceptionEventArgs args) 
    { 
     Exception e = (Exception)args.ExceptionObject; 
     WriteToFile("Simple Service Error on: {0} " + e.Message + e.StackTrace); 
    } 
    private void WriteToFile(string text) 
    { 
     string path = "C:\\ServiceLog.txt"; 
     using (StreamWriter writer = new StreamWriter(path, true)) 
     { 
      writer.WriteLine(string.Format(text, DateTime.Now.ToString("dd/MM/yyyy hh:mm:ss tt"))); 
      writer.Close(); 
     } 
    } 
相關問題