Jak zachować ustawienia user.config w różnych wersjach zestawu w .net?

146

Zasadniczo problem polega na tym, że za każdym razem, gdy zmienia się wersja zestawu (tj. Użytkownik instaluje nową wersję aplikacji), wszystkie ich ustawienia są resetowane do wartości domyślnych (a dokładniej nowy plik user.config jest tworzony w folderze z inną wersją numer jako nazwa)

Jak mogę zachować te same ustawienia podczas aktualizacji wersji, skoro używanie plików ini lub rejestru wydaje się być odradzane?

Kiedy używaliśmy Clickonce, wydawało się, że jest w stanie sobie z tym poradzić, więc wydaje się, że powinno to być możliwe, ale nie jestem pewien, jak.

Davy8
źródło
Podobne pytanie ?
Allen Rice
Nie, to odnosi się do domyślnego braku sprawdzania pliku w kontroli wersji (a
przynajmniej
Tylko pytanie, którego potrzebowałem, dzięki :)
Binary Worrier
Zamieściłem możliwe rozwiązanie w następującym wątku: stackoverflow.com/a/47921377/3223783 Mam nadzieję, że to pomoże!
dontbyteme
W tym wątku zamieściłem możliwe rozwiązanie . Mam nadzieję, że to pomoże!
dontbyteme

Odpowiedzi:

236

ApplicationSettingsBase ma metodę o nazwie Upgrade, która migruje wszystkie ustawienia z poprzedniej wersji.

Aby uruchomić scalanie za każdym razem, gdy publikujesz nową wersję aplikacji, możesz zdefiniować flagę logiczną w pliku ustawień, która domyślnie ma wartość true. Nazwij to UpgradeRequired lub podobną.

Następnie przy uruchomieniu aplikacji sprawdzasz, czy flaga jest ustawiona, a jeśli tak, wywołaj metodę Upgrade , ustaw flagę na false i zapisz konfigurację.

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

Przeczytaj więcej o metodzie uaktualnienia w witrynie MSDN . GetPreviousVersion może również być warte obejrzenia, jeśli trzeba zrobić jakąś niestandardową scalenie.

Markus Olsson
źródło
2
Małe pytanie, co składa się na nową wersję? Jakaś część numeru części 4? Używam ClickOnce, więc czy to inne zwierzę?
Refracted Paladin
4
Jakiego rodzaju ustawienia powinno być wymagane uaktualnienie ? appSettings, userSettingslub applicationSettings? Jako ustawienie użytkownika w Ustawieniach.Settings, po pierwszej zmianie na fałsz nigdy już nie będzie prawdziwe. Nowa wersja nie zresetuje tego UpgradeRequired z powrotem do True.
dialex
4
@dialex To musi być ustawienie użytkownika. Ustawienia typu Aplikacja są tylko do odczytu. Nowe numery wersji powodują resetowanie ustawień, ponieważ są one przechowywane w ścieżce specyficznej dla wersji.
Leonard Thieu
4
Myślę, że odpowiedziałem na własne pytanie. Jeśli istnieje poprzednia wersja pliku ustawień, skopiuje ona swoje wartości do najnowszej wersji przy każdym uruchomieniu aplikacji, prawdopodobnie nie to, czego chcesz!
Hugh Jeffner
1
Jestem trochę zaskoczony, że nie jest to tylko domyślne zachowanie; jeśli ustawienia aplikacji są zerowe przy starcie i znajdzie poprzednią grupę ustawień, ładuje je.
SteveCinq
3

Wiem, że minęło trochę czasu ... W aplikacji winForm wystarczy zadzwonić, My.Settings.Upgrade()zanim je załadujesz. Spowoduje to uzyskanie najnowszych ustawień, niezależnie od tego, czy jest to aktualna wersja, czy poprzednia wersja.

tinlyx
źródło
2

Oto moje badania na wypadek, gdyby ktoś inny miał trudności z migracją ustawień, które zostały zmienione / usunięte. Podstawowy problem polega na tym, GetPreviousVersion()że nie działa, jeśli zmienisz nazwę lub usunąłeś ustawienie w nowej wersji aplikacji. Musisz więc zachować ustawienie w swojej Settingsklasie, ale dodać do niego kilka atrybutów / artefaktów, aby nie przypadkowo użyć go w kodzie w innym miejscu, przez co stanie się przestarzały. Przykładowe przestarzałe ustawienie wyglądałoby tak w VB.NET (można je łatwo przetłumaczyć na 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

Upewnij się, że dodajesz tę właściwość do tej samej przestrzeni nazw / klasy, która zawiera ustawienia aplikacji. W VB.NET ta klasa ma nazwę MySettingsi jest dostępna wMy przestrzeni nazw. Możesz użyć funkcji częściowych klas, aby zapobiec pomieszaniu przestarzałych ustawień z bieżącymi ustawieniami.

Pełne uznanie dla jsharrison za opublikowanie świetnego artykułu na ten temat. Możesz przeczytać więcej szczegółów na ten temat.

dotNET
źródło
1

Oto odmiana przedstawionych tutaj rozwiązań, która hermetyzuje logikę uaktualniania do klasy abstrakcyjnej, z której mogą pochodzić klasy ustawień.

Niektóre proponowane rozwiązania używają atrybutu DefaultSettingsValue do określenia wartości wskazującej, kiedy poprzednie ustawienia nie zostały załadowane. Wolę po prostu użyć typu, którego wartość domyślna to wskazuje. Jako bonus, DateTime? to przydatne informacje do debugowania.

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();
    }
}

Pochodzi z UserSettingsBase:

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

    public MySettings() : base() { }
}

I użyj go:

// Existing settings are loaded and upgraded if needed
MySettings settings = new MySettings();
...
settings.SomeSetting = "SomeValue";
...
settings.Save();
jeff krueger
źródło
0

Jeśli zmiany w user.settings są wykonywane programowo, co powiesz na utrzymywanie kopii (tylko) modyfikacji user.settings w oddzielnym pliku, np. User.customized.settings?

Prawdopodobnie nadal chcesz zachować i załadować zmodyfikowane ustawienia również w pliku user.settings. Ale w ten sposób, gdy instalujesz nowszą wersję swojej aplikacji z nowszą wersją user.settings, możesz zapytać użytkownika, czy chce nadal używać zmodyfikowanych ustawień, kopiując je z powrotem do nowego user.settings. Możesz zaimportować je hurtowo lub stać się bardziej wyszukanym i poprosić użytkownika o potwierdzenie, których ustawień chce nadal używać.

EDYCJA: Zbyt szybko przeczytałem część „dokładniej” dotyczącą wersji assemblera powodującej instalację nowego pliku user.settings w nowym katalogu specyficznym dla wersji. Dlatego powyższy pomysł prawdopodobnie ci nie pomoże, ale może dać do myślenia.

JMD
źródło
0

Oto jak sobie z tym poradziłem:

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;

}

aw klasie settings zdefiniowałem właściwość 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; }
}

W SaveSettings ustawiłem IsDefault na 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();
}
Ian
źródło