Как сохранить настройки user.config для разных версий сборки в.net?

В основном проблема заключается в том, что каждый раз, когда изменяется версия сборки (то есть пользователь устанавливает новую версию приложения), все их настройки сбрасываются по умолчанию (или, точнее, новый файл user.config создается в папке с другой версией номер как имя)

Как я могу сохранить те же настройки при обновлении версий, поскольку использование файлов ini или реестра кажется не рекомендуется?

Когда мы использовали Clickonce, казалось, что он мог справиться с этим, поэтому кажется, что это должно быть в состоянии сделать, но я не уверен, как.

7 ответов

Решение

В ApplicationSettingsBase есть метод Upgrade, который переносит все настройки из предыдущей версии.

Чтобы выполнять слияние при публикации новой версии вашего приложения, вы можете определить логический флаг в файле настроек, который по умолчанию имеет значение true. Назовите его UpgradeRequired или что-то подобное.

Затем при запуске приложения вы проверяете, установлен ли флаг, и если это так, вызовите метод Upgrade, установите флаг в false и сохраните свою конфигурацию.

if (Settings.Default.UpgradeRequired)
{
    Settings.Default.Upgrade();
    Settings.Default.UpgradeRequired = false;
    Settings.Default.Save();
}

Узнайте больше о методе обновления на MSDN. GetPreviousVersion может также стоить посмотреть, если вам нужно выполнить какое-то пользовательское слияние.

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

if (!ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.PerUserRoamingAndLocal).HasFile)
    Settings.Default.Upgrade();

Я знаю, что это было какое-то время... В приложении Winforms просто позвоните My.Settings.Upgrade() прежде чем загрузить их. Это позволит получить последние настройки, будь то текущая версия или предыдущая версия.

Вот мое исследование на случай, если кому-то еще трудно перенести изменения, которые были изменены / удалены. Основная проблема заключается в том, что GetPreviousVersion() не работает, если вы переименовали или удалили настройку в новой версии вашего приложения. Так что вам нужно сохранить настройки в вашем Settings класса, но добавьте к нему несколько атрибутов / артефактов, чтобы вы случайно не использовали его в коде в другом месте, что делает его устаревшим. Пример устаревшей настройки будет выглядеть в VB.NET следующим образом (его можно легко перевести на C#):

<UserScopedSetting(),
DebuggerNonUserCode(),
DefaultSettingValue(""),
Obsolete("Do not use this property for any purpose. Use YOUR_NEW_SETTING_NAME instead."),
NoSettingsVersionUpgrade()>
Public Property OldSettingName() As String
  Get
    Throw New NotSupportedException("This property is obsolete")
  End Get
  Set
    Throw New NotSupportedException("This property is obsolete")
  End Set
End Property

Убедитесь, что вы добавили это свойство в то же пространство имен / класс, в котором находятся настройки вашего приложения. В VB.NET этот класс называется MySettings и доступен в My Пространство имен. Вы можете использовать частичную функциональность класса, чтобы предотвратить смешивание устаревших настроек с текущими настройками.

Полная благодарность jsharrison за публикацию отличной статьи по этому вопросу. Вы можете прочитать более подробную информацию об этом там.

Вот вариант решений, представленных здесь, которые инкапсулируют логику обновления в абстрактный класс, из которого классы настроек могут быть получены.

Некоторые предлагаемые решения используют атрибут DefaultSettingsValue, чтобы указать значение, которое указывает, когда предыдущие параметры не были загружены. Я предпочитаю просто использовать тип, значение которого по умолчанию указывает на это. В качестве бонуса, DateTime? полезна отладочная информация.

public abstract class UserSettingsBase : ApplicationSettingsBase
{
    public UserSettingsBase() : base()
    {
        // Accessing a property attempts to load the settings for this assembly version
        // If LastSaved has no value (default) an upgrade might be needed
        if (LastSaved == null)
        {
            Upgrade();
        }
    }

    [UserScopedSetting]
    public DateTime? LastSaved
    {
        get { return (DateTime?)this[nameof(LastSaved)]; }
        private set { this[nameof(LastSaved)] = value; }
    }

    public override void Save()
    {
        LastSaved = DateTime.Now;
        base.Save();
    }
}

Производная от UserSettingsBase:

public class MySettings : UserSettingsBase
{
    [UserScopedSetting]
    public string SomeSetting
    {
        get { return (string)this[nameof(SomeSetting)]; }
        set { this[nameof(SomeSetting)] = value; }
    }

    public MySettings() : base() { }
}

И использовать это:

// Existing settings are loaded and upgraded if needed
MySettings settings = new MySettings();
...
settings.SomeSetting = "SomeValue";
...
settings.Save();

Вот как я справился с этим:

public virtual void LoadSettings(ServiceFileFormBaseSettings settings = null, bool resetSettingsToDefaults = false)
{
    if (settings == null)
            return;

    if (resetSettingsToDefaults)
        settings.Reset();
    else
    {
        settings.Reload();

        if (settings.IsDefault)
            settings.Upgrade();
    }

    this.Size = settings.FormSize;

}

и в классе настроек я определил свойство IsDefault:

// SaveSettings always sets this to be FALSE.
// This will have the default value TRUE when first deployed, or immediately after an upgrade.
// When the settings exist, this is false.
//
[UserScopedSettingAttribute()]
[DefaultSettingValueAttribute("true")]
public virtual bool IsDefault
{
    get { return (bool)this["IsDefault"]; }
    set { this["IsDefault"] = value; }
}

В SaveSettings я установил для IsDefault значение false:

public virtual void SaveSettings(ServiceFileFormBaseSettings settings = null)
{
    if (settings == null) // ignore calls from this base form, if any
        return;

    settings.IsDefault = false;
    settings.FormSize = this.Size;
    settings.Save();
}

Если ваши изменения в user.settings сделаны программно, как насчет сохранения копии (просто) изменений для user.settings в отдельном файле, например, user.customized.settings?

Вы, вероятно, все еще хотите сохранить и загрузить измененные настройки в user.settings. Но таким образом, когда вы устанавливаете более новую версию своего приложения с более новой версией user.settings, вы можете спросить пользователя, хотят ли они продолжать использовать свои измененные настройки, скопировав их обратно в новый user.settings. Вы можете импортировать их оптом или стать более любопытными и попросить пользователя подтвердить, какие настройки они хотят продолжать использовать.

РЕДАКТИРОВАТЬ: я слишком быстро прочитал "более точную" часть о версиях сборки, в результате чего новые user.settings были установлены в новый каталог для конкретной версии. Таким образом, идея выше, вероятно, не поможет вам, но может дать пищу для размышлений.

Простое решение состоит в том, чтобы изменить только версию файла (то, что "отображается в проводнике Windows") и сохранить ту же версию сборки (то есть "номер версии, используемый платформой во время сборки и во время выполнения для определения местоположения, ссылки и загрузки"). собрания ").

Источник: https://support.microsoft.com/en-ca/help/556041

Другие вопросы по тегам