Comment conserver les paramètres user.config dans différentes versions d'assembly dans .net?

146

Fondamentalement, le problème est que chaque fois que la version de l'assembly change (c'est-à-dire que l'utilisateur installe une nouvelle version de l'application), tous ses paramètres sont réinitialisés les valeurs par défaut (ou plus précisément un nouveau fichier user.config est créé dans un dossier avec une version différente numéro comme nom)

Comment puis-je conserver les mêmes paramètres lors de la mise à niveau des versions, car l'utilisation de fichiers ini ou du registre semble déconseillée?

Lorsque nous avons utilisé Clickonce, il semblait être en mesure de gérer cela, il semble donc que cela devrait pouvoir être fait, mais je ne sais pas comment.

Davy8
la source
Question similaire ?
Allen Rice
Non, cela fait référence à la valeur par défaut de ne pas archiver un fichier dans le contrôle de version (ou c'est ce que j'ai rassemblé) Cela concerne les paramètres spécifiques à l'utilisateur (Windows) pour un utilisateur final
Davy8
Juste la question dont j'avais besoin, merci :)
Binary Worrier
J'ai publié une solution possible dans le fil de discussion suivant: stackoverflow.com/a/47921377/3223783 J'espère que cela aide!
dontbyteme
J'ai publié une solution possible dans ce fil . J'espère que cela pourra aider!
dontbyteme

Réponses:

236

ApplicationSettingsBase a une méthode appelée Upgrade qui migre tous les paramètres de la version précédente.

Afin d'exécuter la fusion chaque fois que vous publiez une nouvelle version de votre application, vous pouvez définir un indicateur booléen dans votre fichier de paramètres qui par défaut est true. Nommez-le UpgradeRequired ou quelque chose de similaire.

Ensuite, au démarrage de l'application, vous vérifiez si l'indicateur est défini et si c'est le cas, appelez la méthode Upgrade , définissez l'indicateur sur false et enregistrez votre configuration.

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

En savoir plus sur la méthode de mise à niveau sur MSDN . La GetPreviousVersion peut également valoir la peine d'être examinée si vous devez effectuer une fusion personnalisée.

Markus Olsson
la source
2
Une petite question, qu'est-ce qu'une nouvelle version? Une partie du numéro de pièce 4? J'utilise ClickOnce, est-ce donc un animal différent?
Paladin réfracté le
4
Quel type de paramètre doit être UpgradeRequired ? appSettings, userSettingsou applicationSettings? En tant que paramètre utilisateur sur Settings.Settings, une fois qu'il est changé pour la première fois en faux, il ne sera plus jamais vrai. Une nouvelle version ne réinitialisera pas cette UpgradeRequired à True.
dialex
4
@dialex Il doit s'agir d'un paramètre utilisateur. Les paramètres de type Application sont en lecture seule. Les nouveaux numéros de version entraînent la réinitialisation des paramètres, car les paramètres sont stockés dans un chemin spécifique à la version.
Leonard Thieu
4
Je pense avoir répondu à ma propre question. Si une version précédente du fichier de paramètres existe, elle copiera ses valeurs dans la version la plus récente à chaque démarrage de l'application, probablement pas ce que vous voulez!
Hugh Jeffner
1
Je suis un peu surpris que ce ne soit pas seulement un comportement par défaut; si les paramètres de l'application sont nuls au démarrage et qu'elle trouve un groupe de paramètres précédent, elle les charge.
SteveCinq
3

Je sais que ça fait un moment ... Dans une application winforms, il suffit d'appeler My.Settings.Upgrade()avant de les charger. Cela obtiendra les derniers paramètres, que ce soit la version actuelle ou une version précédente.

Tinlyx
la source
2

Voici mes recherches au cas où quelqu'un d'autre aurait du mal avec les paramètres de migration qui ont été modifiés / supprimés. Le problème de base est que GetPreviousVersion()cela ne fonctionne pas si vous avez renommé ou supprimé le paramètre dans la nouvelle version de votre application. Vous devez donc conserver le paramètre dans votre Settingsclasse, mais y ajouter quelques attributs / artefacts afin de ne pas l'utiliser par inadvertance dans le code ailleurs, ce qui le rend obsolète. Un exemple de paramètre obsolète ressemblerait à ceci dans VB.NET (peut facilement être traduit en 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

Assurez-vous d'ajouter cette propriété au même espace de noms / classe que les paramètres de votre application. Dans VB.NET, cette classe est nomméeMySettings et est disponible dans l' Myespace de noms. Vous pouvez utiliser la fonctionnalité de classe partielle pour éviter que vos paramètres obsolètes ne se mélangent avec vos paramètres actuels.

Merci à jsharrison pour avoir publié un excellent article sur ce problème. Vous pouvez lire plus de détails à ce sujet ici.

point net
la source
1

Voici une variante des solutions présentées ici qui encapsule la logique de mise à niveau dans une classe abstraite dont les classes de paramètres peuvent dériver.

Certaines solutions proposées utilisent un attribut DefaultSettingsValue pour spécifier une valeur qui indique quand les paramètres précédents n'ont pas été chargés. Ma préférence est d'utiliser simplement un type dont la valeur par défaut l'indique. En prime, un DateTime? est des informations de débogage utiles.

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

Dériver de UserSettingsBase:

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

    public MySettings() : base() { }
}

Et utilisez-le:

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

Si vos modifications de user.settings sont effectuées par programme, que diriez-vous de conserver une copie (uniquement) des modifications apportées à user.settings dans un fichier séparé, par exemple user.customized.settings?

Vous souhaitez probablement toujours conserver et charger les paramètres modifiés dans user.settings également. Mais de cette façon, lorsque vous installez une version plus récente de votre application avec sa nouvelle version de user.settings, vous pouvez demander à l'utilisateur s'il souhaite continuer à utiliser ses paramètres modifiés en les recopiant dans le nouvel utilisateur.settings. Vous pouvez les importer en gros ou devenir plus sophistiqués et demander à l'utilisateur de confirmer les paramètres qu'il souhaite continuer à utiliser.

EDIT: J'ai lu trop rapidement la partie "plus précise" sur les versions d'assemblage provoquant l'installation d'un nouveau user.settings dans un nouveau répertoire spécifique à la version. Ainsi, l'idée ci-dessus ne vous aide probablement pas, mais peut donner matière à réflexion.

JMD
la source
0

Voici comment je l'ai géré:

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;

}

et dans la classe settings, j'ai défini la propriété 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; }
}

Dans SaveSettings, j'ai défini IsDefault sur 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
la source