Обновления программы - QualitySolution/QSProjects GitHub Wiki

Модуль обновлений приложения состоит из двух частей:

  • проверка и установка обновлений приложения;
  • координация процесса через VersionCheckerService.

Для обновления приложения сейчас используется связка IAppUpdater + VersionCheckerService.

Если вашему проекту нужно обновлять еще и базу данных, используйте отдельную статью: Обновление базы данных.

Минимальная настройка модуля (только обновление приложения)

Ниже приведен актуальный минимальный набор регистраций в Autofac.

#region Gtk UI
builder.RegisterType<GtkGuiDispatcher>().As<IGuiDispatcher>();
builder.RegisterType<GtkWindowsNavigationManager>()
	.AsSelf()
	.As<INavigationManager>()
	.SingleInstance();
#endregion

#region База
builder.Register(c => QSProjectsLib.QSMain.ConnectionStringBuilder).AsSelf();
builder.Register(c => new MySqlConnectionFactory(Connection.ConnectionString)).As<IConnectionFactory>();
builder.Register(c => c.Resolve<IConnectionFactory>().OpenConnection())
	.As<DbConnection>()
	.InstancePerLifetimeScope();
builder.RegisterType<ParametersService>().AsSelf();
#endregion

#region Версии и обновления
builder.RegisterType<ApplicationVersionInfo>().As<IApplicationInfo>();

builder.RegisterModule(new UpdaterDesktopAutofacModule());
builder.RegisterModule(new UpdaterAppAutofacModule());
#endregion

Что регистрируют модули:

  • UpdaterDesktopAutofacModuleCheckBaseVersion и VersionCheckerService;
  • UpdaterAppAutofacModuleIAppUpdater, ReleasesService, ISkipVersionState, NewVersionViewModel;

Если проекту нужно обновлять базу данных

Для сценариев с миграциями базы используйте отдельную статью: Обновление базы данных.

В этой статье описывается только общий чекер обновлений приложения.

Автоматическая проверка обновлений при старте

Актуальный способ — получить VersionCheckerService из DI и вызвать RunUpdate():

using(var scope = MainClass.AppDIContainer.BeginLifetimeScope()) {
	var checker = scope.Resolve<VersionCheckerService>();
	UpdateInfo? updateInfo = checker.RunUpdate();

	if(updateInfo?.Status == UpdateStatus.AppUpdateIsRunning) {
		quitService.Quit();
		return;
	}

	if(updateInfo?.Status == UpdateStatus.ConnectionError) {
		logger.Warn(updateInfo.Value.Message);
	}

	if(updateInfo?.Status == UpdateStatus.BaseError) {
		interactive.ShowMessage(updateInfo.Value.ImportanceLevel, updateInfo.Value.Message, updateInfo.Value.Title);
		quitService.Quit();
		return;
	}

	if(updateInfo?.Status == UpdateStatus.ExternalError) {
		interactive.ShowMessage(updateInfo.Value.ImportanceLevel, updateInfo.Value.Message, updateInfo.Value.Title);
		quitService.Quit();
		return;
	}
}

Именно этот сценарий рекомендуется вызывать при старте главного окна.

Что делает VersionCheckerService.RunUpdate()

Сервис объединяет несколько шагов:

  1. проверяет совместимость версии приложения и базы через CheckBaseVersion;
  2. если подключен IAppUpdater, вызывает CheckUpdate();
  3. если доступно обновление приложения, показывает окно через IAppUpdater.RunUpdate();
  4. возвращает UpdateInfo? со статусом результата.

Если в проекте подключен модуль обновления БД, VersionCheckerService также сможет координировать этот шаг. Подробности и настройка — в Обновление базы данных.

Поэтому для автоматического сценария лучше использовать именно VersionCheckerService, а не напрямую IAppUpdater.

Ручная проверка обновлений по кнопке или пункту меню

Для ручной проверки теперь нужно использовать IAppUpdater в два шага:

using(var scope = MainClass.AppDIContainer.BeginLifetimeScope()) {
	var updater = scope.Resolve<IAppUpdater>();
	updater.CheckUpdate();
	updater.RunUpdate();
}

Это важно:

  • CheckUpdate() только получает информацию о доступных релизах;
  • RunUpdate() показывает окно новой версии или сообщение, что обновлений нет / произошла ошибка;
  • параметра manualRun у CheckUpdate() больше нет.

Если вызвать только RunUpdate() без предварительного CheckUpdate(), у обновлятора не будет актуальных результатов проверки.

Каналы обновлений

В модуле приложения поддерживаются каналы:

  • UpdateChannel.Current — текущий;
  • UpdateChannel.Stable — стабильный;
  • UpdateChannel.Off — не проверять обновления автоматически.

Значение хранится в конфигурации по ключу:

AppUpdater:Channel

Если выбран UpdateChannel.Off, то ApplicationUpdater.CheckUpdate() не обращается к серверу обновлений и возвращает информационный результат.

Отключить автоматическую проверку можно, например, так:

configuration["AppUpdater:Channel"] = nameof(UpdateChannel.Off);

Так же это делает NewVersionViewModel.OffAutoUpdate() из окна новой версии.

Пропуск версии

Состояние пропущенной версии хранится через ISkipVersionState.

  • при ручном пропуске в окне новой версии вызывается SkipVersion();
  • при следующем автозапуске VersionCheckerService учитывает это состояние;
  • если версия базы уже новее, чем установленная версия приложения, пропуск может быть проигнорирован, чтобы не оставить приложение несовместимым с базой.

Точки входа

Актуальные точки входа:

  • автоматическая проверкаVersionCheckerService.RunUpdate();
  • ручная проверкаIAppUpdater.CheckUpdate() + IAppUpdater.RunUpdate().