2011-11-15 14 views
0

Windowsのサービスとインストーラを作成して、変更のファイルコレクションを監視し、WatchlistConfig.xmlファイルで指定された宛先ディレクトリに変更されたファイルをコピーします。Windowsサービスで致命的なエラーを処理する

私はサービスにいくつかの問題があります: 1.それはある機会に実行を停止しました。 (受け入れられない) 2.サービスを開始する前に、何度かサービスを開始しなければならないことがあります。

問題#1はおそらく、アプリケーションの致命的なエラーを処理していないためと思われます。私はMain()メソッドに組み込もうとしたコードを見つけましたが、コンソールアプリケーション用に書かれています(アプリケーションは認識されたクラスではありません)ので、今はコメントアウトされています。これをサービスに実装するための適切なクラスであることは何ですか?

問題#2はおそらく私が推測しているタイムアウトです。ウォッチリストは現在、ネットワーク上の異なるマシン上に9つの異なるファイルで構成されています。これらのソースへの接続は即時ではありません(単一ドメイン上のすべてではありません)。サービスの起動時に異なるタイムアウト値を設定する方法はありますか?

ここに関連コードがあります。追加のクラスはリクエストに応じます。
ありがとうございます。

編集:誤ってデバッグに使用するテストハーネス(コンソール)からMain()を投稿しました。私は場所に残し、推測する必要は本当にありませんWinSvcプロジェクト

//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

私はコンソールテストハーネスからメイン()に貼り付けました。どのようにしてサービスをデバッグすることができないので、アセンブリを参照してコンソールで実行してデバッグしています。ネイティブでサービスを実行してデバッグする方法はありますか? –

+0

@JM:少なくとも、処理されていない例外をシステムイベントログに記録する必要があります。デバッグに関しては、コンソールアプリケーションとして起動することができます。その件に関して、[こちらは別の質問です](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 Event Logが設計したものです。必要に応じていつでも両方に書き込むことができますが、通常はWindowsイベントログに必要なものすべてがあります。何かは、このものを追跡するためのものよりも優れています。 –