2011-12-16 70 views
2

我一直在努力讓Windows服務在有新版本時自動重啓應用程序。我的代碼在下面,它實際上工作。我的問題是這樣的:在這裏有一個很大的禁忌?我是在單獨的線程上創建應用程序域的新手,我想知道是否有更好的方法來實現這一點。我也擔心可能我有一個很大的盲點,關於我如何處理這個問題。任何建議表示讚賞。不同線程上的應用程序域自我更新應用程序

有兩個通用部分:運行的Windows服務,以不同的進程啓動我的應用程序,然後輪詢以檢測該應用程序的新版本何時可用。第二部分是開始,更新,重新啓動的實際應用程序。

首先,當服務啓動時,它調用LoadApp(),以便該應用程序開始運行。

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秒,定時器調用此方法:

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 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 2013-06-28 20:54:05