2010-02-25 9 views
12

Ho un assembly .exe e un set di assembly di riferimento che mi piacerebbe essere in grado di distribuire il codice aggiornato per. Non ho bisogno di cambiare il codice in esecuzione, ma la prossima volta che avvierò l'eseguibile vorrei che prendesse il codice aggiornato. Attualmente, quando provo a copiare il file in esecuzione, viene visualizzato un errore relativo all'exe utilizzato da un altro processo.Come aggiornare un assieme per un processo C# in esecuzione (AKA hot deploy)?

Per riassumere; come posso aggiornare il codice mentre l'exe è in uso?

+0

Sembra esserci un progetto su Codeplex che mira alla distribuzione a caldo per .NET. Non ho provato però: http://hotdeploy.codeplex.com/ –

risposta

17

È facile da fare. È possibile rinominare il file, Windows ha un blocco sull'handle, non la voce di directory per il file. Ora puoi semplicemente copiare l'aggiornamento senza problemi. Tutto quello che resta da fare è eliminare il file rinominato dopo che l'app si riavvia. Se necessario.

+0

Puoi fornire maggiori dettagli/codice? – Jerry

+0

Oltre alla risposta, è possibile notare che l'utente potrebbe dover scollegare dal processo di debug prima di rinominare il file, altrimenti l'IDE (cioè Visual Studio) non consentirà la modifica dell'origine. –

+0

è una soluzione pessima, perché dopo la ridenominazione ti verranno danneggiate le scorciatoie. Dovresti invece usare l'helper application. – l0pan

3

Non credo sia possibile. Ad esempio, quando si distribuiscono applicazioni asp.net con tempi di inattività pari a zero, è consigliabile disporre di un servizio di bilanciamento del carico in modo da poter eliminare un'istanza, aggiornarla, quindi rimuovere l'altra per l'aggiornamento.

2

Non è possibile aggiornare il gruppo quando è in uso. L'opzione migliore per questo tipo di situazione consiste nel realizzare un piccolo eseguibile che esegue una copia shadow degli assembly e li avvia da una nuova posizione.

In questo modo, quando l'utente avvia il programma, è possibile eseguire la copia shadow (localmente) dal sito di distribuzione, che può sempre essere sovrascritto.

2

ClickOnce offre alcune opzioni. C'è un update strategy di "aggiornamento dopo l'avvio dell'applicazione".

Per scenari più complessi, c'è lo System.Deployment namespace. Ad esempio, è possibile eseguire periodicamente il polling degli aggiornamenti nella propria applicazione.

1

Che dire quanto segue:

  1. Distribuire l'exe in una cartella di aggiornamento.
  2. Ogni volta che l'applicazione si avvia, è necessario controllare la cartella di aggiornamento .
  3. Se la sua non è vuoto, eseguire un programma di copia
  4. Il programma di copia sarebbe quindi sostituire l'exe esistente con quello nella cartella aggiornamento
  5. eliminare nulla nella cartella di aggiornamento
  6. Poi rilanciare l'exe
1

L'idea migliore sarebbe una delle altre risposte già suggerite ... come utilizzare la ricomposizione con MEF o ClickOnce. Tuttavia, quelle soluzioni non ti aiuteranno per "questo deploy". Richiedono di apportare modifiche al file exe o di creare un file eseguibile per il boot strap, che sarà di aiuto solo per la prossima distribuzione.

Per questa distribuire si può provare a fare questo (non ho mai fatto prima, ma in teoria potrebbe funzionare):

  1. Copiare i nuovi dll in una sottocartella da qualche parte
  2. aggiungere un comando comando linea xcopy per RunOnce registry key per copiare la nuova dll dalla sottocartella alla cartella exe finale in cui si desidera che vada.
  3. Riavviare.

La chiave RunOnce contiene comandi da riga di comando che vengono eseguiti una volta al riavvio e quindi rimossi dal registro in modo che non vengano eseguiti nuovamente. In questo modo, InstallShield consente di sovrascrivere determinate DLL mentre sono utilizzate da altre applicazioni.

0

Questa classe rinominerà l'eseguibile attualmente in esecuzione, se si completa senza eccezione, si può semplicemente scrivere il nuovo eseguibile, quindi rilanciare, ad esempio: abbastanza

Ourself.Rename(); 
// Download or copy new version 
File.Copy(newVersion, Ourself.FileName()); 
// Launch new version 
System.Diagnostics.Process.Start(Ourself.FileName()); 
// Close current version 
Close(); // Exit(); 

facile?

class Ourself 
{ 
    public static string FileName() { 
     Assembly _objParentAssembly; 

     if (Assembly.GetEntryAssembly() == null) 
      _objParentAssembly = Assembly.GetCallingAssembly(); 
     else 
      _objParentAssembly = Assembly.GetEntryAssembly(); 

     if (_objParentAssembly.CodeBase.StartsWith("http://")) 
      throw new IOException("Deployed from URL"); 

     if (File.Exists(_objParentAssembly.Location)) 
      return _objParentAssembly.Location; 
     if (File.Exists(System.AppDomain.CurrentDomain.BaseDirectory + System.AppDomain.CurrentDomain.FriendlyName)) 
      return System.AppDomain.CurrentDomain.BaseDirectory + System.AppDomain.CurrentDomain.FriendlyName; 
     if (File.Exists(Assembly.GetExecutingAssembly().Location)) 
      return Assembly.GetExecutingAssembly().Location; 

     throw new IOException("Assembly not found"); 
    } 

    public static bool Rename() 
    { 
     string currentName = FileName(); 
     string newName = FileName() + ".ori"; 
     if (File.Exists(newName)) 
     { 
      File.Delete(newName); 
     } 
     File.Move(currentName, newName); 
     return true; 
    } 
} 
Problemi correlati