Settings.Default. sempre retorna valor padrão em vez do valor no armazenamento persistente (arquivo XML)

StackOverflow https://stackoverflow.com/questions/192641

Pergunta

Eu escrevi recentemente uma DLL em C # (.Net 2.0), que contém uma classe que requer um endereço IP. Um colega de trabalho de meus alterou a classe para recuperar o IP de um arquivo ".dll.config" (XML) - Isto aparentemente é gerado automaticamente pelo arquivo 'Configurações do aplicativo' ele criou (Settings1.settings). O benefício desta era permitir que o usuário final para alterar o endereço IP no arquivo XML / config na vontade.

Infelizmente, quando eu verificar o seu código fora da árvore e tentar compilar (ou utilização), este novo código, qualquer aplicativo chamar essa DLL só recebe o valor padrão, em vez do valor do arquivo.

O construtor que chama a aparência arquivo de configuração como esta:

    public class form : System.Windows.Forms.Form
    {
        public form()
        {
            // This call is required by the Windows Form Designer.
            InitializeComponent();
            IP = IPAddress.Parse(Settings1.Default.IPAddress);
        }
    }

um referência a este problema nos fóruns do MSDN onde um usuário disse:

os valores 'antigos' (aqueles que você definir em tempo de desenvolvimento) são codificado. Se o franework não é capaz de acessar ou abrir o arquivo de configuração que irá usar os padrões em seu lugar. Isso sempre vai acontecer se você usar as configurações em uma dll.

  1. Isso significa que eu não pode armazenar um valor externo para uma DLL em um arquivo de configuração? (Meu colega de trabalho, de alguma forma fez este trabalho ...)

  2. Uma vez que o meu quadro parece ser incapaz de acesso ou abrir o arquivo de configuração, como faço para descobrir por que ele está falhando? Ou mesmo detectar quando isso acontece?

Decker : Isso ajuda um pouco. Infelizmente, eu estou escrevendo este DLL com uma especificação, então eu realmente não têm acesso ao arquivo de configuração do aplicativo. Como você vai notar acima, a minha colega de trabalho criou uma "Configurações 1 .settings" arquivo. Eu não entendia isso na época, mas parece agora que adicionando o "1" mantém fora do espaço de configurações de qualquer aplicativo que chama-lo.

Eu acho que o que estou tentando descobrir é por isso que a DLL não parecem encontrar o arquivo de configuração sentado próximo a ele no mesmo diretório. Rastreamento através do código passo-a-passo não revela nada.

Como um aparte, eu posso mudar o "Tipo de saída" da minha montagem de "biblioteca de classes" para "Windows Application" e adicione as seguintes linhas no início do meu código DLL:

    [STAThread]
    public static void Main(string[] args)
    {
        System.Windows.Forms.Application.Run(new form());
    }

Quando eu executo isso, ele gera um arquivo de configuração diferente (um "exe.config") e que um que eu posso alterar e tê-lo puxar os novos dados do arquivo. Então, eu estou um pouco confuso. Alguma idéia?

Foi útil?

Solução

Estou abordando este problema exato em um aplicativo que eu estou no meio de prototipagem. Embora a sugestão de cortar os arquivos de configuração conjunto de Decker deve funcionar Acho que este é um hack Manual bastante inconveniente para executar como parte de um ciclo de construção. Em vez de que eu decidi que a solução mais limpa é apenas ter cada biblioteca parse seu próprio arquivo library.dll.config. Sua ainda não é perfeito e que exige algum código caldeira de placa extra, mas parece ser a única maneira de obter em torno da maneira bizantino que .Net lida com esses arquivos app.

Outras dicas

Eu uso essa técnica todos os tempos tempo. Muitas vezes eu tenho um assembly de biblioteca que requer determinadas configurações, e eu preciso deles definir tanto testando projetos, bem como as assembleias primárias "executáveis" - sejam eles projetos web ou projetos de serviços do Windows

.

Você está correto em que quando você cria um arquivo de configurações para qualquer projeto, ele adiciona um arquivo de configuração do aplicativo. O valor inserido para qualquer configuração é armazenada em dois lugares - o arquivo de configuração e nos atributos nas classes criadas pela infra-estrutura configurações. Quando um arquivo de configuração não for encontrado, são utilizados os valores embutidos nos atributos.

Aqui está um trecho que mostra tal atributo:

Aqui está um trecho que mostra o valor padrão do ConcordanceServicesEndpointName na classe gerada:

    [global::System.Configuration.ApplicationScopedSettingAttribute()]
    [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
    [global::System.Configuration.DefaultSettingValueAttribute("InternalTCP")]

    public string ConcordanceServicesEndpointName {
        get {
            return ((string)(this["ConcordanceServicesEndpointName"]));
        }
    }

O que você quer fazer é copiar a seção de configuração fora do arquivo app.config do projeto de montagem de biblioteca e mesclá-lo (com cuidado) no web.config aplicável ou app.config para o conjunto principal. Em tempo de execução, que é o arquivo somente de configuração que é usado.

Aqui está um exemplo:

<configSections>
    <sectionGroup name="applicationSettings" type="System.Configuration.ApplicationSettingsGroup, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" >
      <section name="LitigationPortal.Documents.BLL.DocumentsBLLSettings" type="System.Configuration.ClientSettingsSection, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />
    </sectionGroup>
  </configSections>
  <applicationSettings>
    <LitigationPortal.Documents.BLL.DocumentsBLLSettings>
      <setting name="ConcordanceServicesEndpointName" serializeAs="String">
        <value>InternalTCP</value>
      </setting>
    </KayeScholer.LitigationPortal.Documents.BLL.DocumentsBLLSettings>
  </applicationSettings>

Você deve copiar essas seções para o "verdadeiro" arquivo de configuração.

Eu tive esse mesmo problema por um longo tempo - é chato

.

Eu gosto da idéia de fazer o seu próprio arquivo de configuração e ter cada DLL analisá-lo, embora ele ainda pode ser fácil de perder ter de alterar a configuração.

Uma coisa que eu fiz no passado para, pelo menos, tornar este um pouco mais fácil é para se certificar de que todos os valores de configuração que os Setting1.Settings de arquivo são inválidos.

Por exemplo, eu tenho uma classe que usa LINQ to SQL para falar com o DB. Por isso, tem um arquivo Setting1.settings que ele armazena a seqüência de conexão ao banco de dados. O valor padrão que é inserido (mediante arrastar e soltar as tabelas de banco de dados para o designer) é a seqüência de conexão do banco de dados dev.

Assim que eu tiver o arquivo DBML criado com base fora do banco de dados de teste, eu posso entrar e editar o arquivo de configurações e digite um nome de banco de dados como "FAKE_DATABASE".

Dessa forma, se você usar o DLL em outro projeto, e depois se esqueça de mesclar os arquivos de configuração para adicionar no valor de configuração adequada para a DLL, pelo menos você obterá um erro dizendo algo como "Não é possível conectar-se FAKE_DATABASE ".

Claro que, se você tem que trabalhar com o designer novamente, você terá que alterar o valor de volta para o valor do seu banco de dados dev.

dor enorme. Eles tenho que mudar isso de alguma forma.

Aparentemente, a sua aplicação está tentando ler a partir do arquivo de configuração padrão (que é provavelmente o arquivo de configuração do aplicativo). Para certificar-se, adicionar o par de valores-chave no arquivo de configuração do dll no arquivo de configuração do aplicativo, execute o aplicativo e ver se ele é lido neste momento.

Eu acho que eu só encontrei uma explicação de por que isso não está funcionando para minha DLL e meu aplicativo de teste. Aqui é a exceção de conclusão de de um cara blogue :

A correcção para este, quer seja para se certificar de sua aplicação e os conjuntos de apoio têm o mesmo namespace ou para certificar-se de que você mesclar o conteúdo de AppName.exe.config e DllName.dll.config (sim quando você compilar um arquivo .dll agora ele gera esse arquivo, no entanto, é ignorado se você copiá-lo para o diretório do aplicativo e não é mesclada automaticamente)

Então, ou eu tenho que manter a DLL e Aplicação no mesmo namespace -ou- eu tenho que mesclar o conteúdo do arquivo de configuração DLL com arquivo de configuração do aplicativo.

(não se este tipo de derrota o propósito da DLL? Eu pensei que uma DLL era para ser uma biblioteca independente.)

Talvez seja por isso que ele funciona para o meu colega de trabalho. O aplicativo de produção compartilha o mesmo espaço de nomes como o DLL. (Meu aplicativo de teste claramente não faz ...)

UPDATE: Eu apenas sentei com meu colega de trabalho recentemente e falou sobre este problema novamente e parece que ele nunca estava trabalhando para ele também, mas ele não tinha percebido isso porque ele tinha definir o valor inicial a ser o mesmo que o dispositivo estávamos tentando usar. Então é claro que apareceu para o trabalho no início, mas assim que implantado em outro lugar com configurações ligeiramente diferentes foi quebrado novamente.

Eu vi um problema semelhante ao usar app. Tente executar o aplicativo a partir do .exe em vez da partir do Visual Studio & ver se, em seguida, se comporta como esperado.

É possível que na sua DLL você tem o modificador de acesso (para os Settings1.Settings) definido para Internal (Friend for VB). Tente alterar o modificador de acesso ao público e ver se isso permite que o seu aplicativo de leitura / gravação valores de configuração de dll.

A resposta de Howard abrange a teoria.

Uma maneira rápida e suja de resolver isso é para analisar o arquivo XML de configuração manualmente.

    string configFile = Assembly.GetExecutingAssembly().Location + ".config";
    XDocument.Load(configFile).Root.Element("appSettings")....

O erro que eu acho que todos fazem é que você parece fazer referece às Configurações DLL via Settings1.Default.IPAddress enquanto você está simplesmente suppossed fazer isso Settings1.IPAddress.

A diferença é que quando você usa Settings1.Default.IPAddress os valores são obtidos a partir dos valores codificados encravada no arquivo de montagem (.dll ou .exe) como atributo [global :: System.Configuration.DefaultSettingValueAttribute (...)].

Enquanto Settings1.IPAddress é o valor que é editável no .dll.config arquivo (arquivo XML) **. por isso todas as alterações feitas para o arquivo XML, não é refletido no valor padrão codificado no conjunto.

Não esta:

IP = IPAddress.Parse(Settings1.Default.IPAddress);

Mas tente o seguinte:

*IP = IPAddress.Parse(Settings1.IPAddress);
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top