2010-02-25 16 views
12

Tengo un ensamblado .exe y un conjunto de ensambles referenciados para los que me gustaría poder implementar el código actualizado. No necesito cambiar realmente el código de ejecución, pero la próxima vez que lance el ejecutable, me gustaría que recoja el código actualizado. Actualmente, cuando intento copiar el archivo en ejecución, aparece un error sobre el exe que está siendo utilizado por otro proceso.¿Cómo actualizar un ensamblaje para un proceso de ejecución de C# (AKA hot deploy)?

Resumir; ¿Cómo puedo actualizar el código mientras el .exe está en uso?

+0

Parece haber un proyecto en Codeplex apuntando a la implementación en caliente para .NET. No lo he intentado sin embargo: http://hotdeploy.codeplex.com/ –

Respuesta

17

Es fácil de hacer. Puede cambiar el nombre del archivo, Windows tiene un candado en el mango, no la entrada del directorio para el archivo. Ahora puede copiar la actualización sin problemas. Todo lo que queda por hacer es deshacerse del archivo renombrado después de que la aplicación se inicie de nuevo. Si necesario.

+0

¿Puedes dar más detalles/código? – Jerry

+0

Además de su respuesta, es posible que desee tener en cuenta que el usuario podría necesitar desconectarse del proceso de depuración antes de cambiar el nombre del archivo; de lo contrario, el IDE (es decir, Visual Studio) no permitirá que se edite la fuente. –

+0

es una mala solución porque recibirá accesos directos dañados después de cambiar el nombre. Deberías usar la aplicación auxiliar en su lugar. – l0pan

3

No creo que esto sea posible. Por ejemplo, al implementar aplicaciones asp.net sin tiempo de inactividad, la mejor práctica es tener un equilibrador de carga para que pueda eliminar una instancia, actualizarla y luego quitar la otra para actualizarla.

2

No puede actualizar el conjunto cuando está en uso. La mejor opción para este tipo de situaciones es crear un pequeño archivo ejecutable que haga una copia oculta de sus ensamblajes y los inicie desde una nueva ubicación.

De esta forma, cuando el usuario inicia el programa, puede copiar sombra (localmente) desde el sitio de implementación, que siempre se puede sobrescribir.

2

ClickOnce le ofrece algunas opciones. Hay un update strategy de "actualización después del inicio de la aplicación".

Para escenarios más complejos, existe el System.Deployment namespace. Por ejemplo, puede buscar periódicamente actualizaciones en su aplicación.

1

¿Qué hay de lo siguiente:

  1. Implementar el exe a una carpeta de actualización.
  2. Cada vez que se inicia la aplicación, sería revise la carpeta de actualización.
  3. Si no es vacía, ejecutar un programa de copia
  4. El programa de copia entonces reemplazar el exe existente con el que está en la carpeta actualización
  5. borrar nada en la carpeta de actualización
  6. Entonces relanzar el exe
1

La mejor idea sería una de las otras respuestas ya sugeridas ... como usar la recomposición con MEF o con ClickOnce. Sin embargo, esas soluciones no lo ayudarán para "este despliegue". Requieren que hagas cambios en el exe y/o que crees un ejecutable de correa de arranque, que solo te ayudará en la próxima implementación.

Para esta desplegar puede intentar hacer esto (que nunca he hecho esto antes, pero en teoría podría funcionar):

  1. Copie sus nuevas DLL a una subcarpeta en algún lugar
  2. añadir un comando línea de comando xcopy al RunOnce registry key para copiar el nuevo dll de la subcarpeta a la carpeta final del exe donde desea que vaya.
  3. Reinicio.

La clave RunOnce contiene comandos de línea de comandos que se Ejecutan Una vez al reiniciar, y luego se eliminan del registro para que no se vuelvan a ejecutar. Así es como InstallShield le permite sobrescribir ciertos dll mientras están siendo utilizados por otras aplicaciones.

0

Esta clase se cambie el nombre del archivo ejecutable actualmente en ejecución, si se completa sin excepción, simplemente hay que escribir el nuevo ejecutable, relanzar, por ejemplo:

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(); 

Fácil suficiente?

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; 
    } 
} 
Cuestiones relacionadas