Использование ConfigurationManager для загрузки конфигурации из произвольного места

124

Я разрабатываю компонент доступа к данным, который будет использоваться на веб-сайте, который содержит сочетание классических страниц ASP и ASP.NET, и мне нужен хороший способ управления его параметрами конфигурации.

Я хотел бы использовать обычай ConfigurationSection, и для страниц ASP.NET это отлично работает. Но когда компонент вызывается через COM-взаимодействие с классической страницы ASP, компонент не работает в контексте запроса ASP.NET и, следовательно, не знает web.config.

Есть ли способ указать ConfigurationManagerпросто загрузить конфигурацию по произвольному пути (например, ..\web.configесли моя сборка находится в /binпапке)? Если есть, то я думаю, что мой компонент может вернуться к этому, если для моего настраиваемого раздела ConfigurationManager.GetSectionвернется значение по умолчанию null.

Приветствуются любые другие подходы к этому!

Майк Пауэлл
источник
2
См. Stackoverflow.com/questions/3912727/…
Охад Шнайдер

Ответы:

124

Попробуй это:

System.Configuration.ConfigurationFileMap fileMap = new ConfigurationFileMap(strConfigPath); //Path to your config file
System.Configuration.Configuration configuration = System.Configuration.ConfigurationManager.OpenMappedMachineConfiguration(fileMap);
Ishmaeel
источник
Как я могу программно получить значение strConfigPath для моего приложения ASP.NET WebForms, размещенного в sub.domain.com/virtualDir2, и пути C: \ Portals \ App1 \ v2 и файла конфигурации в C: \ Portals \ App1 \ v2 \ web.config ?
Kiquenet 07
1
@Kiquenet: Суть вопроса в том, что strConfigPath - это произвольное местоположение. Другими словами, вы сами решаете, каков путь, вместо того, чтобы полагаться на фреймворк, пытаясь загрузить файл конфигурации из его обычного местоположения. Я предполагаю, что Server.MapPath предоставит вам абсолютное расположение любых файлов в вашем решении.
Ishmaeel
1
Может бытьvar config = System.Web.Configuration.WebConfigurationManager.OpenWebConfiguration("~/web.config");
Kiquenet
@Kiquenet Определенно.
Учо
66

Другое решение - переопределить путь к файлу конфигурации среды по умолчанию.

Я считаю, что это лучшее решение для загрузки файла конфигурации нетривиального пути, в частности лучший способ прикрепить файл конфигурации к dll.

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

Пример:

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

Более подробную информацию можно найти в этом блоге .

Кроме того, у этого другого ответа есть отличное решение, в комплекте с кодом для обновления конфигурации приложения и IDisposableобъектом, чтобы вернуть его в исходное состояние. С помощью этого решения вы можете сохранить временную конфигурацию приложения в определенной области:

using(AppConfig.Change(tempFileName))
{
    // tempFileName is used for the app config during this context
}
Сатурн Технологии
источник
1
Это также работает для загрузки файлов web.config. Я использую его для загрузки web.config вместо app.config для консольного приложения, связанного с задачами. ;)
Джеймс Уилкинс
1
Этот (и другие ответы здесь) не работает для меня. Я добавил код в program.cs - function: Main (). Моя конфигурация содержит перенаправление версии сборки (см. Stackoverflow.com/questions/30165393/… ), но перенаправление не влияет на изменение конфигурации вручную.
Vortex852456
1
Вы использовали "APP_CONFIG_FILE"?
Saturn Technologies
40

Ответ Ishmaeel обычно работает, однако я обнаружил одну проблему, заключающуюся в том, что использование, OpenMappedMachineConfigurationпохоже, теряет ваши унаследованные группы разделов из machine.config. Это означает, что вы можете получить доступ к своим собственным пользовательским разделам (а это все, что нужно OP), но не к обычным системным разделам. Например, такой код работать не будет:

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

По сути, если вы configuration.SectionGroupsвключите часы , вы увидите, что system.net не зарегистрирован как SectionGroup, поэтому он практически недоступен через обычные каналы.

Я нашел два способа обойти это. Первое, что мне не нравится, - это повторно реализовать группы системных разделов, скопировав их из machine.config в свой собственный web.config, например

<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>

Я не уверен, что само веб-приложение после этого будет работать правильно, но вы можете правильно получить доступ к sectionGroups.

Второе решение - вместо этого открыть ваш web.config как конфигурацию EXE, которая, вероятно, в любом случае ближе к предполагаемой функции:

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!

Осмелюсь предположить, что ни один из приведенных здесь ответов, ни мой, ни Ишмаил, не использует эти функции так, как задумано разработчиками .NET. Но, похоже, это работает для меня.

Gavin
источник
1
Вы также можете использовать перегрузку ConfigurationManager.OpenExeConfiguration (String) для той же цели. См .: codeproject.com/KB/dotnet/mysteriesofconfiguration3.aspx#t2_1
Охад Шнайдер
10

В дополнение к ответу Ishmaeel метод OpenMappedMachineConfiguration()всегда будет возвращать Configurationобъект. Итак, чтобы проверить, загрузился ли он, вы должны проверить HasFileсвойство, где true означает, что оно было получено из файла.

Джозеф Дейгл
источник
9

Принятый ответ неверен !!

Он вызывает следующее исключение при доступе к свойству AppSettings:

Невозможно преобразовать объект типа «System.Configuration.DefaultSection» к типу «System.Configuration.AppSettingsSection».

Вот правильное решение:

System.Configuration.ExeConfigurationFileMap fileMap = new ExeConfigurationFileMap();
fileMap.ExeConfigFilename = "YourFilePath";
System.Configuration.Configuration configuration = System.Configuration.ConfigurationManager.OpenMappedExeConfiguration(fileMap, ConfigurationUserLevel.None);
Иаков
источник
1
да, это определенно правильный ответ! Спасибо, что разместили свой ответ.
Fabio Milheiro
Я думаю, что System.Web.Configuration.WebConfigurationManager.OpenWebConfiguration еще более правильный, но он недоступен для .NET Core, поэтому в этом случае этот ответ, похоже, выполняет работу.
Risord 08
4

Я предоставил значения конфигурации для Word hosted .nET Compoent следующим образом.

Компонент библиотеки классов .NET вызывается / размещается в MS Word. Чтобы предоставить значения конфигурации моему компоненту, я создал файл winword.exe.config в папке C: \ Program Files \ Microsoft Office \ OFFICE11. Вы должны уметь читать значения конфигурации, как в традиционном .NET.

string sMsg = System.Configuration.ConfigurationManager.AppSettings["WSURL"];
Ифтихар Али
источник
1

Для ASP.NET используйте WebConfigurationManager:

var config = WebConfigurationManager.OpenWebConfiguration("~/Sites/" + requestDomain + "/");
(..)
config.AppSettings.Settings["xxxx"].Value;
Хавьер Каньон
источник
0

Использовать обработку XML:

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

// can call root.Elements(...)
JoelFan
источник