Изменение App.config во время выполнения

Я пишу тестовое приложение WinForms/C#/.NET 3.5 для системы, которую мы разрабатываем, и нам пришлось переключаться между файлами .config во время выполнения, но это оказалось кошмаром.

Вот сцена: приложение WinForms предназначено для тестирования WebApp, разделенного на 5 подсистем. Процесс тестирования работает с сообщениями, отправляемыми между подсистемами, и для того, чтобы этот процесс был успешным, каждая подсистема должна иметь свой собственный файл .config.

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

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

Заранее спасибо!

--- ОБНОВЛЕНИЕ 06.01.10 ---

Есть кое-что, о чем я не упомянул раньше. Изначально наша система представляла собой веб-приложение с вызовами WCF между каждой подсистемой. Из соображений тестирования производительности (мы используем ANTS 4) нам пришлось создать локальную копию сборок и ссылаться на них из тестового проекта. Это может показаться немного неправильным, но мы не смогли найти удовлетворительного способа измерения производительности удаленного приложения.

--- Завершить обновление ---

Вот что я делаю:

public void UpdateAppSettings(string key, string value)
{
    XmlDocument xmlDoc = XmlDocument.Load(AppDomain.CurrentDomain.SetupInformation.ConfigurationFile);

    foreach (XmlElement item in xmlDoc.DocumentElement)
    {
        foreach (XmlNode node in item.ChildNodes)
        {
            if (node.Name == key)
            {
                node.Attributes[0].Value = value;
                break;
            }
        }
    }

    xmlDoc.Save(AppDomain.CurrentDomain.SetupInformation.ConfigurationFile);

    System.Configuration.ConfigurationManager.RefreshSection("section/subSection");    
}

person born to hula    schedule 05.01.2010    source источник
comment
дубликат / связанный? stackoverflow.com/questions/1542171/   -  person Hogan    schedule 06.01.2010
comment
Я уже пробовал эти подходы... проблема в том, что тег, который я меняю, находится вне ‹appSettings›. Я также пытался создать новые домены приложений и установить для них разные файлы .config, но это тоже не сработало.   -  person born to hula    schedule 06.01.2010


Ответы (4)


ОБНОВЛЕНИЕ

Приведенное ниже решение не сработало, потому что XmlDocument не удаляется, и кажется, что некоторые версии .net не закрываются правильно при указании пути к файлу. Решение (пример кода в ссылке) состоит в том, чтобы открыть поток, который будет выполнять удаление, и передать этот поток функции сохранения.

Здесь показано решение. http://web-beta.archive.org/web/20150107004558/www.devnewsgroups.net/group/microsoft.public.dotnet.xml/topic40736.aspx


Старые материалы ниже

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

Обратите внимание, я перешел на xpath, но прошло некоторое время, поэтому я мог неправильно понять xpath, но в любом случае вы должны использовать xpath, а не ходить по дереву. Как видите, стало намного понятнее.

Важным моментом является оператор using, который будет dispose(), что, я думаю, было вашей проблемой.

Дай знать, удачи.

  public void UpdateAppSettings(string key, string value)
  {
    using (XmlDocument xmlDoc = new XmlDocument())
    {
      xmlDoc.Load(AppDomain.CurrentDomain.SetupInformation.ConfigurationFile);
      xmlDoc.DocumentElement.FirstChild.SelectSingleNode("descendant::"+key).Attributes[0].Value = value;
      xmlDoc.Save(AppDomain.CurrentDomain.SetupInformation.ConfigurationFile);
    }
    System.Configuration.ConfigurationManager.RefreshSection("section/subSection");
  }
person Hogan    schedule 06.01.2010
comment
В этом есть смысл, проблема в том, что XmlDocument не реализует IDisposable, поэтому невозможно использовать область использования. - person born to hula; 06.01.2010
comment
Ну, у меня есть небольшое предположение, что это не так. Я использую фреймворк .NET 3.5. Кроме того, я думаю, что если бы файловый поток все еще был открыт, при второй попытке записи в файл xml я бы получил исключение... но все равно спасибо. - person born to hula; 06.01.2010
comment
ммм... есть задокументированная проблема с .net framework с примером кода, который выглядит точно так же, как у вас, я даю вам ссылку на код, решающий эту проблему, и вы не собираетесь его пробовать? Вы не хотите решить проблему? - person Hogan; 07.01.2010
comment
Я попробую и сообщу вам о результатах. Спасибо за вашу помощь. - person born to hula; 07.01.2010
comment
Я попробовал это, и, по-видимому, результат был таким же. Все равно спасибо мужик. - person born to hula; 07.01.2010
comment
К плохому - извините, я не мог помочь. - person Hogan; 07.01.2010
comment
Эта ссылка на devnewsgroups была взломана. - person Øyvind; 01.07.2015

Я понимаю, что это довольно старый поток, но я не мог заставить работать перечисленные методы. Вот более простая версия метода UpdateAppSettings (с использованием .NET 4.0):

private void UpdateAppSettings(string theKey, string theValue)
        {
            Configuration configuration = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
            if (ConfigurationManager.AppSettings.AllKeys.Contains(theKey))
            {
                configuration.AppSettings.Settings[theKey].Value = theValue;
            }

            configuration.Save(ConfigurationSaveMode.Modified);

            ConfigurationManager.RefreshSection("appSettings");
        }

Довольно читабельно и позволяет избежать необходимости просматривать app.config с помощью Xpath или тому подобного. Примечание. Приведенный выше код взят из этого. фрагмент в MSDN.

person Sudhanshu Mishra    schedule 11.04.2012
comment
Не работает в моем приложении winforms, работает нормально, но в *.config никаких изменений - person Eric Brown - Cal; 08.08.2019

Я предполагаю, что вы на самом деле не закрываете дескриптор файла в первый раз, поэтому Windows не «видит», что вы вносите более поздние изменения.

Я предлагаю использовать вызов API для IIS и отключить веб-приложение (и пул), внести изменения, включить веб-приложение. Таким образом, вы уверены, что он перечитает файл и будет иметь «чистую» среду для каждого теста.

person Hogan    schedule 05.01.2010
comment
Я обновил вопрос с некоторыми деталями. По сути, в этом контексте (тестирование производительности) мы не используем IIS, на сборки ссылаются локально. Я использую библиотеки Xml для записи в файл .config. Во время выполнения я вижу, что файл записывается и изменяется. - person born to hula; 06.01.2010

Предполагая, что дескриптор файла конфигурации закрыт после того, как файл конфигурации был прочитан и обработан, я бы отправил сообщение приложению, чтобы сообщить ему перечитать файл конфигурации после того, как вы обновили файл. Если этот подход не работает, то я подозреваю (как предположил Хоган), что дескриптор файла не закрыт. Какие коды ошибок вы получаете при открытии, чтении и закрытии файлов системными вызовами? (используйте perror, чтобы сообщить об ошибке)

person David Harris    schedule 05.01.2010
comment
Этот подход интересен, но не могли бы вы дать мне несколько шагов о том, как отправить это сообщение в приложение? Я попытался вызвать ConfigurationManager.RefreshSection(), но это не сработало. - person born to hula; 06.01.2010
comment
@born to hula: Как изменить конфигурацию во время выполнения? Я бы использовал тот же подход, чтобы приложение перечитало файл конфигурации. Какой язык и ОС вы используете? Какие сообщения отправляются приложению во время тестирования? Входные данные для приложения поступают с веб-страницы? Ответы на эти вопросы дадут некоторые подсказки о наилучшем подходе к вашей ситуации. - person David Harris; 06.01.2010
comment
Я использую XmlDocument для изменения файла .config (см. обновленный вопрос). Но независимо от того, сколько раз я его изменю, изменения будут отражены только один раз в контексте выполнения. Я использую С# и Windows XP. Ввод из приложения поступает прямо из формы. По сути, основной ввод — это сообщение, из которого создаются разнообразные объекты. - person born to hula; 06.01.2010
comment
@born to hula: Мой опыт работы с Unix; не на винде. Прости. - person David Harris; 07.01.2010