Changing App.config at Runtime
Asked Answered
T

4

8

I'm writing a test WinForms / C# / .NET 3.5 application for the system we're developing and we fell in the need to switch between .config files at runtime, but this is turning out to be a nightmare.

Here's the scene: the WinForms application is aimed at testing a WebApp, divided into 5 subsystems. The test process works with messages being sent between the subsystems, and for this process to be successful each subsystem got to have its own .config file.

For my Test Application I wrote 5 separate configuration files. I wish I was able to switch between these 5 files during runtime, but the problem is: I can programatically edit the application .config file numerous times, but these changes will only take effect once. I've been searching a long time for a form to address this problem but I still wasn't successful.

I know the problem definition may be a bit confusing but I would really appreciate it if someone helped me.

Thanks in advance!

--- UPDATE 01-06-10 ---

There's something I didn't mention before. Originally, our system is a Web Application with WCF calls between each subsystem. For performance testing reasons (we're using ANTS 4), we had to create a local copy of the assemblies and reference them from the test project. It may sound a bit wrong, but we couldn't find a satisfying way to measure performance of a remote application.

--- End Update ---

Here's what I'm doing:

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");    
}
Thelen answered 5/1, 2010 at 20:20 Comment(2)
dup / related? #1542671Reginaldreginauld
I've already tried these aproaches... the problem is, the tag I'm changing is outside <appSettings>. I also tried creating new AppDomains and setting different .config files to them, but it didn't work either.Thelen
R
3

UPDATE

The solution below did not work because XmlDocument does not dispose and it seems some versions of .net do not close correctly when given a file path. The solution (example code in the link) is to open a stream which will do a dispose and pass that stream to the save function.

A solution is shown here. http://web-beta.archive.org/web/20150107004558/www.devnewsgroups.net/group/microsoft.public.dotnet.xml/topic40736.aspx


Old stuff below

Try this:

Note, I changed to xpath, but it has been a while so I might have gotten the xpath wrong, but in any case you should use xpath and not walk the tree. As you can see it is much clearer.

The important point is the using statement which will dispose(), which I think was your problem.

Let me know, good luck.

  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");
  }
Reginaldreginauld answered 6/1, 2010 at 16:43 Comment(7)
That kinda makes sense, the problem is XmlDocument doesn't implement IDisposable, so it is not possible to use the "using" scope.Thelen
Well, I have a slight guess that this isn't the case. I'm using framework .NET 3.5. Besides, I think if the file stream was still open, by the second time I'd try to write to the xml file, I would get an exception... but thanks anyway.Thelen
ummm... there is a documented problem with the .net framework with example code that looks exactly the same as yours, I provide you with a link to code that solves that problem and you are not going to try it? Don't you want to fix the problem?Reginaldreginauld
I'm gonna give it a try and will update you with the results. Thanks for your help.Thelen
I've tried it out and apparently the result was the same. Thanks anyway man.Thelen
To bad -- sorry I could not help.Reginaldreginauld
That devnewsgroups link has been hijacked.Arondell
A
27

I understand this is quite an old thread, but I could not get the listed methods to work. Here is a simpler version of the UpdateAppSettings method (using .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");
        }

Pretty readable and avoids having to traverse the app.config using Xpath or the like. Note: The code above is inspired from this snippet on MSDN.

Adamec answered 11/4, 2012 at 16:34 Comment(1)
Doesn't work in my winforms app, executes fine, but no change in *.configParagraphia
R
3

UPDATE

The solution below did not work because XmlDocument does not dispose and it seems some versions of .net do not close correctly when given a file path. The solution (example code in the link) is to open a stream which will do a dispose and pass that stream to the save function.

A solution is shown here. http://web-beta.archive.org/web/20150107004558/www.devnewsgroups.net/group/microsoft.public.dotnet.xml/topic40736.aspx


Old stuff below

Try this:

Note, I changed to xpath, but it has been a while so I might have gotten the xpath wrong, but in any case you should use xpath and not walk the tree. As you can see it is much clearer.

The important point is the using statement which will dispose(), which I think was your problem.

Let me know, good luck.

  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");
  }
Reginaldreginauld answered 6/1, 2010 at 16:43 Comment(7)
That kinda makes sense, the problem is XmlDocument doesn't implement IDisposable, so it is not possible to use the "using" scope.Thelen
Well, I have a slight guess that this isn't the case. I'm using framework .NET 3.5. Besides, I think if the file stream was still open, by the second time I'd try to write to the xml file, I would get an exception... but thanks anyway.Thelen
ummm... there is a documented problem with the .net framework with example code that looks exactly the same as yours, I provide you with a link to code that solves that problem and you are not going to try it? Don't you want to fix the problem?Reginaldreginauld
I'm gonna give it a try and will update you with the results. Thanks for your help.Thelen
I've tried it out and apparently the result was the same. Thanks anyway man.Thelen
To bad -- sorry I could not help.Reginaldreginauld
That devnewsgroups link has been hijacked.Arondell
R
1

My guess is you are not really closing the file handle the first time so windows does not "see" you making the later changes.

My suggestions is to use an API call to IIS and turn off the web app (and pool), make the change, turn on the web app. This way you are sure it will re-read the file and have a "clean" environment for each test.

Reginaldreginauld answered 5/1, 2010 at 20:25 Comment(1)
I updated the question with some details. Basically, in this context (performance testing) we're not using IIS, the assemblies are being referenced locally. I'm using Xml libraries to write to the .config file. During execution I can see that the file is being written and changed.Thelen
F
0

Assuming that the file handle to the configuration file is closed after the configuration file has been read and processed, I would send a message to the application to tell it to re-read the configuration file after you have updated the file. If this approach is not working, then I suspect (as Hogan suggested) that the file handle is not closed. What error codes are you getting from the file opening, reading and closing system calls? (use perror to report the error message)

Fibrinolysin answered 5/1, 2010 at 20:54 Comment(4)
This approach is interesting, but can you give me some steps on how to send this message to the application? I tried calling ConfigurationManager.RefreshSection() but it didn't work out.Thelen
@born to hula: How do you change the configuration @ runtime? I'd use the same approach to have the application reread the configuration file. What language and OS are you using? What are the messages sent to the application during testing? Does the input to the application come from a web page? Answering these questions would give some clues about the best approach for your situation.Fibrinolysin
I'm using XmlDocument to change the .config file (refer to the updated question). But, regardless of how many times I change it, the changes will only be reflected once on the execution context. I'm using C# and Windows XP. The input from the application comes straight from the form. Basically, the main input is a message, from which a variety of objects is created.Thelen
@born to hula: My experience is on Unix; not on Windows. Sorry.Fibrinolysin

© 2022 - 2024 — McMap. All rights reserved.