Posso controlar a localização das configurações do usuário .NET para evitar a perda de configurações na atualização do aplicativo?

104

Estou tentando personalizar a localização do user.configarquivo. Atualmente é armazenado com um hash e número de versão

%AppData%\[CompanyName]\[ExeName]_Url_[some_hash]\[Version]\

Eu quero ser agnóstico em relação à versão do aplicativo

%AppData%\[CompanyName]\[ProductName]\

Isso pode ser feito e como? Quais são as implicações? O usuário perderá as configurações da versão anterior após a atualização?

Muxa
fonte
Embora a resposta do uzbones seja informativa com relação à localização do arquivo, acredito que a de Ian seja mais correta com relação à atualização.
Anthony Mastrean
4
@AnthonyMastrean Pessoalmente, acho que nenhuma configuração importante deve depender da infraestrutura ApplicationSettings fornecida por meu Microsoft. Muxa deve apenas armazenar as configurações %AppData%\[CompanyName]/[ProductName]onde podemos confiar que ele permanecerá.
Ian Boyd
2
Sem dúvida, minha experiência contínua com o aplicativo integrado e as configurações do usuário tem sido terrível. Eu recomendo arquivos json em appdata ou programdata.
Anthony Mastrean
Você também pode armazenar suas configurações em um registro. Consulte stackoverflow.com/a/12127888/1273550 para implementação de classes de configurações alternativas.
Ravi Patel de

Respostas:

39

Para responder à primeira pergunta, você pode tecnicamente colocar o arquivo onde quiser, mas terá que codificá-lo você mesmo, pois o local padrão para onde o arquivo vai é o primeiro de seus dois exemplos. ( link para como fazer você mesmo )

Quanto à segunda pergunta, depende de como você implanta o aplicativo. Se você implantar por meio de um .msi, haverá dois hashes nas propriedades do projeto de instalação (a partir do qual o msi foi criado), o 'código de atualização' e o 'código do produto'. Isso determina como o msi pode ser instalado e se ele atualiza, sobrescreve ou instala ao lado de qualquer outra versão do mesmo aplicativo.

Por exemplo, se você tem duas versões do seu software e eles têm códigos de 'atualização' diferentes, para o Windows eles são partes de software completamente diferentes, independentemente do nome. No entanto, se o código de 'atualização' for o mesmo, mas o código do 'produto' for diferente de quando você tentar instalar o segundo msi, ele perguntará se você deseja atualizar, momento em que deve copiar os valores do configuração antiga para uma nova configuração. Se os dois valores forem iguais e o número da versão não mudar, a nova configuração estará no mesmo local da configuração antiga e não terá que fazer nada. Documentação MSDN

O ClickOnce é um pouco diferente, porque se baseia mais na versão # e no caminho do URL do ClickOnce. No entanto, descobri que, enquanto você continuar a 'Publicar' no mesmo local, a nova versão do aplicativo continuará a usar o configuração existente. ( link para como ClickOnce lida com atualizações )

Também sei que existe uma maneira de mesclar manualmente as configurações durante a instalação do msi usando scripts de instalação personalizados, mas não me lembro das etapas exatas para fazer isso ... (veja este link para saber como fazer isso com uma web. config)

uzbones
fonte
O código de atualização não é aquele que deve permanecer constante e o código do produto aquele que deve ser alterado entre os lançamentos? blogs.msdn.com/b/pusu/archive/2009/06/10/understanding-msi.aspx
estanford
Doh! você está correto, não acredito que entendi aquele ao contrário (e demorou 2 anos para pegá-lo). Foi como uma assinatura de
robô
Isso significa que apenas o usuário que está instalando terá suas configurações atualizadas?
Micha Wiedenmann
79

Eu queria adicionar este texto citado como uma referência para quando eu tiver esse problema no futuro. Supostamente, você pode instruir a infraestrutura ApplicationSettings a copiar as configurações de uma versão anterior chamando Upgrade :

Properties.Settings.Value.Upgrade();

Da postagem do blog de Perguntas frequentes sobre as configurações do cliente : ( arquivo )

P: Por que há um número de versão no caminho user.config? Se eu implantar uma nova versão do meu aplicativo, o usuário não perderá todas as configurações salvas pela versão anterior?

R: Existem alguns motivos pelos quais o caminho user.config é sensível à versão.

(1) Para dar suporte à implantação lado a lado de diferentes versões de um aplicativo (você pode fazer isso com Clickonce, por exemplo). É possível que versões diferentes do aplicativo tenham configurações diferentes salvas.

(2) Quando você atualiza um aplicativo, a classe de configurações pode ter sido alterada e pode não ser compatível com o que foi salvo, o que pode causar problemas.

No entanto, facilitamos a atualização das configurações de uma versão anterior do aplicativo para a mais recente. Basta chamar ApplicationSettingsBase.Upgrade () e ele recuperará as configurações da versão anterior que correspondem à versão atual da classe e as armazenará no arquivo user.config da versão atual. Você também tem a opção de substituir esse comportamento na classe de configurações ou na implementação do provedor.

P: Ok, mas como sei quando devo ligar para o Upgrade?

R: Boa pergunta. No Clickonce, quando você instala uma nova versão do seu aplicativo, ApplicationSettingsBase irá detectá-la e atualizar automaticamente as configurações para você assim que as configurações forem carregadas. Em casos diferentes do Clickonce, não há atualização automática - você mesmo deve ligar para a atualização. Aqui está uma ideia para determinar quando chamar o Upgrade:

Tenha uma configuração booleana chamada CallUpgrade e atribua a ela um valor padrão true. Quando seu aplicativo é inicializado, você pode fazer algo como:

if (Properties.Settings.Value.CallUpgrade)
{
   Properties.Settings.Value.Upgrade();
   Properties.Settings.Value.CallUpgrade = false;    
}

Isso garantirá que Upgrade () seja chamado apenas na primeira vez que o aplicativo for executado após a implantação de uma nova versão.

não acredito por um segundo que isso realmente funcione - não há nenhuma maneira da Microsoft fornecer essa capacidade, mas o método está lá do mesmo jeito.

Ian Boyd
fonte
3
ISSO FUNCIONA TOTALMENTE! Usei apenas uma if(CallUpgrade) { Upgrade(); }declaração simples .
Anthony Mastrean
@ Ian Boyd: Gosto desta ideia e estou totalmente entusiasmado por ter uma solução potencial, mas estou confuso sobre uma coisa. Eu não tenho um Properties.Settings.Value Eu tenho a Properties.Settingsparte, mas estou faltando alguma coisa ou isso é específico para você?
Paladino refratado
8
Isso funciona bem, mas lembro aos leitores que o caminho da configuração até, mas excluindo o número da versão, deve ser o mesmo. ou seja, veja a resposta de @Amr. por exemplo, se uma nova versão do aplicativo for iniciada a partir de um caminho de arquivo diferente do da versão anterior, Upgradeisso não funciona.
Stephen Swensen,
1
@RefractedPaladin éProperties.Settings.Default.Upgrade()
Stephen Swensen
5
Não se esqueça de adicionar Properties.Settings.Default.Save();depois de alterá-lo para falso :-)
Jeff
32

O arquivo user.config é armazenado em

c:\Documents and Settings>\<username>\[Local Settings\]Application Data\<companyname>\<appdomainname>_<eid>_<hash>\<verison>

<c:\Documents and Settings>é o diretório de dados do usuário, seja sem roaming (Configurações locais acima) ou em roaming.
<username>é o nome do usuário.
<companyname>é o valor CompanyNameAttribute, se disponível. Caso contrário, ignore este elemento.
<appdomainname>é o AppDomain.CurrentDomain.FriendlyName. Geralmente, o padrão é o nome .exe.
<eid>é a URL, StrongName ou Path, com base na evidência disponível para hash.
<hash>é um hash SHA1 de evidências coletadas do CurrentDomain, na seguinte ordem de preferência:
1. StrongName
2. URL:
Se nenhum deles estiver disponível, use o caminho .exe.
<version>é a configuração AssemblyVersionAttribute do AssemblyInfo.

A descrição completa está aqui http://msdn.microsoft.com/en-us/library/ms379611.aspx

Amr
fonte
4

(Eu adicionaria isso como um comentário à resposta de @Amr, mas ainda não tenho representantes suficientes para fazer isso.)

o informações no artigo do MSDN são muito claras e parecem ainda se aplicar. No entanto, não menciona que o hash SHA1 é gravado codificado na base 32, em vez da base 16 mais típica.

Acredito que o algoritmo que está sendo usado está implementado no ToBase32StringSuitableForDirName, que pode ser encontrado aqui na fonte de referência da Microsoft .

JulianRendell
fonte