2011-11-15 39 views
0

我創建了一個windows服務和安裝程序,該服務和安裝程序監視文件的更改以進行更改,並複製任何更改到WatchlistConfig.xml文件中指定的目標目錄的文件。處理Windows服務中的致命錯誤

我有幾個問題與服務: 1.它已經停止運行有一次。 (不可接受) 2.我們有時必須嘗試多次啓動該服務,然後才能「取得」。

我認爲問題#1可能是由於沒有處理應用程序中的致命錯誤。我發現了一些代碼,我試圖將其併入Main()方法,但是爲控制檯應用程序編寫(應用程序不是公認的類),因此現在已被註釋掉。任何想法是在服務中實現這一點的正確類?

問題2很可能是我猜測的超時。該監視列表目前由網絡上不同機器上的9個不同文件組成。連接到這些源不是立即的(並非全部在單個域上)。有沒有辦法爲服務啓動設置不同的超時值?

下面是相關的代碼。根據要求提供其他課程
在此先感謝。

編輯:錯誤地從我用來調試的測試工具(控制檯)發佈Main()。我已經將它留在原地並添加了WinSvc項目中的Program類

//Console Test harness 
     class Program 
      { 
       [STAThread] 
       static void Main(string[] args) 
       { 
        //AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException; 
        //Application.ThreadException += new System.Threading.ThreadExceptionEventHandler(Application_ThreadException); 
        //Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException); 
        //Application.EnableVisualStyles(); 
        //Application.SetCompatibleTextRenderingDefault(false); 
        //Application.Run(new Form1()); 

        TimedWatchList twl = new TimedWatchList(new PSU_Config(Helpers.GetConfigFile())); 

        Console.WriteLine("Press \'q\' to quit the sample."); 
        while (Console.Read() != 'q') ; 
       } 

       static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e) 
       { 
        HandleException((Exception)e.ExceptionObject); 
       } 

       static void HandleException(Exception e) 
       { 
        //Handle/Log Exception Here 
       } 
       static void Application_ThreadException(object sender, System.Threading.ThreadExceptionEventArgs e) 
       { 
        Logger.Loggit(e.Exception.Message); 
       } 
      } 

    //Actual Service 
     static class Program 
     { 
      /// <summary> 
      /// The main entry point for the application. 
      /// </summary> 
      static void Main() 
      { 
       ServiceBase[] ServicesToRun; 
       ServicesToRun = new ServiceBase[] 
       { 
        new Psu() 
       }; 
       ServiceBase.Run(ServicesToRun); 
      } 
     } 

     public partial class Psu : ServiceBase 
     { 
      public Psu() 
      { 
       InitializeComponent(); 
       TimedWatchList twl = new TimedWatchList(new PSU_Config(Helpers.GetConfigFile())); 
      } 

      protected override void OnStart(string[] args) 
      { 
      } 

      protected override void OnStop() 
      { 
      } 
     } 


     public class TimedWatchList 
     { 
      public static PSU_Config Config { get; set; } 
      List<WatchFile> WatchList = new List<WatchFile>(); 

      public TimedWatchList(PSU_Config config) 
      { 
       Config = config; 
       if (Config.PrintDebugMsgs) Logger.Loggit("Attempting to create TimedWatchList object"); 
       WatchList = WatchListFactory.GetWatchList(Helpers.GetWatchListFile()); 
       if (Config.PrintDebugMsgs) Logger.Loggit("TimedWatchList created"); 

       Timer _timer = new Timer(); 
       _timer.Interval += Config.Interval; 
       _timer.Enabled = true; 
       // register OnTimedEvent() to fire on each "tick" 
       _timer.Elapsed += OnTimedEvent; 
      } 

      private void OnTimedEvent(object source, ElapsedEventArgs e) 
      { 
       foreach (WatchFile file in WatchList) 
       { 
        file.PostOnUpdate(); 
       } 
      } 

     }//TimedWatchList class 

internal class WatchFile 
    // represents a file that is being watched 
    { 
    #region Props 
     public FileInfo SourceFile { get; set; } 
     public DirectoryInfo TargetPath { get; set; } 
    #endregion //Props 

    #region CTOR 
     public WatchFile() { } 
     public WatchFile(string fileName, string sourcePath, string destPath) 
     { 
      SourceFile = new FileInfo(Path.Combine(sourcePath, fileName)); 
      TargetPath = new DirectoryInfo(destPath); 
     } 
     public WatchFile(FileInfo sourceFile, DirectoryInfo targetDirectory) 
     { 
      SourceFile = sourceFile; 
      TargetPath = targetDirectory; 
     } 
    #endregion //CTOR 

     public void PostOnUpdate() 
     { 
      //if (TimedWatchList.Config.PrintDebugMsgs) Logger.Loggit("WatchFile Post Event called for: " + SourceFile.Name); 
      //if (TimedWatchList.Config.PrintDebugMsgs) Logger.Loggit("Stored LastModified datetime: " + LastModified); 

      string targetPath = String.Format(@"{0}\{1}", TargetPath.FullName, SourceFile.Name); 
      { 
       try 
       { 
        //ensure directory exists 
        if (!Directory.Exists(TargetPath.FullName)) Directory.CreateDirectory(TargetPath.FullName); 

        //ensure file version is current 
        if (!File.Exists(targetPath) || (File.GetLastWriteTime(targetPath) != File.GetLastWriteTime(SourceFile.FullName))) 
        { 
         Logger.Loggit(String.Empty); 
         Logger.Loggit("Attempting to copy: " + SourceFile + " (" + File.GetLastWriteTime(SourceFile.FullName) + ")"); 
         SourceFile.CopyTo(targetPath, true); 
         Logger.Loggit("\tCopy posted.\tLastModified: " + File.GetLastWriteTime(targetPath)); 
        } 

       } 
       catch (IOException ioex) 
       { 
        Logger.Loggit("Error: " + ioex.Message); 
       } 
       catch (Exception ex) 
       { 
        Logger.Loggit("Error: " + ex.Message); 
       } 
      } 
     } 
    }// WatchFile class 

回答

3

真的不需要猜測;作爲服務,您應該將錯誤記錄到系統事件日誌中。設置一個頂級處理程序(就像你所做的那樣),但不要指望能夠處理它。

如果錯誤未處理,您將無法在此處做任何事情。記錄並退出。抓住你可以儘快處理的錯誤,測試和設計你的代碼,不要以其他方式破壞。

您可以將服務設置爲在崩潰後自動重啓,但這應該是最後的手段。打破你的調試器,並找出錯誤發生的位置以及原因。我在這裏看到很多「這可能是[某事]」和「這可能是(別的)」陳述。再一次,沒有很好的理由去猜測。你可以使用工具來幫助你找出究竟發生了什麼。

+0

哎呀,我從主控臺測試線束中粘貼Main()。不知道我該如何調試一個服務,以便通過引用程序集並在控制檯中運行它來進行調試。有沒有辦法在本地運行和調試服務? –

+0

@JM:至少應該將未處理的異常記錄到系統事件日誌中。至於調試,是的,你可以啓動它作爲一個控制檯應用程序。 [這裏是另一個SO問題](http://stackoverflow.com/questions/5156427/how-do-you-debug-a-windows-service)關於該主題。 –

+0

Thx Ed。創建自定義錯誤/事件日誌是否很差? –

0

您可能想簡單地將函數包裝在try/catch塊中以查看可能會找到的內容。

try 
{ 
    MainAppFunctionality(); 
} 
catch (Exception e) 
{ 
    //Not sure what you are going to do here, it's probably too late 
} 

我建議您在應用程序的各個位置登錄Windows事件日誌作爲開始,以便您可以開始縮小錯誤的位置。

我也不確定你爲什麼從Windows服務上下文中使用Console.Read()。從Vista開始,服務無法與桌面交互。

+0

嗨布萊恩。我不得不承認我真的沒有使用Windows事件日誌。我認爲將消息寫入自定義錯誤日誌會更方便用戶。這是不好的做法嗎? –

+0

@JM。 :我不確定這是否對你有幫助。但這就是Windows事件日誌的設計目的。如果你願意,你可以隨時寫入兩者,但通常Windows事件日誌就是你所需要的。爲了追蹤這些東西,有些事情總比沒有好。 –