Come mantenere le impostazioni user.config tra diverse versioni di assembly in .net?


146

Fondamentalmente il problema è che ogni volta che cambia la versione dell'assembly (ovvero l'utente installa una nuova versione dell'applicazione) tutte le loro impostazioni vengono ripristinate ai valori predefiniti (o più precisamente viene creato un nuovo file user.config in una cartella con una versione diversa numero come nome)

Come posso mantenere le stesse impostazioni durante l'aggiornamento delle versioni, poiché l'utilizzo dei file ini o del registro sembra scoraggiato?

Quando abbiamo usato Clickonce sembrava essere in grado di gestirlo, quindi sembra che dovrebbe essere possibile farlo, ma non sono sicuro di come.



No, si riferisce al valore predefinito di non controllare un file nel controllo della versione (o così ho raccolto) Ciò riguarda le impostazioni specifiche dell'utente (Windows) per un utente finale
Davy8

Proprio la domanda di cui avevo bisogno, grazie :)
Binary Worrier,

Ho pubblicato una possibile soluzione nel seguente thread: stackoverflow.com/a/47921377/3223783 Spero che sia d'aiuto!
dontbyteme,

Ho pubblicato una possibile soluzione in questa discussione . Spero che aiuti!
dontbyteme,

Risposte:


236

ApplicationSettingsBase ha un metodo chiamato Upgrade che migra tutte le impostazioni dalla versione precedente.

Per eseguire l'unione ogni volta che pubblichi una nuova versione della tua applicazione, puoi definire un flag booleano nel tuo file di impostazioni che per impostazione predefinita è true. Denominalo UpgradeRequired o qualcosa di simile.

Quindi, all'avvio dell'applicazione, verificare se il flag è impostato e, in tal caso, chiamare il metodo di aggiornamento , impostare il flag su false e salvare la configurazione.

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

Ulteriori informazioni sul metodo di aggiornamento su MSDN . Il GetPreviousVersion potrebbe anche essere la pena dare un'occhiata se avete bisogno di fare un po 'fusione personalizzato.


2
Una piccola domanda, cosa costituisce una nuova versione? Qualsiasi parte del numero di 4 parti? Uso ClickOnce quindi è un animale diverso?
Rifadito Paladino il

4
Che tipo di impostazione dovrebbe essere UpgradeRequired ? appSettings, userSettingso applicationSettings? Come impostazione utente su Settings.Settings, una volta che la prima volta è cambiato in false non sarà più vero. Una nuova versione non reimposterà un UpgradeRequired su True.
dialex,

4
@dialex Deve essere un'impostazione utente. Le impostazioni di tipo Applicazione sono di sola lettura. I nuovi numeri di versione causano il ripristino delle impostazioni poiché le impostazioni sono memorizzate in un percorso specifico della versione.
Leonard Thieu,

4
Penso di aver risposto alla mia domanda. Se esiste una versione precedente del file delle impostazioni, i suoi valori verranno copiati nella versione più recente ogni volta che l'app viene avviata, probabilmente non quello che desideri!
Hugh Jeffner,

1
Sono un po 'sorpreso che questo non sia solo un comportamento predefinito; se le impostazioni dell'applicazione sono nulle all'avvio e trova un gruppo precedente di impostazioni, le carica.
SteveCinq,

3

So che è passato un po 'di tempo ... In un'app Winforms, basta chiamare My.Settings.Upgrade()prima di caricarli. Verranno visualizzate le impostazioni più recenti, sia la versione corrente sia una versione precedente.


2

Ecco la mia ricerca nel caso in cui qualcun altro abbia difficoltà a migrare le impostazioni che sono state modificate / rimosse. Il problema di base è che GetPreviousVersion()non funziona se la nuova versione dell'applicazione è stata rinominata o rimossa. Quindi devi mantenere l'impostazione nella tua Settingsclasse, ma aggiungi alcuni attributi / artefatti in modo da non utilizzarla inavvertitamente nel codice altrove, rendendola obsoleta. Un'impostazione obsoleta di esempio sarebbe simile a questa in VB.NET (può essere facilmente tradotta in 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

Assicurati di aggiungere questa proprietà allo stesso spazio dei nomi / classe con le impostazioni dell'applicazione. In VB.NET, questa classe è denominata MySettingsed è disponibile nello Myspazio dei nomi. È possibile utilizzare la funzionalità di classe parziale per impedire che le impostazioni obsolete si confondano con le impostazioni correnti.

Riconoscimento completo a jsharrison per la pubblicazione di un eccellente articolo su questo problema. Puoi leggere maggiori dettagli al riguardo lì.


1

Ecco una variazione delle soluzioni qui presentate che incapsula la logica di aggiornamento in una classe astratta da cui possono derivare le classi di impostazioni.

Alcune soluzioni proposte utilizzano un attributo DefaultSettingsValue per specificare un valore che indica quando non sono state caricate le impostazioni precedenti. La mia preferenza è semplicemente usare un tipo il cui valore predefinito indica questo. Come bonus, un DateTime? sono utili informazioni di debug.

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

Deriva da UserSettingsBase:

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

    public MySettings() : base() { }
}

E usalo:

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

0

Se le modifiche a user.settings vengono eseguite a livello di programmazione, che ne dite di conservare una copia di (solo) le modifiche a user.settings in un file separato, ad esempio user.customized.settings?

Probabilmente vorrai comunque mantenere e caricare le impostazioni modificate anche in user.settings. In questo modo, quando si installa una versione più recente dell'applicazione con la sua versione più recente di user.settings, è possibile chiedere all'utente se desidera continuare a utilizzare le impostazioni modificate copiandole nuovamente nella nuova user.settings. È possibile importarli all'ingrosso o diventare più elaborati e chiedere all'utente di confermare quali impostazioni desiderano continuare a utilizzare.

EDIT: ho letto troppo rapidamente la parte "più accurata" sulle versioni dell'assembly causando l'installazione di un nuovo user.settings in una nuova directory specifica della versione. Pertanto, l'idea sopra probabilmente non ti aiuta, ma può fornire qualche spunto di riflessione.


0

Ecco come l'ho gestito:

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;

}

e nella classe settings, ho definito la proprietà 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; }
}

In SaveSettings, ho impostato IsDefault su 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();
}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.