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

146

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

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

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

Davy8
источник
Подобный вопрос ?
Аллен Райс
Нет, это относится к тому, чтобы по умолчанию не проверять файл в системе управления версиями (или я так понял) Это касается (Windows) пользовательских настроек для конечного пользователя
Davy8
Просто вопрос, который мне был нужен, спасибо :)
Binary Worrier
Я разместил возможное решение в следующей теме: stackoverflow.com/a/47921377/3223783 Надеюсь, это поможет!
dontbyteme
Я разместил возможное решение в этой теме . Надеюсь, это поможет!
dontbyteme

Ответы:

236

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

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

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

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

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

Маркус Олссон
источник
2
Небольшой вопрос, что представляет собой новая версия? Любая часть из 4-х частей? Я использую ClickOnce, так это другое животное?
преломил паладин
4
Какой тип настройки должен быть UpgradeRequired ? appSettings, userSettingsили applicationSettings? Как пользовательский параметр в Settings.Settings, после первого изменения значения false он никогда не будет верным. Новая версия не вернет значение UpgradeRequired обратно в True.
dialex
4
@dialex Это должна быть настройка пользователя. Настройки типа Приложения доступны только для чтения. Новые номера версий приводят к сбросу настроек, поскольку настройки хранятся в пути к конкретной версии.
Леонард Тьё,
4
Я думаю, что ответил на свой вопрос. Если предыдущая версия файла настроек существует, он будет копировать свои значения в самую новую версию при каждом запуске приложения, вероятно, не то, что вам нужно!
Хью Джеффнер
1
Я немного удивлен, что это не просто поведение по умолчанию; если настройки приложения при запуске не заданы и оно находит предыдущую группу настроек, оно загружает их.
SteveCinq
3

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

tinlyx
источник
2

Вот мое исследование на случай, если кому-то еще будет трудно перенести настройки, которые были изменены / удалены. Основная проблема заключается в том, 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 за публикацию отличной статьи по этому вопросу. Вы можете прочитать более подробную информацию об этом там.

Dotnet
источник
1

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

Некоторые предлагаемые решения используют атрибут 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();
Джефф Крюгер
источник
0

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

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

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

JMD
источник
0

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

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();
}
Ян
источник