Equivalente a 'app.config' para uma biblioteca (DLL)

149

Existe um equivalente app.configpara bibliotecas (DLLs)? Caso contrário, qual é a maneira mais fácil de armazenar definições de configuração específicas de uma biblioteca? Por favor, considere que a biblioteca pode ser usada em diferentes aplicativos.

Louis Rhys
fonte

Respostas:

161

Você pode ter um arquivo de configuração separado, mas precisará lê-lo "manualmente", oConfigurationManager.AppSettings["key"] ele lerá apenas a configuração do assembly em execução.

Supondo que você esteja usando o Visual Studio como seu IDE, clique com o botão direito do mouse no projeto desejado → Adicionar → Novo item → Arquivo de configuração do aplicativo

Isso adicionará App.configà pasta do projeto, coloque suas configurações na <appSettings>seção. Caso você não esteja usando o Visual Studio e adicione o arquivo manualmente, forneça o nome: DllName.dll.config , caso contrário, o código abaixo não funcionará corretamente.

Agora, para ler este arquivo, temos essa função:

string GetAppSetting(Configuration config, string key)
{
    KeyValueConfigurationElement element = config.AppSettings.Settings[key];
    if (element != null)
    {
        string value = element.Value;
        if (!string.IsNullOrEmpty(value))
            return value;
    }
    return string.Empty;
}

E para usá-lo:

Configuration config = null;
string exeConfigPath = this.GetType().Assembly.Location;
try
{
    config = ConfigurationManager.OpenExeConfiguration(exeConfigPath);
}
catch (Exception ex)
{
    //handle errror here.. means DLL has no sattelite configuration file.
}

if (config != null)
{
    string myValue = GetAppSetting(config, "myKey");
    ...
}

Você também precisará adicionar referência ao namespace System.Configuration para ter a classe ConfigurationManager disponível.

Ao criar o projeto, além da DLL, você terá DllName.dll.config arquivo, que é o arquivo que você deve publicar com a própria DLL.

O código acima é de exemplo básico. Para os interessados ​​em um exemplo em grande escala, consulte esta outra resposta .

Shadow Wizard é Ear For You
fonte
1
@Rodney tente mudar string exeConfigPath = this.GetType().Assembly.Location;para algo como:string exeConfigPath = @"C:\MyFolder\DllFolder\ExeName.exe";
Assistente de Sombra é ouvido para Você
1
Alguma idéia de como fazer isso se a dll estiver sendo copiada para alguma pasta desconhecida pela ferramenta de teste de unidade de recarregador?
Autodidata 01/10
11
Uma dica para qualquer pessoa que implemente isso: para automatizar a geração do DllName.dll.config referenciando aplicativos, simplesmente renomeei app.config para DllName.dll.config e alterei a propriedade "Copiar para diretório de saída" para "Copiar sempre" . Além disso, minha necessidade era de cadeias de conexão, que podem ser recuperadas usando config.ConnectionStrings.ConnectionStrings [connStringName] .ConnectionString.
Jeff G.
2
o nome do arquivo app.cfg é muito importante para ler os valores appcfg, o nome do arquivo deve ser "DLL_NAME.DLL.CONFIG"
SaddamBinSyed 10/17/17
2
Correção no meu último comentário. Na minha solução VS2017, removendo meus novos arquivos App.config que não funcionavam dos meus projetos de teste e DLL e apenas o adicionando novamente ao meu projeto de teste, ele de repente começou a funcionar! Minha configuração App.config agora é automaticamente incluída nos DLL.configs. Que alivio!
Zeek2
30

Infelizmente, você só pode ter um arquivo app.config por executável; portanto, se você tiver DLLs vinculados ao seu aplicativo, eles não poderão ter seus próprios arquivos app.config.

A solução é: você não precisa colocar o arquivo App.config no projeto da biblioteca de classes.
Você coloca o arquivo App.config no aplicativo que está referenciando a DLL da sua biblioteca de classes.

Por exemplo, digamos que temos uma biblioteca de classes chamada MyClasses.dll que usa o arquivo app.config da seguinte maneira:

string connect = 
ConfigurationSettings.AppSettings["MyClasses.ConnectionString"];

Agora, digamos que tenhamos um aplicativo do Windows chamado MyApp.exe que faça referência ao MyClasses.dll. Ele conteria um App.config com uma entrada como:

<appSettings>
    <add key="MyClasses.ConnectionString"
         value="Connection string body goes here" />
</appSettings>

OU

Um arquivo xml é o melhor equivalente para app.config. Use xml serialize / desserialize conforme necessário. Você pode chamá-lo como quiser. Se sua configuração é "estática" e não precisa ser alterada, você também pode adicioná-la ao projeto como um recurso incorporado.

Espero que dê alguma idéia

PawanS
fonte
6
ConfigurationSettingsé agora obsoleto e substituído por ConfigurationManager, por isso, o equivalente seria agoraConfigurationManager.AppSettings
Ido Codificação
2
voto negativo. a pergunta é por dll e não por aplicativo. melhor solução: stackoverflow.com/a/5191101/2935383
raiserle 17/10
3
Suspeito que essa sugestão não funcione no caso de DLLs com ligação tardia, que não teriam conhecimento do executável que as chamava.
beanmf
9

Os arquivos de configuração têm escopo no aplicativo e não no conjunto. Portanto, você precisará colocar as seções de configuração da sua biblioteca no arquivo de configuração de cada aplicativo que está usando sua biblioteca.

Dito isso, não é uma boa prática obter configuração do arquivo de configuração do aplicativo, especialmente da appSettingsseção, em uma biblioteca de classes. Se sua biblioteca precisar de parâmetros, eles provavelmente deverão ser passados ​​como argumentos de método em construtores, métodos de fábrica etc. por quem estiver chamando sua biblioteca. Isso impede que os aplicativos de chamada reutilizem acidentalmente as entradas de configuração esperadas pela biblioteca de classes.

Dito isto, os arquivos de configuração XML são extremamente úteis, portanto, o melhor compromisso que encontrei é usar seções de configuração personalizadas. Você pode colocar a configuração da sua biblioteca em um arquivo XML que é automaticamente lido e analisado pela estrutura e evita possíveis acidentes.

Você pode aprender mais sobre as seções de configuração personalizada no MSDN e também Phil Haack tem um bom artigo sobre elas.

madd0
fonte
7
"não é uma boa prática obter configuração de um arquivo de configuração em uma biblioteca de classes" - discordo totalmente disso. Por exemplo, uma biblioteca de classes DAL normalmente deve obter dados de configuração, como cadeias de conexão do arquivo de configuração do aplicativo, em vez de passar essas informações da camada BLL. Quaisquer classes do Framework que usam a configuração (por exemplo, Associação ao ASP.NET) funcionam dessa maneira.
Joe
Eu modifiquei minha resposta um pouco. Ainda mantenho o que disse, mas você está certo, nunca pretendi sugerir que os arquivos de configuração não devam ser usados. O que eu quis dizer foi que, em vez de appSettingsseções personalizadas baseadas em convenções , oferecem uma ótima alternativa; é basicamente o que a Associação do ASP.NET usa, afinal.
precisa saber é
5
public class ConfigMan
{
    #region Members

    string _assemblyLocation;
    Configuration _configuration;

    #endregion Members

    #region Constructors

    /// <summary>
    /// Loads config file settings for libraries that use assembly.dll.config files
    /// </summary>
    /// <param name="assemblyLocation">The full path or UNC location of the loaded file that contains the manifest.</param>
    public ConfigMan(string assemblyLocation)
    {
        _assemblyLocation = assemblyLocation;
    }

    #endregion Constructors

    #region Properties

    Configuration Configuration
    {
        get
        {
            if (_configuration == null)
            {
                try
                {
                    _configuration = ConfigurationManager.OpenExeConfiguration(_assemblyLocation);
                }
                catch (Exception exception)
                {
                }
            }
            return _configuration;
        }
    }

    #endregion Properties

    #region Methods

    public string GetAppSetting(string key)
    {
        string result = string.Empty;
        if (Configuration != null)
        {
            KeyValueConfigurationElement keyValueConfigurationElement = Configuration.AppSettings.Settings[key];
            if (keyValueConfigurationElement != null)
            {
                string value = keyValueConfigurationElement.Value;
                if (!string.IsNullOrEmpty(value)) result = value;
            }
        }
        return result;
    }

    #endregion Methods
}

Apenas para alguma coisa, refatorei a resposta principal em uma classe. O uso é algo como:

ConfigMan configMan = new ConfigMan(this.GetType().Assembly.Location);
var setting = configMan.GetAppSetting("AppSettingsKey");
Firegarden
fonte
4

Se você adicionar Configurações a um projeto da Biblioteca de Classes no Visual Studio (Propriedades do Projeto, Configurações), ele adicionará um arquivo app.config ao seu projeto com as seções userSettings / applicatioNSettings relevantes e os valores padrão para essas configurações em Settings.settings Arquivo.

No entanto, esse arquivo de configuração não será usado no tempo de execução - em vez disso, a biblioteca de classes usa o arquivo de configuração do aplicativo de hospedagem.

Acredito que o principal motivo para gerar esse arquivo é para que você possa copiar / colar as configurações no arquivo de configuração do aplicativo host.

Joe
fonte
4

Atualmente, estou criando plugins para uma marca de software de varejo, que na verdade são bibliotecas de classe .net. Como requisito, cada plug-in precisa ser configurado usando um arquivo de configuração. Após algumas pesquisas e testes, compilei a seguinte classe. Ele faz o trabalho na perfeição. Observe que eu não implementei o tratamento de exceções locais no meu caso porque, eu pego exceções em um nível superior.

Talvez seja necessário fazer alguns ajustes para acertar o ponto decimal, no caso de decimais e duplos, mas funciona bem para o meu CultureInfo ...

static class Settings
{
    static UriBuilder uri = new UriBuilder(Assembly.GetExecutingAssembly().CodeBase);
    static Configuration myDllConfig = ConfigurationManager.OpenExeConfiguration(uri.Path);
    static AppSettingsSection AppSettings = (AppSettingsSection)myDllConfig.GetSection("appSettings");
    static NumberFormatInfo nfi = new NumberFormatInfo() 
    { 
        NumberGroupSeparator = "", 
        CurrencyDecimalSeparator = "." 
    };

    public static T Setting<T>(string name)
    {
        return (T)Convert.ChangeType(AppSettings.Settings[name].Value, typeof(T), nfi);
    }
}

Amostra de arquivo App.Config

<add key="Enabled" value="true" />
<add key="ExportPath" value="c:\" />
<add key="Seconds" value="25" />
<add key="Ratio" value="0.14" />

Uso:

  somebooleanvar = Settings.Setting<bool>("Enabled");
  somestringlvar = Settings.Setting<string>("ExportPath");
  someintvar =     Settings.Setting<int>("Seconds");
  somedoublevar =  Settings.Setting<double>("Ratio");

Créditos ao Shadow Wizard & MattC

Yiannis Leoussis
fonte
1
Essa deve ser a resposta aceita. Muito compacto e "funciona imediatamente". Coisas boas
nmarler 27/04/19
2

Em resposta à pergunta original, normalmente adiciono o arquivo de configuração no meu projeto de teste como um link; você pode usar o atributo DeploymentItem para adicionar à pasta Out da execução de teste.

[TestClass]
[DeploymentItem("MyProject.Cache.dll.config")]
public class CacheTest
{
    .
    .
    .
    .
}

Em resposta aos comentários de que as Assembléias não podem ser específicas do projeto, elas podem e isso fornece uma grande flexibilidade esp. ao trabalhar com estruturas do COI.

Allan Elder
fonte
2

Eu enfrentei o mesmo problema e resolvi-o criando uma classe estática Parametersdepois de adicionar um arquivo de configuração do aplicativo ao projeto:

public static class Parameters
{
    // For a Web Application
    public static string PathConfig { get; private set; } =
        Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "web.config");

    // For a Class Library
    public static string PathConfig { get; private set; } =
        Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "bin", "LibraryName.dll.config");

    public static string GetParameter(string paramName)
    {
        string paramValue = string.Empty;

        using (Stream stream = File.OpenRead(PathConfig))
        {
            XDocument xdoc = XDocument.Load(stream);

            XElement element = xdoc.Element("configuration").Element("appSettings").Elements().First(a => a.Attribute("key").Value == paramName);
            paramValue = element.Attribute("value").Value;
        }

        return paramValue;
    }
}

Em seguida, obtenha um parâmetro como este:

Parameters.GetParameter("keyName");
krlzlx
fonte
1
Brilhante! Isso me ajudou a executar meus testes automatizados do Windows Application Driver nas máquinas de destino. As DLLs no meu caso eram de um projeto de teste. A única coisa que gostaria de acrescentar é que, no Win App Driver (e possivelmente em outras formas de teste automatizado), o BaseDirectory é na verdade a pasta de saída que muda a cada vez. Eu tive que substring como este ... AppDomain.CurrentDomain.BaseDirectory.Substring (0, AppDomain.CurrentDomain.BaseDirectory.IndexOf ("TestResults")). Dessa forma, eu poderia cortar a pasta de saída indesejada, pois meu arquivo de configuração estava na mesma pasta que minhas DLLs de teste.
Ewan
1

assemblies não têm seu próprio arquivo app.config. Eles usam o arquivo app.config do aplicativo que os está usando. Portanto, se seu assembly está esperando algumas coisas no arquivo de configuração, verifique se o arquivo de configuração do seu aplicativo possui essas entradas.

Se o seu assembly estiver sendo usado por vários aplicativos, cada um desses aplicativos precisará ter essas entradas em seu arquivo app.config.

O que eu recomendaria que você faça é definir propriedades nas classes em sua montagem para esses valores, por exemplo

private string ExternalServicesUrl
{
  get
  {
    string externalServiceUrl = ConfigurationManager.AppSettings["ExternalServicesUrl"];
    if (String.IsNullOrEmpty(externalServiceUrl))
      throw new MissingConfigFileAppSettings("The Config file is missing the appSettings entry for: ExternalServicesUrl");
    return externalServiceUrl;
  }
}

Aqui, a propriedade ExternalServicesUrl obtém seu valor do arquivo de configuração do aplicativo. Se algum aplicativo usando esse assembly estiver com essa configuração ausente no arquivo de configuração, você receberá uma exceção ou ficará claro que algo está faltando.

MissingConfigFileAppSettings é uma exceção personalizada. Você pode querer lançar uma exceção diferente.

Obviamente, um design melhor seria que o método dessas classes fornecesse esses valores como parâmetros, em vez de depender da configuração do arquivo de configuração. Dessa forma, os aplicativos que usam essas classes podem decidir de onde e como fornecem esses valores.

Shiv Kumar
fonte
Advertência para o acima: ao executar testes xUnit em sua DLL de montagem .NET, o xUnit lerá o arquivo .config da biblioteca em tempo de execução. E ele ignorará qualquer App.config adicionado ao projeto de teste ou DLL.
Zeek2
1

Use adicionar item existente, selecione a configuração do aplicativo no projeto dll. Antes de clicar em adicionar, use a pequena seta para baixo no lado direito do botão Adicionar para "adicionar como link"

Eu faço isso o tempo todo no meu desenvolvedor.

ghostJago
fonte
1

Preâmbulo : Estou usando o NET 2.0;

A solução postada por Yiannis Leoussis é aceitável, mas eu tive algum problema com ela.

Primeiro, os static AppSettingsSection AppSettings = (AppSettingsSection)myDllConfig.GetSection("appSettings");retornos nulos. Eu tive que mudar parastatic AppSettingSection = myDllConfig.AppSettings;

Então o return (T)Convert.ChangeType(AppSettings.Settings[name].Value, typeof(T), nfi);não tem um problema para exceções. Então eu mudei

try
{
    return (T)Convert.ChangeType(AppSettings.Settings[name].Value, typeof(T), nfi);
}
catch (Exception ex)
{
    return default(T);
}

Isso funciona muito bem, mas se você tiver uma DLL diferente, precisará reescrever toda vez que o código para cada assembly. Portanto, esta é a minha versão para uma classe instanciar toda vez que você precisar.

public class Settings
{
    private AppSettingsSection _appSettings;
    private NumberFormatInfo _nfi;

    public Settings(Assembly currentAssembly)
    {
        UriBuilder uri = new UriBuilder(currentAssembly.CodeBase);
        string configPath = Uri.UnescapeDataString(uri.Path);
        Configuration myDllConfig = ConfigurationManager.OpenExeConfiguration(configPath);
        _appSettings = myDllConfig.AppSettings;
        _nfi = new NumberFormatInfo() 
        { 
            NumberGroupSeparator = "", 
            CurrencyDecimalSeparator = "." 
        };
    }


    public T Setting<T>(string name)
    {
        try
        {
            return (T)Convert.ChangeType(_appSettings.Settings[name].Value, typeof(T), _nfi);
        }
        catch (Exception ex)
        {
            return default(T);
        }
    }
}

Para uma configuração:

<add key="Enabled" value="true" />
<add key="ExportPath" value="c:\" />
<add key="Seconds" value="25" />
<add key="Ratio" value="0.14" />

Use-o como:

Settings _setting = new Settings(Assembly.GetExecutingAssembly());

somebooleanvar = _settings.Setting<bool>("Enabled");
somestringlvar = _settings.Setting<string>("ExportPath");
someintvar =     _settings.Setting<int>("Seconds");
somedoublevar =  _settings.Setting<double>("Ratio");
Matteo Gaggiano
fonte
Por favor, revise o voto para exclusão. Meu erro foi enviar a resposta enquanto escrevia.
Matteo Gaggiano
0

Tanto quanto sei, você deve copiar + colar as seções que deseja da biblioteca .config no arquivo .config dos aplicativos. Você obtém apenas 1 app.config por instância executável.

Mike
fonte
se você estiver usando seções de configuração personalizada, você pode usar configSource atributo: <MySection configSource = "mysection.config" /> e arquivo de configuração única cópia com dll
Jan Remunda
Eu adicionei novas perguntas conforme solicitado, por exemplo, sobre a função sempre retornando uma string vazia e configurações do servidor de email> stackoverflow.com/questions/25123544/… e> stackoverflow.com/questions/25138788/…, então espero que alguém responda a elas como eu Estou quase no limite de apenas codificar os valores na DLL!
precisa
0

Por que não usar:

  • [ProjectNamespace].Properties.Settings.Default.[KeyProperty] para c #
  • My.Settings.[KeyProperty] para VB.NET

Você só precisa atualizar visualmente essas propriedades no tempo de design através de:

[Solution Project]->Properties->Settings

Pedro Mora
fonte
Isso criará automaticamente um arquivo de configuração para a dll. Mas você não pode ler valores modificados no arquivo de configuração em tempo de execução. Por fim, ele mostrará os valores do seu aplicativo de chamada. Veja também @Joe answer
Code Pope
Não, se estiver configurado para a configuração do usuário. A idéia é editar o que o usuário precisa, configurá-lo em tempo de execução e salvá-lo. Então, quando o usuário trabalha com a biblioteca, ele carrega sua configuração, salva no respectivo caminho do usuário, mas funciona apenas para ele.
Pedro Mora
0

O uso das configurações deve ser muito, muito fácil assim:

var config = new MiniConfig("setting.conf");

config.AddOrUpdate("port", "1580");

if (config.TryGet("port", out int port)) // if config exist
{
    Console.Write(port);
}

para mais detalhes, consulte MiniConfig

Rahmat Anjirabi
fonte