Как сохранить файл конфигурации при значительном обновлении в wix v3.8?
Я хочу сохранить файл конфигурации, когда установщик MSI делает серьезное обновление. Для файла конфигурации я делаю изменения при установке. Код выглядит следующим образом:
<Component Id="MODIFYCONFIG" Guid="6A1D7762-B707-4084-A01F-6F936CC159CE" Win64="yes">
<File Id="Application.config" Name="Application.config" Vital="yes" KeyPath="yes" Source="Resource\Application.config"></File>
<util:XmlFile Id="SetValueIP" Action="setValue" Permanent="yes" File="[#Application.config]"
ElementPath="/configuration/applicationSettings/Application.Properties.Settings/setting[\[]@name='IpAddress'[\]]/value" Value="[IPADDRESS]" Sequence="1"/>
<util:XmlFile Id="SetValuePort" Action="setValue" Permanent="yes" File="[#Application.config]"
ElementPath="/configuration/applicationSettings/Application.Properties.Settings/setting[\[]@name='IpPort'[\]]/value" Value="[PORT]" Sequence="2"/>
<Condition>Not Installed</Condition>
</Component>
<Component Id="KEEPCONFIG" Guid="F7F173AA-C2FD-4017-BFBC-B81852A671E7" Win64="yes">
<RemoveFile Id="ApplicationConfig" Name="Application.config" On="uninstall"/>
<Condition>(REMOVE=ALL) AND (NOT UPGRADINGPRODUCTCODE)</Condition>
</Component>
Но когда происходит серьезное обновление, файл не сохраняется. Как я могу сохранить измененный файл?
4 ответа
Это решило это для меня... файл конфигурации сохранен с незначительным / главным обновлением и полностью удален при удалении.
Ссылка: http://blogs.msdn.com/b/astebner/archive/2008/10/19/9006538.aspx
РЕДАКТИРОВАТЬ: Обобщенная информация со связанной страницы...
- Каждый файл конфигурации должен иметь свой собственный компонент, где файл конфигурации помечается как ключевой путь компонента. Неверная логика замены файлов будет использоваться установщиком Windows.
- Добавьте действие "RemoveExistingProducts" после действия "InstallFiles". Новые версии всех компонентов устанавливаются перед удалением старого MSI. Когда это будет сделано в этой последовательности, счетчики ссылок будут увеличены до 2, но файлы конфигурации не будут заменены, если они не изменены (из-за неверсионной логики замены файлов). При удалении старого MSI счетчик ссылок будет уменьшен до 1, но файлы не будут удалены, поскольку счетчик ссылок не равен 0.
У вас есть 3 варианта при обновлении:
- Сделайте компонент файла конфигурации постоянным. Это не удалит его, и вы сможете обновить его, но удалить его будет очень сложно.
- Используйте шаблон свойства Remember для сохранения настроек реестра для IP и PORT в реестре.
- В процессе установки запишите файл конфигурации во временное имя файла, а затем используйте команду CopyFile для создания файла назначения. При обновлении проверьте файл, используя FileSearch, и, если он существует, не копируйте. Проблема здесь только в том, что если файл конфигурации изменился, вы не получите обновленные разделы.
Лучший вариант - помнить меня, так как здесь меньше всего проблем.
Это заняло у меня некоторое время, но вот как я решил это сам. Вероятно, это вариант третьего варианта caveman_dick.
1) Добавьте новое действие в UISequence для резервного копирования вашего текущего файла конфигурации. Вы можете сделать это с помощью волшебства пользовательских действий и ComponentSearch, чтобы фактически найти файл.
2) Восстановите файл позже в ExecuteSequence.
<Binary Id="CustomActions.CA.dll" SourceFile="..\CustomActions\bin\$(var.Configuration)\CustomActions.CA.dll" />
<CustomAction Id="BackupConfigFile"
Return="check"
BinaryKey="CustomActions.CA.dll"
DllEntry="BackupFile" />
<CustomAction Id="RestoreConfigFile"
Return="check"
Execute="deferred"
Impersonate="no"
BinaryKey="CustomActions.CA.dll"
DllEntry="RestoreFile" />
<CustomAction Id="PropertyDelegator"
Property="RestoreConfigFile"
Value="MYTARGET=[MYTARGET];FILENAME_TO_BACKUP=[FILENAME_TO_BACKUP]" />
<Property Id="FILENAME_TO_BACKUP" Value="test.exe.config" />
<Property Id="PREVIOUS_PATH">
<ComponentSearch Id="evSearch" Guid="{010447A6-3330-41BB-8A7A-70D08ADB35E4}" />
</Property>
и вот быстрый CustomAction.cs, который я написал:
[CustomAction]
public static ActionResult BackupFile(Session session)
{
try
{
// check out if the previous installation has our file included
// and if it does,
// then make copy of it.
var previousInstallationPath = session["PREVIOUS_PATH"];
var fileToBackup = session["FILENAME_TO_BACKUP"];
if (!string.IsNullOrEmpty(previousInstallationPath) && !string.IsNullOrEmpty(fileToBackup))
{
var absolutePath = Path.Combine(previousInstallationPath, fileToBackup);
if (File.Exists(absolutePath))
{
var destinationPath = Path.Combine(Path.GetTempPath(),
string.Concat(fileToBackup, _MODIFIER));
File.Copy(absolutePath, destinationPath);
}
}
}
catch (Exception e)
{
session.Log("Couldn't backup previous file: {0}", e);
}
return ActionResult.Success;
}
[CustomAction]
public static ActionResult RestoreFile(Session session)
{
try
{
// check if our CustomAction made backup of file,
// and if it indeed exists in temp path, then
// we basically copy it back.
var currentInstallationPath = session.CustomActionData["MYTARGET"];
var fileToRestore = session.CustomActionData["FILENAME_TO_BACKUP"];
var fileOriginalContentPath = Path.Combine(Path.GetTempPath(),
string.Concat(fileToRestore, _MODIFIER));
if (File.Exists(fileOriginalContentPath))
{
var destinationFile = Path.Combine(currentInstallationPath, fileToRestore);
if (File.Exists(destinationFile))
File.Delete(destinationFile);
File.Move(fileOriginalContentPath, destinationFile);
}
}
catch (Exception e)
{
session.Log("Couldn't restore previous file: {0}", e);
}
return ActionResult.Success;
}
на самом деле определить последовательности:
<InstallUISequence>
<Custom Action="BackupConfigFile" After="AppSearch"></Custom>
</InstallUISequence>
<InstallExecuteSequence>
<Custom Action="PropertyDelegator" Before="RestoreConfigFile" />
<Custom Action="RestoreConfigFile" After="InstallFiles"></Custom>
</InstallExecuteSequence>
не проверил это полностью, но, кажется, делает работу на данный момент. Предостережение: временная папка может измениться?!
В качестве альтернативы есть тот, который я нашел в Интернете, но не проверял.
<!-- Support Upgrading the Product -->
<Upgrade Id="{B0FB80ED-249E-4946-87A2-08A5BCA36E7E}">
<UpgradeVersion Minimum="$(var.Version)"
OnlyDetect="yes" Property="NEWERVERSIONDETECTED" />
<UpgradeVersion Minimum="0.0.0"
Maximum="$(var.Version)" IncludeMinimum="yes"
IncludeMaximum="no"
Property="OLDERVERSIONBEINGUPGRADED" />
</Upgrade>
<Property Id="OLDERVERSIONBEINGUPGRADED" Secure="yes" />
<!-- Action to save and Restore the Config-File on reinstall
-->
<!-- We're using CAQuietExec to prevent DOS-Boxes from
popping up -->
<CustomAction Id="SetQtCmdLineCopy" Property="QtExecCmdLine"
Value=""[SystemFolder]cmd.exe" /c copy
"[INSTALLDIR]MyApp.exe.config"
"[INSTALLDIR]config.bak"" />
<CustomAction Id="QtCmdCopy" BinaryKey="WixCA"
DllEntry="CAQuietExec" Execute="immediate" />
<CustomAction Id="SetQtCmdLineRestore"
Property="QtCmdRestore" Value=""[SystemFolder]cmd.exe" /c move
/Y "[INSTALLDIR]config.bak"
"[INSTALLDIR]MyApp.exe.config"" />
<CustomAction Id="QtCmdRestore" Execute="commit"
BinaryKey="WixCA" DllEntry="CAQuietExec" />
<!-- These actions will run only for a major upgrade -->
<InstallExecuteSequence>
<Custom Action="SetQtCmdLineCopy"
After="InstallInitialize"> NOT (OLDERVERSIONBEINGUPGRADED = "")</Custom>
<Custom Action="QtCmdCopy"
After="SetQtCmdLineCopy">NOT (OLDERVERSIONBEINGUPGRADED = "")</Custom>
<Custom Action="SetQtCmdLineRestore"
Before="InstallFinalize">NOT (OLDERVERSIONBEINGUPGRADED = "")</Custom>
<Custom Action="QtCmdRestore"
After="SetQtCmdLineRestore">NOT (OLDERVERSIONBEINGUPGRADED =
"")</Custom>
</InstallExecuteSequence>
Добавлять Schedule="afterInstallExecuteAgain"
в MajorUpgrade
<MajorUpgrade DowngradeErrorMessage="A newer version of [ProductName] is already installed." Schedule="afterInstallExecuteAgain" />
Это работает для меня
Есть и другой вариант, но он может не подходить к вашему сценарию - все зависит от того, кто изначально запускает ваш установщик...
Если ваше приложение загружается, например, через Интернет, то мы обычно используем шаблон свойств caveman_dick запомнить.
Однако у нас есть несколько наборов продуктов, которые всегда устанавливаются нашими собственными специалистами по установке, которые посещают сайт клиентов. В этом случае просто не включайте файл конфигурации в установщик!
Проще говоря - если установщик не знает о файле, он не будет удален!
В этом случае у вас есть возможность вашей команды установки создать и настроить файл конфигурации, или ваше приложение создает его, когда он не существует, и запрашивает у пользователя значения.
Как уже говорилось, это не будет вариантом в некоторых сценариях, но он отлично работает для наших.