Dot Net

Syrinx .NET Development Blog
Need help on your project? info@syrinx.com, or toll free (888) 579-7469, press 1

News



Need help with your .NET Development project?

Syrinx works with clients throughout New England to architect, design, develop, and deploy .NET Applications. Working on fully outsourced projects, as part of your team, helping to train your team, or rescuing projects in trouble, we are comfortable doing it all. Projects from a couple weeks to several months in duration, reference clients available. Contact us today - info@syrinx.com, or toll free (888) 579-7469 and press 1 to speak to someone now!

Part 2 - Modify app.config On-The-Fly

In this installation of my blog series I’ll cover the first concrete item listed in the introduction. Implement a WinForm that modifies its own Config file.

Let’s start by creating a Main form for the UI that will be our work area for the Code Generator.  We add a button “Modify Config” that executes the following code to launch the frmAppConfig form:

private void btnModifyConfig_Click(object sender, EventArgs e)       
{
            frmAppConfig dlgAppconfig = new frmAppConfig();
            dlgAppconfig.ShowDialog();       
}

The form itself looks like this at this point:

Main Syrinx Code Generator application form 

The frmAppConfig executes the following LoadConfigValues code called from its constructor:

        private void LoadConfigValues()        
        {
            try
            {
                NameValueCollection appSettings
                    = ConfigurationManager.AppSettings;
                dgvAppConfigSettings.Rows.Clear();
                dgvAppConfigSettings.Rows.Add(appSettings.Count);
                int i = 0;
                foreach (string key in appSettings)
                {
                    string value = appSettings[key];
                    DataGridViewRow row = dgvAppConfigSettings.Rows[i++];
                    row.Cells["Key"].Value = key;
                    row.Cells["Value"].Value = value;
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message,
                                "Setting Application Configuration Error",
                                MessageBoxButtons.OK,
                                MessageBoxIcon.Stop);
            }
        } 

As you can see the method uses the System.Configuration.ConfigurationManager.AppSettings property to get a System.Collections.Specialized.NameValueCollection of the app settings in the app.config file.  If we open the app.config file we’ll see the following:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <appSettings>
    <clear />
    <add key="CodeGeneratorDefinitionFilePath" value="C:\Syrinx\Syrinx.Architecture\DefinitionFiles\" />
    <add key="DataAccessFilePath" value="C:\Syrinx\Syrinx.Consumer\DataAccess\" />
    <add key="ApplicationObjectFilePath" value="C:\Syrinx\Syrinx.Consumer\ApplicationObject\" />
    <add key="DeveloperName" value="John P. Frampton" />
    <add key="InterfaceObjectFilePath" value="C:\Syrinx\Syrinx.Consumer\InterfaceObject\" />
    <add key="StoredProcedureFilePath" value="C:\Syrinx\Syrinx.DB\StoredProcedures\" />
    <add key="TableDefinitionFilePath" value="C:\Syrinx\Syrinx.DB\Tables\" />
  </appSettings>
  <connectionStrings>
    <add
      name="FakeConnectionString"
      connectionString="NotReally"/>
  </connectionStrings>
</configuration>

Note that there is a connectionStrings section in the app.config with which we are not concerned and which will not be modified.  If we run our application, not in debug mode, but with the actual compiled .exe, the frmAppConfig form will display the following:

Starting App.config 

As expected the DataGridView is populated with values from the appSettings section of the Config file.  The only thing we have left to do is persist any changes back into the app.config file.  That is accomplished with the following code:

    private void PersistAppSettings()        
    {
            Hashtable htAppConfigValuesInGrid = new Hashtable();
            // Load the existing Grid values into a hashtable
            htAppConfigValuesInGrid.Clear();
            foreach (DataGridViewRow row in dgvAppConfigSettings.Rows)
            {
                if (row.Cells["Key"].Value != null)
                {
                    htAppConfigValuesInGrid.Add(row.Cells["Key"].Value, row.Cells["Value"].Value);
                }
            }
            // Open App.Config of executable and get AppSettingsSection
            Configuration config
                = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
            AppSettingsSection appSettings = (AppSettingsSection)config.GetSection("appSettings");
            appSettings.Settings.Clear();
            // Go through the hashtable and see if the value exists in the config file
            // if so update it
            // if not, add it
            foreach (DictionaryEntry entry in htAppConfigValuesInGrid)
            {
                string key = entry.Key.ToString();
                KeyValueConfigurationElement kvcElement = appSettings.Settings[key];
                // exists in the grid but not in the appSettings, add the missing value
                if (kvcElement == null)
                {
                    appSettings.Settings.Add(key, (string)htAppConfigValuesInGrid[key]);
                }
                else
                {
                    // only update the value if it has changed
                    if (kvcElement.Value != (string)htAppConfigValuesInGrid[key])
                    {
                        appSettings.Settings[key].Value = (string)htAppConfigValuesInGrid[key];
                    }
                }
            }
             // Go through the settings and remove any that are not in the grid hashtable
            foreach (KeyValueConfigurationElement element in config.AppSettings.Settings)
            {
                string keyVal = (string)htAppConfigValuesInGrid[element.Key];
                if (keyVal == null)
                {
                    appSettings.Settings.Remove(element.Key);
                }
            }
            // Save the configuration file.
            //config.Save(ConfigurationSaveMode.Modified, true);
            config.Save();
            // Force a reload of a changed section.
            ConfigurationManager.RefreshSection("appSettings");
        }
    }

If we add a new setting and modify an existing one, the UI will show this:

Modified app.config 

And the executables app.config (SyrinxCodeGenerator.exe.config) will reflect the addition and update like this:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <appSettings>
    <clear />
    <add key="DeveloperName" value="John P. Frampton" />
    <add key="StoredProcedureFilePath" value="C:\Syrinx\Syrinx.DB\StoredProcedures\" />
    <add key="ApplicationObjectFilePath" value="C:\Syrinx\Syrinx.Consumer\ApplicationObject\" />
    <add key="InterfaceObjectFilePath" value="C:\Syrinx\Syrinx.Consumer\InterfaceObject\" />
    <add key="TableDefinitionFilePath _I_HAVE_CHANGED" value="C:\Syrinx\Syrinx.DB\Tables\" />
    <add key="NEW_APP_SETTING" value="THIS_IS_NEW" />
    <add key="DataAccessFilePath" value="C:\Syrinx\Syrinx.Consumer\DataAccess\" />
    <add key="CodeGeneratorDefinitionFilePath" value="C:\Syrinx\Syrinx.Architecture\DefinitionFiles\" />
  </appSettings>
  <connectionStrings>
    <add
      name="FakeConnectionString"
      connectionString="NotReally"/>
  </connectionStrings>
</configuration>

If we remove the new field from the UI we see that the app.config file reflects it like this:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <appSettings>
    <clear />
    <add key="TableDefinitionFilePath _I_HAVE_CHANGED" value="C:\Syrinx\Syrinx.DB\Tables\" />
    <add key="DataAccessFilePath" value="C:\Syrinx\Syrinx.Consumer\DataAccess\" />
    <add key="ApplicationObjectFilePath" value="C:\Syrinx\Syrinx.Consumer\ApplicationObject\" />
    <add key="DeveloperName" value="John P. Frampton" />
    <add key="InterfaceObjectFilePath" value="C:\Syrinx\Syrinx.Consumer\InterfaceObject\" />
    <add key="CodeGeneratorDefinitionFilePath" value="C:\Syrinx\Syrinx.Architecture\DefinitionFiles\" />
    <add key="StoredProcedureFilePath" value="C:\Syrinx\Syrinx.DB\StoredProcedures\" />
  </appSettings>
  <connectionStrings>
    <add
      name="FakeConnectionString"
      connectionString="NotReally"/>
  </connectionStrings>
</configuration>

That wraps it up for this installation, next we’ll look at saving and loading definition files to and from XML.

 

Comments

Recent URLs tagged Keyval - Urlrecorder said:

Pingback from  Recent URLs tagged Keyval - Urlrecorder

# April 29, 2009 10:31 PM

Mercury Cougar S, Walmart Cougar said:

Pingback from  Mercury Cougar S, Walmart Cougar

# May 21, 2010 8:43 PM

Freightliner New Truck Parts, Freightliner Fitness said:

Pingback from  Freightliner New Truck Parts, Freightliner Fitness

# May 21, 2010 9:11 PM

Headlight Oem Suzuki Verona Piaa, Verona American Racing Wheels And Tires said:

Pingback from  Headlight Oem Suzuki Verona Piaa, Verona American Racing Wheels And Tires

# May 22, 2010 9:59 AM

Luv Dash Replacement Headlight Assembly Oxygen Sensor, Bulb Chevrolet Luv Pickup Light said:

Pingback from  Luv Dash Replacement Headlight Assembly Oxygen Sensor, Bulb Chevrolet Luv Pickup Light

# May 22, 2010 10:21 AM

Mazda B4000 Parts, B2300 Discount Auto Parts B2500 Mazda B4000 - 386.jeepsunlimted.com said:

Pingback from  Mazda B4000 Parts, B2300 Discount Auto Parts B2500 Mazda B4000 - 386.jeepsunlimted.com

# May 24, 2010 2:48 PM

Freightliner Episodes Out, Buy Freightliner Store - 482.myipgirl.com said:

Pingback from  Freightliner Episodes Out, Buy Freightliner Store - 482.myipgirl.com

# May 25, 2010 12:48 AM

2000 - 1991 @ Mercedes Benz E550 Aftermarket Ml55 Slk55 Amg, Fujifilm Finepix E550 Preis - 463.binggreen.com said:

Pingback from  2000 - 1991 @ Mercedes Benz E550 Aftermarket Ml55 Slk55 Amg, Fujifilm Finepix E550 Preis - 463.binggreen.com

# May 27, 2010 11:36 AM

1990 - 2005 @ B3500 Model Used Dodge Vehicle, B3500 Replacement Price 2002 Dodge Ram 1500 - 110.tijuanareader.com said:

Pingback from  1990 - 2005 @ B3500 Model Used Dodge Vehicle, B3500 Replacement Price 2002 Dodge Ram 1500 - 110.tijuanareader.com

# May 31, 2010 2:54 AM