Winforms – How to edit an external web.config file

configurationweb-configwinforms

I am trying to write a winform application that would be able to edit the web.config file of an installed web application.
I have read through the ConfigurationManager and WebConfigurationManager class methods but I am unsure as to how I can open the configuration file of a web app and edit it.

I am looking for a method that does not require me to load the config file as a regular XmlDocument, although I am willing to do that if that is the only option available.

Any advice would be appreciated.

Best Solution

Ok so here is the answer, I have the EXACT same scenario. I wanted to write a winforms app to allow normal users to update the web.config. You have to go about getting the config a goofy way...

// the key of the setting
string key = "MyKey";

// the new value you want to change the setting to
string value = "This is my New Value!";

// the path to the web.config
string path = @"C:\web.config";

// open your web.config, so far this is the ONLY way i've found to do this without it wanting a virtual directory or some nonsense
// even "OpenExeConfiguration" will not work
var config = ConfigurationManager.OpenMappedExeConfiguration(new ExeConfigurationFileMap() { ExeConfigFilename = path }, ConfigurationUserLevel.None);

// now that we have our config, grab the element out of the settings
var element = config.AppSettings.Settings[key];

// it may be null if its not there already
if (element == null)
{
 // we'll handle it not being there by adding it with the new value
 config.AppSettings.Settings.Add(key, value);
}
else
{
 // note: if you wanted to you could inspect the current value via element.Value

 // in this case, its already present, just update the value
 element.Value = value;
}

// save the config, minimal is key here if you dont want huge web.config bloat
config.Save(ConfigurationSaveMode.Minimal, true);

Here is an example of what it does

Before:

<?xml version="1.0"?>
<configuration>
  <appSettings>
    <add key="MyKey" value="OldValue" />
  </appSettings>
  <connectionStrings>
    <add name="myConnString" connectionString="blah blah blah" providerName="System.Data.SqlClient" />
  </connectionStrings>
</configuration>

After:

<?xml version="1.0"?>
<configuration>
  <appSettings>
    <add key="MyKey" value="This is my New Value!" />
  </appSettings>
  <connectionStrings>
    <add name="myConnString" connectionString="blah blah blah" providerName="System.Data.SqlClient" />
  </connectionStrings>
  <system.web>
    <trust level="Full" />
    <webControls clientScriptsLocation="/aspnet_client/{0}/{1}/" />
  </system.web>
</configuration>

Just be careful, if you give it an invalid path, it will just create a config file at that path / filename. Basically, do a File.Exists check on it first

BTW, while you're at it, you could write a class that represents your settings in your web.config. Once you do this, write your getters/setters to read/write the settings in the web.config. Once THIS is done, you can add this class as a datasource and drag the databound controls onto your winform. This will give you a completely databound winform web.config editor that you can easily hammer out in a matter of minutes. I've got an example at work that I'll post tomorrow.

Fully featured winforms solution

So this is a relatively simple solution to writing a Gui to edit a web.config, some may say its overly complicated when notepad will do just fine but it works for me and my audience.

It basically works as described above, I wrote a class that had the configuration points that I wanted as properties. The ctor opens the file from a path and the getters / setters pull the data out of the returned configuration object, finally it has a save method that writes it out. With this class, I'm able to add the class as a datasource and drag / drop bound controls onto winforms. From there all you have to do is to wire up a button that calls the save method on your class.

Configuration class

using System.Configuration;

// This is a representation of our web.config, we can change the properties and call save to save them
public class WebConfigSettings
{
 // This holds our configuration element so we dont have to reopen the file constantly
 private Configuration config;

 // given a path to a web.config, this ctor will init the class and open the config file so it can map the getters / setters to the values in the config
 public WebConfigSettings(string path)
 {
  // open the config via a method that we wrote, since we'll be opening it in more than 1 location
  this.config = this.OpenConfig(path);
 }

 // Read/Write property that maps to a web.config setting
 public string MySetting
 {
  get { return this.Get("MySetting"); }
  set { this.Set("MySetting", value); }
 }

 // Read/Write property that maps to a web.config setting
 public string MySetting2
 {
  get { return this.Get("MySetting2"); }
  set { this.Set("MySetting2", value); }
 }

 // helper method to get the value of a given key
 private string Get(string key)
 { 
  var element = config.AppSettings.Settings[key];

  // it may be null if its not there already
  if (element == null)
  {
   // we'll handle it not being there by adding it with the new value
   config.AppSettings.Settings.Add(key, "");

   // pull the element again so we can set it below
   element = config.AppSettings.Settings[key];
  }
  return element.Value;
 }

 // helper method to set the value of a given key
 private void Set(string key, string value)
 {
  // now that we have our config, grab the element out of the settings
  var element = this.config.AppSettings.Settings[key];

  // it may be null if its not there already
  if (element == null)
  {
   // we'll handle it not being there by adding it with the new value
   config.AppSettings.Settings.Add(key, value);
  }
  else
  {
   // in this case, its already present, just update the value
   element.Value = value;
  }
 }

 // Writes all the values to the config file
 public void Save()
 {
  // save the config, minimal is key here if you dont want huge web.config bloat
  this.config.Save(ConfigurationSaveMode.Minimal, true);
 }

 public void SaveAs(string newPath)
 {
  this.config.SaveAs(path, ConfigurationSaveMode.Minimal, true);

  // due to some weird .net issue, you have to null the config out after you SaveAs it because next time you try to save, it will error
  this.config = null;
  this.config = this.OpenConfig(newPath);
 }

 // where the magic happens, we'll open the config here     
 protected Configuration OpenConfig(string path)
 {
  return ConfigurationManager.OpenMappedExeConfiguration(
        new ExeConfigurationFileMap() {  ExeConfigFilename = path }, 
        ConfigurationUserLevel.None);   
 }
}

Build and then from there you can just goto your winform designer, goto Data > Show Data Sources (Shift+Alt+D). Right click > Add New Data Source and add it as an object as shown

Data Source Configuration Wizard 1 of 2 http://img109.imageshack.us/img109/8268/98868932.png

Data Source Configuration Wizard 2 of 2 http://img714.imageshack.us/img714/7287/91962513.png

Drag it (WebConfigSettings, the topmost) onto the winform. In my case, I will remove the navigator as that is for a List and I just have one.

Freshly added databound controls http://img96.imageshack.us/img96/8268/29648681.png

You should have something like webConfigSettingsBindingSource at the bottom of the designer (shown in the next pic). Goto the code view and change the ctor to this

public Form1()
{
    InitializeComponent();

    // wire up the actual source of data
    this.webConfigSettingsBindingSource.DataSource = new WebConfigSettings(@"c:\web.config");
}

Add a save button to your winform

Save button added http://img402.imageshack.us/img402/8634/73975062.png

Add the following event handler

private void saveButton_Click(object sender, EventArgs e)
{
    // get our WebConfigSettings object out of the datasource to do some save'n
    var settings = (WebConfigSettings)this.webConfigSettingsBindingSource.DataSource;

    // call save, this will write the changes to the file via the ConfigurationManager
    settings.Save();
}

There, now you have a nice simple databound web.config editor. To add / remove fields, you just modify your WebConfigSettings class, refresh the datasource in the Data Sources window (after a build), and then drag n drop the new fields onto the UI.

You'll still have to wire up some code that specifies a web.config to open, for this example I just hard coded the path.

The cool thing here is all the value that a GUI adds. You can easily add directory or filebrowser dialogs, you can have connection string testers etc. All are very easy to add and very powerful to the end user.