Автоматичне оновлення програм на C #. Частина 2

  Кілька днів тому мною була написана стаття про реалізацію автоматичного оновлення програмного забезпечення на мові C #.
 
Взявши до уваги конструктивну критику коментаторів, було прийнято рішення поліпшити той код, додавши кілька нових можливостей, включаючи поліпшення «старих»:
 
     
  • Автоматична перевірка, скачування і установка оновлень;
  •  
  • Надання користувачеві можливості вибору моменту поновлення (нове) ;
  •  
  • Поліпшений механізм перевірки версії файлу;
  •  
  • Перевірка цілісності файлу оновлення (нове)
  •  
Щоб не передруковувати текст минулої статті , в цій акцентую увагу лише на перероблених частинах коду.
 
 
 

Основні зауваження

Коментаторами попередньої статті були виявлені наступні недоліки коду (вказую тільки ті, на які спирався):
 
     
  • Тільки краще спочатку завантажити новий файл, щоб не вийшла ситуація, коли посередині завантаження, з якихось причин, додаток завершується і користувач залишається с. bak файлів і неповним. exe, тобто без робочого додатку. (DarkByte );
  •  
  • Тільки не побачив перевірки на контрольну суму. (naum );
  •  
  • Показувати користувачеві модальное (швидше за все) інформаційне вікно з єдиною кнопкою «Ok», не залишаючи вибору — не сама хороша практика. Потрібно робити все тихо і непомітно, або ненав'язливо запропонувати оновитися з можливістю зробити це як-небудь потім, коли користувачеві буде зручніше. (iroln );
  •  
  • Порівняння версій у вас неправильне. Проблеми будуть, наприклад, при оновленні з 9.12.2 до 10.0.0. (eyeless_watcher )
  •  
  • А що заважає порівнювати безпосередньо типи Version? (teleavtomatika ).
  •  
Були, звичайно, й інші коментарі схожі з цими, але не став їх все приводити і пропоную приступити до розгляду проблем.
 
 

Внесення поправок

Так як при скачуванні файлу може виникнути яка-небудь помилка, в наслідок чого файл буде пошкоджено, в код були внесені наступні поправки:
 
 
public void checkUpdates(){
	try
	{
		if (File.Exists("launcher.update") && new Version(FileVersionInfo.GetVersionInfo("launcher.update").FileVersion) > new Version(Application.ProductVersion))
		{
			Process.Start("updater.exe", "launcher.update \"" + Process.GetCurrentProcess().ProcessName + "\"");
			Process.GetCurrentProcess().CloseMainWindow();
		}
		else
		{
			if (File.Exists("launcher.update")) { File.Delete("launcher.update"); }
			Download();
		}
	}
	catch (Exception)
	{
		if (File.Exists("launcher.update")) { File.Delete("launcher.update"); }
		Download();
	}
}

Спочатку ми перевіряємо чи існує файл оновлень launcher.update , а також перевіряємо версію файлу, так як нам не важливо його розширення. У разі, якщо файл пошкоджений, спрацює обробник виключень try catch , виконавши код з видалення пошкодженого файлу з наступним запуском функції перевірки і скачування (якщо знайдені) оновлень на сайті.
Якщо ж файл виявиться цілим і його версія буде вище поточної, то запускається додаткова утиліта updater.exe для проведення операцій по заміні основного файлу програми. Розписувати докладніше не стану, так як це вже було раннє .
 
Таким чином, ми переконаємося в цілісності файлу оновлення.
 
 
private void Download()
{
	try
	{
		XmlDocument doc = new XmlDocument();
		doc.Load(@"http://mysite/version.xml");

		remoteVersion = new Version(doc.GetElementsByTagName("version")[0].InnerText);
		localVersion = new Version(Application.ProductVersion);

		if (localVersion < remoteVersion)
		{
			if (File.Exists("launcher.update")) { File.Delete("launcher.update"); }

			WebClient client = new WebClient();
			client.DownloadProgressChanged += new DownloadProgressChangedEventHandler(ProgressChanged);
			client.DownloadFileCompleted += new AsyncCompletedEventHandler(Completed);
			client.DownloadFileAsync(new Uri(@"http://mysite/launcher.exe"), "launcher.update");
		}
	}
	catch (Exception) { }
}

Далі зазнала змін функція процесу перевірки версії файлу, ключовим моментом якого є реалізація порівняння версій файлу за допомогою вбудованих засобів System.Version , в наслідок чого була усунена проблема коректної звірки версій, скажімо, «9.12.2» і «10.0.0».
У разі, коли виявлена ​​більш нова версія, дії відбуваються за наступним сценарієм: програма автоматично у фоновому режимі викачує файл оновлення, потім видає користувачеві повідомлення про доступність цього оновлення і пропонує на вибір 2 варіанти розвитку подій:
 
     
  1. Погоджуючись на оновлення , програма моментально перезапускається, зробивши всі необхідні дії;
  2.  
  3. Відмовляючись від оновлення програма зберігає файл поруч з виконуваним файлом, куди і було завантажено. У даному варіанті процес оновлення відбудеться при наступному запуску програми не виводячи жодних повідомлень.
  4.  
 
 

Висновок

Переписаний код вийшов більш досконалим у порівнянні з попереднім варіантом, а також виключає ймовірність застосування поновлення на «битому» файлі, а також відсутність реалізації функції перевірки контрольної суми завантаженого файлу з версією на сервері.
 
І окреме спасибі хотілося б сказати наступним людям за їх конструктивну критику: DarkByte , naum , iroln , eyeless_watcher , teleavtomatika , wire .
 
 З повагою, Андрій Helldar!
 
PS: люди добрі з числа мінусуючих — будьте ласкаві в коментарях пишіть чому Ви так вирішили. Цікаво ж знати де я не правий.
  
Джерело: Хабрахабр

0 коментарів

Тільки зареєстровані та авторизовані користувачі можуть залишати коментарі.