.net

¿Cómo puede un programa.net actualizarse?



(5)

He escrito un programa que se actualiza a sí mismo si encuentra una versión más nueva en un servidor, pero me resulta difícil implementarla limpiamente.

La comprobación de un servidor remoto y la descarga del archivo son bastante fáciles, pero ¿qué pasa? No puede simplemente File.Copy ("newversion.exe", "myprogram.exe") porque myprogram se está ejecutando y el archivo está bloqueado.

Lo hago descargando dos archivos de versión y actualización. myprogram luego inicia la actualización y sale. la actualización espera dos segundos, hace la copia, luego inicia myprogram (que ahora es la versión actualizada) y sale. myprogram busca actualizaciones cuando se inicia y las elimina, y versión nueva si las encuentra. mypogram es ahora la nueva versión sin archivos por ahí.

Debe haber una forma mejor que esta, entonces, ¿cuál es la forma .net de que un programa se actualice?

PD. Lo siento si esta pregunta aparece dos veces: la primera vez que la envié, aparece una página de ''desbordamiento de pila roto''.


Es fácil cuando sabes la "solución". Su programa no puede descargarse por sí mismo porque el archivo está bloqueado por el proceso en ejecución. La solución es que todavía es posible RENOMBRAR el archivo. Así que aquí está lo que haces:

SI el nombre de su programa es "myprogram.exe":

  1. myprogram.exe se inicia
  2. Myprogram.exe descarga una nueva versión de sí mismo pero con el nombre "newversion.bak"
  3. Comprueba que newversion.bak se haya descargado correctamente (md5-check o algo así)
  4. myprogram.exe cambia el nombre de "myprogram.exe" a "myprogram.old"
  5. myprogram.exe cambia el nombre de "newversion.bak" a "myprogram.exe"
  6. myprogram.exe se reinicia, y listo, se actualiza.
  7. (opcional) myprogram.exe elimina "myprogram.old" si existe cuando se inicia.

Esto le permitirá actualizar su programa sin tener un actualizador externo.


Es posible que desee ver la implementación sin toque de .NET . Fue reemplazado, al menos en marketing, por Click-Once.

Escribí una aplicación que usaba esto. Extrajo su ensamblaje de un servidor de intranet local. Usó sockets para escuchar un puerto específico, así que pude forzar las actualizaciones enviando un mensaje, lo que generó otro programa para eliminarlo / reiniciarlo. Probablemente no sea la mejor solución pero funcionó.

Yo diría que Click-Once es una mejor solución, pero pensé que mencionaría No Touch.


Miré tanto a Wix como a ClickOnce y no los amé. Quería algo más simple, para aplicaciones WPF tipo "despliegue xcopy" de un solo archivo.

Así que construí uno. Es una clase de AppUpdater que puede colocar en cualquier aplicación de WPF, que se actualiza automáticamente cuando sea necesario.

Es fácil verificar el número de versión y descargar la última versión.

La siguiente parte es menos fácil. ¿Cómo reemplazar una aplicación en ejecución? El enfoque que tomé fue este:

  • Cada vez que se ejecuta, la aplicación comprueba una URL conocida para una versión. Si la versión NO es posterior a la versión de la aplicación que se ejecuta actualmente, no hay nada más que hacer.

  • Si la versión ES más tarde, entonces la aplicación toma un Mutex con nombre, se copia a sí misma (Assembly.GetExecutingAssembly (). Location) en una ubicación temporal, luego inicia un nuevo proceso (proceso # 2) desde esa ubicación temporal, pasando una línea de comando argumento que dice "estás intentando actualizar" y le da la ubicación original del archivo ejecutable.

  • el proceso # 1 se apaga solo.

  • el proceso # 2 se inicia: ve que está intentando actualizar, por lo que descarga la imagen actualizada y la coloca en la ubicación original (la ubicación que se pasó en la línea de comandos). En lugar de esperar 2 segundos, o cualquier momento arbitrario, utiliza el Mutex denominado para determinar cuándo ha salido el proceso # 1.

  • el proceso # 2 luego inicia el proceso # 3 - usando la ubicación original.

  • El proceso # 2 se apaga, liberando su nombre Mutex.

  • se inicia el proceso # 3. Comprueba la URL de la versión - ve que es actual. No es necesario actualizar. El proceso # 3 también espera el proceso # 2 para liberar su Mutex, y luego elimina la copia temporal del EXE, la que fue utilizada por el proceso # 2.

EDITAR

En respuesta al comentario, sí, suena complicado. Pero la lógica que hace todo eso está en el módulo AppUpdater. Usar desde una aplicación WPF es bastante simple:

public partial class Window1 : Window { public Window1() { InitializeComponent(); // add this line in your constructor if (UpdaterCheck()) this.Hide(); } // this is all boilerplate private Ionic.AppUpdater.Wpf.Updater _updater; private string _manifestUrl = "http://example.org/AppUpdates/MyApplication/Manifest.xml"; private string _infoUrl = "http://example.org/MyApplication.html"; private string _description = "MyApplication is a delightful application; it does x, y, and z. "; // Obtain the publicKey XML from the ManifestTool that ships with Ionic AppUpdater. // The following string is Ionic''s public key. You will need a different one. // Consult the Readme for more information. private string _publicKeyXml = "<RSAKeyValue><Modulus>sZqhvF0KX6m4blah..blah...=</Modulus><Exponent>AQAB</Exponent></RSAKeyValue>"; // add this boilerplate method private bool UpdaterCheck() { _updater = new Ionic.AppUpdater.Wpf.Updater("This is MyApplication.", _infoUrl, _description, _manifestUrl, _publicKeyXml); return _updater.Status.IsUpdating; } ...

Detalles y código que puede ejecutar, aquí .

Funciona solo con aplicaciones WPF, pero sería bastante simple construir una versión de WinForms de la cosa. La misma idea, aunque parte de la lógica que genera la interfaz de usuario tendría que cambiar.