Wie behalten Sie die Einstellungen für user.config in verschiedenen Assemblyversionen in .net bei?


146

Grundsätzlich besteht das Problem darin, dass jedes Mal, wenn sich die Assemblyversion ändert (dh der Benutzer installiert eine neue Version der Anwendung), alle Einstellungen auf die Standardeinstellungen zurückgesetzt werden (oder genauer gesagt, eine neue user.config-Datei wird in einem Ordner mit einer anderen Version erstellt Nummer als Name)

Wie kann ich beim Aktualisieren von Versionen dieselben Einstellungen beibehalten, da von der Verwendung von INI-Dateien oder der Registrierung abgeraten wird?

Als wir Clickonce verwendeten, schien es in der Lage zu sein, damit umzugehen, also sollte es möglich sein, aber ich bin mir nicht sicher, wie.



Nein, das bezieht sich auf die Standardeinstellung, dass eine Datei nicht in die Versionskontrolle eingecheckt wird (oder wie ich festgestellt habe). Dies bezieht sich auf (Windows) benutzerspezifische Einstellungen für einen Endbenutzer
Davy8

Nur die Frage, die ich brauchte, danke :)
Binary Worrier

Ich habe eine mögliche Lösung im folgenden Thread veröffentlicht: stackoverflow.com/a/47921377/3223783 Hoffe, das hilft!
Dontbyteme

Ich habe eine mögliche Lösung in diesem Thread gepostet . Hoffentlich hilft das!
Dontbyteme

Antworten:


236

ApplicationSettingsBase verfügt über eine Methode namens Upgrade, mit der alle Einstellungen aus der vorherigen Version migriert werden.

Um die Zusammenführung auszuführen, wenn Sie eine neue Version Ihrer Anwendung veröffentlichen, können Sie in Ihrer Einstellungsdatei ein boolesches Flag definieren, das standardmäßig true ist. Nennen Sie es UpgradeRequired oder ähnliches.

Überprüfen Sie dann beim Start der Anwendung, ob das Flag gesetzt ist, und rufen Sie gegebenenfalls die Upgrade-Methode auf , setzen Sie das Flag auf false und speichern Sie Ihre Konfiguration.

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

Lesen Sie mehr über die Upgrade-Methode bei MSDN . Die GetPreviousVersion ist möglicherweise auch einen Blick wert, wenn Sie eine benutzerdefinierte Zusammenführung durchführen müssen.


2
Eine kleine Frage, was macht eine neue Version aus? Irgendein Teil der 4 Teilenummer? Ich benutze ClickOnce, ist das also ein anderes Tier?
Gebrochener Paladin

4
Welche Art von Einstellung sollte UpgradeRequired sein? appSettings, userSettingsOder applicationSettings? Als Benutzereinstellung in Settings.Settings wird es beim ersten Ändern in false nie wieder wahr sein. Eine neue Version setzt ein UpgradeRequired nicht auf True zurück.
Dialex

4
@dialex Es muss eine Benutzereinstellung sein. Einstellungen vom Typ Anwendung sind schreibgeschützt. Neue Versionsnummern führen dazu, dass Einstellungen zurückgesetzt werden, da die Einstellungen in einem versionierungsspezifischen Pfad gespeichert werden.
Leonard Thieu

4
Ich glaube, ich habe meine eigene Frage beantwortet. Wenn eine frühere Version der Einstellungsdatei vorhanden ist, werden die Werte bei jedem Start der App in die neueste Version kopiert, wahrscheinlich nicht das, was Sie möchten!
Hugh Jeffner

1
Ich bin ein bisschen überrascht, dass dies nicht nur das Standardverhalten ist. Wenn die Einstellungen der Anwendung beim Start null sind und eine vorherige Reihe von Einstellungen gefunden wird, werden sie geladen.
SteveCinq

3

Ich weiß, dass es eine Weile her ist ... Rufen My.Settings.Upgrade()Sie in einer Winforms-App einfach an, bevor Sie sie laden. Dadurch werden die neuesten Einstellungen abgerufen, unabhängig davon, ob es sich um die aktuelle oder eine frühere Version handelt.


2

Hier ist meine Forschung für den Fall, dass es jemand anderem schwer fällt, Einstellungen zu migrieren, die geändert / entfernt wurden. Grundlegendes Problem ist, dass GetPreviousVersion()dies nicht funktioniert, wenn Sie die Einstellung in der neuen Version Ihrer Anwendung umbenannt oder entfernt haben. Sie müssen also die Einstellung in Ihrer SettingsKlasse beibehalten , aber einige Attribute / Artefakte hinzufügen, damit Sie sie nicht versehentlich im Code an anderer Stelle verwenden und sie veralten lassen. Eine veraltete Beispieleinstellung würde in VB.NET folgendermaßen aussehen (kann leicht in C # übersetzt werden):

<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

Stellen Sie sicher, dass Sie diese Eigenschaft demselben Namespace / derselben Klasse hinzufügen, in dem sich Ihre Anwendungseinstellungen befinden. In VB.NET wird diese Klasse benannt MySettingsund ist im MyNamespace verfügbar . Sie können Teilklassenfunktionen verwenden, um zu verhindern, dass Ihre veralteten Einstellungen mit Ihren aktuellen Einstellungen verwechselt werden.

Wir danken jsharrison für die Veröffentlichung eines hervorragenden Artikels zu diesem Thema. Weitere Details dazu finden Sie dort.


1

Hier ist eine Variation der hier vorgestellten Lösungen, die die Upgrade-Logik in eine abstrakte Klasse kapselt, von der Einstellungsklassen abgeleitet werden können.

Einige vorgeschlagene Lösungen verwenden ein DefaultSettingsValue-Attribut, um einen Wert anzugeben, der angibt, wann vorherige Einstellungen nicht geladen wurden. Ich bevorzuge es, einfach einen Typ zu verwenden, dessen Standardwert dies anzeigt. Als Bonus eine DateTime? ist hilfreich beim Debuggen von Informationen.

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

Ableiten von UserSettingsBase:

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

    public MySettings() : base() { }
}

Und benutze es:

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

0

Wenn Ihre Änderungen an user.settings programmgesteuert vorgenommen werden, können Sie eine Kopie (nur) der Änderungen an user.settings in einer separaten Datei, z. B. user.customized.settings, verwalten.

Sie möchten die geänderten Einstellungen wahrscheinlich auch weiterhin in user.settings beibehalten und laden. Auf diese Weise können Sie den Benutzer bei der Installation einer neueren Version Ihrer Anwendung mit der neueren Version von user.settings fragen, ob er seine geänderten Einstellungen weiterhin verwenden möchte, indem er sie wieder in die neuen user.settings kopiert. Sie können sie im Großhandel importieren oder schicker werden und den Benutzer bitten, zu bestätigen, welche Einstellungen er weiterhin verwenden möchte.

BEARBEITEN: Ich habe den "genaueren" Teil über Baugruppenversionen zu schnell gelesen, wodurch eine neue user.settings in einem neuen versionierungsspezifischen Verzeichnis installiert wurde. Daher hilft Ihnen die obige Idee wahrscheinlich nicht weiter, kann aber einige Denkanstöße geben.


0

So habe ich damit umgegangen:

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;

}}

und in der Einstellungsklasse habe ich die IsDefault-Eigenschaft definiert:

// 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; }
}

In den SaveSettings habe ich IsDefault auf false gesetzt:

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();
}
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.