Usando o ConfigurationManager para carregar a configuração de um local arbitrário

124

Estou desenvolvendo um componente de acesso a dados que será usado em um site que contém uma mistura de páginas clássicas de ASP e ASP.NET e precisa de uma boa maneira de gerenciar suas definições de configuração.

Eu gostaria de usar um costume ConfigurationSection, e para as páginas ASP.NET isso funciona muito bem. Mas quando o componente é chamado via interoperabilidade COM a partir de uma página ASP clássica, o componente não está sendo executado no contexto de uma solicitação ASP.NET e, portanto, não tem conhecimento do web.config.

Existe uma maneira de dizer ConfigurationManagerpara apenas carregar a configuração de um caminho arbitrário (por exemplo, ..\web.configse meu assembly estiver na /binpasta)? Se houver, acho que meu componente pode voltar a isso se o padrão ConfigurationManager.GetSectionretornar nullpara minha seção personalizada.

Quaisquer outras abordagens para isso serão bem-vindas!

Mike Powell
fonte

Respostas:

124

Tente o seguinte:

System.Configuration.ConfigurationFileMap fileMap = new ConfigurationFileMap(strConfigPath); //Path to your config file
System.Configuration.Configuration configuration = System.Configuration.ConfigurationManager.OpenMappedMachineConfiguration(fileMap);
Ishmaeel
fonte
Como obter programaticamente o valor strConfigPath para meu aplicativo ASP.NET WebForms hospedado em sub.domínio.com / virtualDir2 e o caminho C: \ Portals \ App1 \ v2 e o arquivo de configuração em C: \ Portals \ App1 \ v2 \ web.config ?
Kiquenet 7/10
1
@Kiquenet: O ponto da questão é que strConfigPath é um local arbitrário . Em outras palavras, você decide qual é o caminho, em vez de confiar na estrutura para tentar carregar um arquivo de configuração a partir de seu local convencional. Eu assumiria que Server.MapPath forneceria a localização absoluta para todos os arquivos em sua solução.
Ishmaeel 7/10
1
Talvezvar config = System.Web.Configuration.WebConfigurationManager.OpenWebConfiguration("~/web.config");
Kiquenet
@Kiquenet Definitely.
Ucho 19/02
66

Outra solução é substituir o caminho do arquivo de configuração do ambiente padrão.

Acho que é a melhor solução para o carregamento de arquivos de configuração de caminho não trivial, especificamente a melhor maneira de anexar arquivos de configuração à dll.

AppDomain.CurrentDomain.SetData("APP_CONFIG_FILE", <Full_Path_To_The_Configuration_File>);

Exemplo:

AppDomain.CurrentDomain.SetData("APP_CONFIG_FILE", @"C:\Shared\app.config");

Mais detalhes podem ser encontrados neste blog .

Além disso, esta outra resposta possui uma excelente solução, completa com código para atualizar a configuração do aplicativo e um IDisposableobjeto para redefini-la ao seu estado original. Com esta solução, você pode manter a configuração temporária do aplicativo no escopo:

using(AppConfig.Change(tempFileName))
{
    // tempFileName is used for the app config during this context
}
Saturn Technologies
fonte
1
Isso também funciona para carregar arquivos web.config. Eu o uso para carregar um web.config em vez de app.config para um aplicativo de console relacionado a tarefas. ;)
James Wilkins
1
Isso (e as outras respostas aqui) não funciona para mim. Eu adicionei o código na função program.cs -: Main (). Minha configuração contém um redirecionamento de versão do assembly (consulte stackoverflow.com/questions/30165393/… ), mas o redirecionamento não afeta quando a configuração é alterada manualmente.
Vortex852456
1
Você usou "APP_CONFIG_FILE"?
Saturn Technologies
40

A resposta de Ishmaeel geralmente funciona, no entanto, encontrei um problema, que é o de que o uso OpenMappedMachineConfigurationparece perder seus grupos de seções herdados do machine.config. Isso significa que você pode acessar suas próprias seções personalizadas (que é todo o OP desejado), mas não as seções normais do sistema. Por exemplo, este código não funcionará:

ConfigurationFileMap fileMap = new ConfigurationFileMap(strConfigPath);
Configuration configuration = ConfigurationManager.OpenMappedMachineConfiguration(fileMap);
MailSettingsSectionGroup thisMail = configuration.GetSectionGroup("system.net/mailSettings") as MailSettingsSectionGroup;  // returns null

Basicamente, se você observar configuration.SectionGroups, verá que o system.net não está registrado como um SectionGroup, por isso é praticamente inacessível pelos canais normais.

Encontrei duas maneiras de contornar isso. A primeira, da qual não gosto, é reimplementar os grupos de seções do sistema, copiando-os do machine.config para o seu próprio web.config, por exemplo

<sectionGroup name="system.net" type="System.Net.Configuration.NetSectionGroup, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
  <sectionGroup name="mailSettings" type="System.Net.Configuration.MailSettingsSectionGroup, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
    <section name="smtp" type="System.Net.Configuration.SmtpSection, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
  </sectionGroup>
</sectionGroup>

Não sei se o aplicativo da Web será executado corretamente depois disso, mas você pode acessar os sectionGroups corretamente.

A segunda solução é abrir o seu web.config como uma configuração EXE, que provavelmente está mais próxima da função pretendida:

ExeConfigurationFileMap fileMap = new ExeConfigurationFileMap() { ExeConfigFilename = strConfigPath };
Configuration configuration = ConfigurationManager.OpenMappedExeConfiguration(fileMap, ConfigurationUserLevel.None);
MailSettingsSectionGroup thisMail = configuration.GetSectionGroup("system.net/mailSettings") as MailSettingsSectionGroup;  // returns valid object!

Ouso dizer que nenhuma das respostas fornecidas aqui, nem a minha nem a de Ishmaeel, estão usando essas funções como os projetistas do .NET pretendiam. Mas, isso parece funcionar para mim.

Gavin
fonte
1
Você também pode usar a sobrecarga de ConfigurationManager.OpenExeConfiguration (String) para a mesma finalidade. Veja: codeproject.com/KB/dotnet/mysteriesofconfiguration3.aspx#t2_1
Ohad Schneider
10

Além da resposta de Ishmaeel, o método OpenMappedMachineConfiguration()sempre retornará um Configurationobjeto. Portanto, para verificar se ele carregou, verifique a HasFilepropriedade onde true significa que veio de um arquivo.

Joseph Daigle
fonte
9

A resposta aceita está errada !!

Ele lança a seguinte exceção ao acessar a propriedade AppSettings:

Não foi possível converter o objeto do tipo 'System.Configuration.DefaultSection' para o tipo 'System.Configuration.AppSettingsSection'.

Aqui está a solução correta:

System.Configuration.ExeConfigurationFileMap fileMap = new ExeConfigurationFileMap();
fileMap.ExeConfigFilename = "YourFilePath";
System.Configuration.Configuration configuration = System.Configuration.ConfigurationManager.OpenMappedExeConfiguration(fileMap, ConfigurationUserLevel.None);
Jacob
fonte
1
Sim, esta é definitivamente a resposta certa! Obrigado por postar sua resposta.
Fabio Milheiro
Eu acho que System.Web.Configuration.WebConfigurationManager.OpenWebConfiguration é ainda mais correto, mas não está disponível para o .NET Core, portanto, nesse caso, essa resposta parece concluir o trabalho.
Risord 8/10/19
4

Forneci os valores de configuração à palavra hospedada .nET Compoent da seguinte maneira.

Um componente da .NET Class Library sendo chamado / hospedado no MS Word. Para fornecer valores de configuração ao meu componente, criei winword.exe.config na pasta C: \ Arquivos de Programas \ Microsoft Office \ OFFICE11. Você deve conseguir ler os valores das configurações como faz no .NET tradicional.

string sMsg = System.Configuration.ConfigurationManager.AppSettings["WSURL"];
Iftikhar Ali
fonte
1

Para o ASP.NET, use o WebConfigurationManager:

var config = WebConfigurationManager.OpenWebConfiguration("~/Sites/" + requestDomain + "/");
(..)
config.AppSettings.Settings["xxxx"].Value;
Javier Cañon
fonte
0

Use o processamento XML:

var appPath = AppDomain.CurrentDomain.BaseDirectory;
var configPath = Path.Combine(appPath, baseFileName);;
var root = XElement.Load(configPath);

// can call root.Elements(...)
JoelFan
fonte