2011-12-16 6 views
2

私は、新しいバージョンがあるときに自動的にアプリケーションを再起動するためのWindowsサービスを手に入れようとしています。私のコードは以下の通りですが、実際には動作します。私の質問はこれです:どこか大きなノーノーはありますか?私は、別々のスレッドでアプリドメインを作成するのは初めてです。これを実現するためのより洗練された方法があるかどうかを知りたいと思います。また、私がこれをどのように扱っているかについて、私は大きな盲点があるかもしれないと心配しています。アドバイスをいただければ幸いです。別のスレッドにアプリケーションドメインを持つ自己更新アプリケーション

2つの一般的な部分があります:実行中のWindowsサービス、別のプロセスで自分のアプリケーションを起動し、そのアプリケーションの新しいバージョンが利用可能であることを検出するためにポーリングします。 2番目の部分は、起動、更新、再起動される実際のアプリです。

まず、サービスが開始されると、LoadApp()が呼び出され、アプリケーションの実行が開始されます。

private void Process(object stateInfo) 
{ 
    if (!Monitor.TryEnter(_locker)) { return; } 

    try 
    { 
     // Check for new binaries. If new, copy the files and restart the app domain.    
     if (!NewAppVersionReady()) { return; } 
     DeleteFiles(); 
     CopyFiles(); 
     RestartAppDomain(); 
    } 
    finally 
    { 
     Monitor.Exit(_locker); 
    } 
} 

RestartAppDomain()次のようになります。そして、

private void LoadApp() 
    { 
    // ** appDomainSetup here ** 

    this._appDomain = AppDomain.CreateDomain("MyUpdatedApp", AppDomain.CurrentDomain.Evidence, appDomainSetup); 

    this._tokenSource = new CancellationTokenSource(); 

    Task.Factory.StartNew(() => 
    { 
     try 
     { 
      this._appDomain.ExecuteAssembly(assembly); 
     } 
     catch (AppDomainUnloadedException ex) 
     { 
      Debug.WriteLine(ex.ToString()); 
     } 
    }, _tokenSource.Token); 
} 

、10秒ごとに、タイマーは、このメソッドを呼び出します。このメソッドの2行目にappドメインをアンロードすると、例外が発生することに注意してください。 (私は例外をキャッチし、基本的にはそれを無視してその周りを取得する。)

private void RestartAppDomain() 
{ 
    this._tokenSource.Cancel(); 
    AppDomain.Unload(this._appDomain); 
    LoadApp(); 
} 

編集:私は以来、AppDomain.Unload()ラインが不要であることが判明しました。それがなければ、サービスはまだ新しいバージョンでアプリケーションを更新してから、新しいバージョンのアプリケーションを開始します。私の大きな関心事は、トークンソースでCancel()を呼び出すことです。私はアプリを強制的にシャットダウンするのではなく、正常にシャットダウンできるようにしたいと思っています。

答えて

3

いくつかの試行錯誤と学習を通して、私はまともな解決策に納得したようです。それが他の人を助ける場合に備えて私がここに投稿すると思った。

まず、別のプロジェクトでインターフェイスを作成しました。そのため、自己更新アプリケーションは、実際に自分のアプリケーションドメインで実行されるアプリケーションを参照する必要はありません。このインターフェイスは、自己更新アプリが他のアプリでStartとStopを呼び出せるように使用されています。別のドメインで実行しますアプリで

public interface IStartStop 
{ 
    void Start(); 
    void Stop(); 
} 

、私はクラスはMarshalByRefObjectから派生し、IStartStopを実装していました。

public class PrestoTaskRunnerController : MarshalByRefObject, IStartStop, IDisposable 

これは私が私の自己更新アプリからこのアプリを起動および停止することができます:

this._appDomain = AppDomain.CreateDomain(this._appName, AppDomain.CurrentDomain.Evidence, appDomainSetup); 
this._startStopControllerToRun = (IStartStop)this._appDomain.CreateInstanceFromAndUnwrap(assemblyName, this._fullyQualifiedClassName); 
this._startStopControllerToRun.Start(); 

そして、それがこのように行われている停止:

this._startStopControllerToRun.Stop(); 
AppDomain.Unload(this._appDomain); 

いくつかのより多くの詳細があります。しかしこれは一般的な考え方であり、うまくいっているようです。

+0

あなたはそれが働いていることを聞いてうれしい!私は非常に似たようなことをやっているので、あなたのコード/擬似コードの比較をもっと見ることに興味があり、お互いに何かを学ぶことができるかもしれません。私の主な目標は、データベースでアセンブリをホストすることでしたが、共通の依存関係(IStartStopインターフェイス、余分なDLL)の必要性を避けるなど、管理できるいくつかのきれいな側面があります。 – Thracx

+0

どうやって共通の依存関係を避けましたか? –

関連する問題