Como você mantém as configurações do user.config em diferentes versões de montagem no .net?

146

Basicamente, o problema é que sempre que a versão do assembly é alterada (ou seja, o usuário instala uma nova versão do aplicativo), todas as suas configurações são redefinidas para os padrões (ou mais precisamente, um novo arquivo user.config é criado em uma pasta com uma versão diferente número como o nome)

Como posso manter as mesmas configurações ao atualizar versões, pois o uso de arquivos ini ou o registro parece desencorajado?

Quando usamos o Clickonce, parecia ser capaz de lidar com isso, então parece que deveria ser possível, mas não sei como.

Davy8
fonte
Pergunta semelhante ?
Allen arroz
Não, isso está se referindo como padrão para não verificar um arquivo no controle de versão (ou assim eu reunidos) Esta é em relação às configurações do usuário específicas (Windows) para um usuário final
Davy8
Apenas a questão que eu precisava, obrigado :)
Binary Worrier
Publiquei uma possível solução no seguinte segmento: stackoverflow.com/a/47921377/3223783 Espero que ajude!
precisa saber é o seguinte
Publiquei uma possível solução neste tópico . Espero que ajude!
precisa saber é o seguinte

Respostas:

236

O ApplicationSettingsBase possui um método chamado Upgrade que migra todas as configurações da versão anterior.

Para executar a mesclagem sempre que você publicar uma nova versão do seu aplicativo, você pode definir um sinalizador booleano no arquivo de configurações que seja padronizado como true. Nomeie UpgradeRequired ou algo semelhante.

Em seguida, no início do aplicativo, verifique se o sinalizador está definido e, se estiver, chame o método Upgrade , defina o sinalizador como false e salve sua configuração.

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

Leia mais sobre o método de atualização no MSDN . O GetPreviousVersion também pode valer uma olhada, se você precisar fazer uma mesclagem personalizada.

Markus Olsson
fonte
2
Uma pequena pergunta, o que constitui uma nova versão? Alguma parte do número de 4 partes? Eu uso o ClickOnce, então esse animal é diferente?
Refracted Paladin
4
Que tipo de configuração deve ser UpgradeRequired ? appSettings, userSettingsou applicationSettings? Como uma configuração de usuário em Settings.Settings, uma vez que a primeira vez que for alterada para false, nunca mais será verdadeira. Uma nova versão não redefinirá um UpgradeRequired de volta para True.
Dialex 15/04
4
@dialex Deve ser uma configuração de usuário. As configurações do tipo Aplicativo são somente leitura. Os novos números de versão fazem com que as configurações sejam redefinidas porque as configurações são armazenadas em um caminho específico da versão.
precisa
4
Eu acho que respondi minha própria pergunta. Se existir uma versão anterior do arquivo de configurações, ele copiará seus valores para a versão mais recente sempre que o aplicativo for iniciado, provavelmente não o que você deseja!
precisa saber é o seguinte
1
Estou um pouco surpreso que isso não seja apenas um comportamento padrão; se as configurações do aplicativo forem nulas no início e encontrar um monte de configurações anteriores, ele será carregado.
SteveCinq
3

Eu sei que já faz um tempo ... Em um aplicativo winforms, basta ligar My.Settings.Upgrade()antes de carregá-los. Isso obterá as configurações mais recentes, seja a versão atual ou uma versão anterior.

tinlyx
fonte
2

Aqui está minha pesquisa, caso alguém esteja tendo dificuldades para migrar configurações que foram alteradas / removidas. O problema básico é que GetPreviousVersion()não funcionará se você renomeou ou removeu a configuração na nova versão do seu aplicativo. Portanto, você precisa manter a configuração em sua Settingsclasse, mas adicione alguns atributos / artefatos a ela para não usá-la inadvertidamente no código em outro lugar, tornando-a obsoleta. Um exemplo de configuração obsoleta ficaria assim no VB.NET (pode ser facilmente traduzido para 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

Certifique-se de adicionar essa propriedade ao mesmo namespace / classe que possui as configurações do aplicativo. No VB.NET, essa classe é nomeada MySettingse está disponível no Myespaço para nome. Você pode usar a funcionalidade de classe parcial para impedir que suas configurações obsoletas se misturem com as atuais.

Crédito total para jsharrison por postar um excelente artigo sobre esse problema. Você pode ler mais detalhes sobre isso lá.

ponto Net
fonte
1

Aqui está uma variação das soluções apresentadas aqui que encapsulam a lógica de atualização em uma classe abstrata da qual as classes de configurações podem derivar.

Algumas soluções propostas usam um atributo DefaultSettingsValue para especificar um valor que indica quando as configurações anteriores não foram carregadas. Minha preferência é simplesmente usar um tipo cujo valor padrão indica isso. Como um bônus, um DateTime? é uma informação útil para depuração.

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

Derivar de UserSettingsBase:

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

    public MySettings() : base() { }
}

E use-o:

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

Se suas alterações em user.settings são feitas de forma programática, que tal manter uma cópia (apenas) das modificações em user.settings em um arquivo separado, por exemplo, user.customized.settings?

Você provavelmente ainda deseja manter e carregar as configurações modificadas em user.settings também. Porém, desta maneira, quando você instala uma versão mais recente do seu aplicativo com a versão mais nova do user.settings, pode perguntar ao usuário se ele deseja continuar usando as configurações modificadas, copiando-as novamente para o novo user.settings. Você pode importá-los por atacado ou ficar mais chiques e pedir ao usuário para confirmar quais configurações ele deseja continuar usando.

Edição: li muito rapidamente sobre a parte "mais precisa" sobre as versões de montagem, fazendo com que um novo user.settings seja instalado em um novo diretório específico da versão. Portanto, a idéia acima provavelmente não ajuda, mas pode fornecer algum alimento para o pensamento.

JMD
fonte
0

É assim que eu lidei com isso:

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 na classe de configurações, eu defini a propriedade 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; }
}

No SaveSettings, defino IsDefault como 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
fonte