SSW .NET Toolkit > User Guide

DOT NET Tool kit - Develop Applications More Efficiently with the SSW .NET Toolkit

Managing the storage of application configuration settings

Key Features and benefits of SSW Configuration

How do you get a setting from a configuration file?  What do you do when you want to get a setting from a registry, a database or memory?  Everyone faces these problems, and most people come up with their own solution.  We used to have a few different standards, but when Microsoft released the Configuration Application Blocks, we have found that working to extend it and use it in all our projects saves us a lot of time! Use a a local configuration file for machine and/or user specific settings (such as a connection string), and use a database for any shared values such as Tax Rates.

Now, getting a setting is a breeze, the code is simple, and no one has to worry about how it works underneath.  Here are the procedures for setting your project up to use the Configuration Management Application Block (CMAB).

  1. Reference the Configuration block dll from the package.
  2. For your convenience, an example App.Config and Settings.Config files is available here: Configs.zip
    If you use these as a starting point, read the comments in the App.Config file and remove any sections that you won't need (like database, memory section handlers)

  3. Modify your App.Config, you'll need to copy & paste the sections that you want into your current App.Config file.

    App.Config is a special file that Visual Studio.NET uses, at compilation, it is converted to <AppName>.Config and resides in the same folder as the application.

    Your App.Config needs the following lines/sections as a minimum:

    <?xml version="1.0" encoding="utf-8" ?>
    <configuration>
      <configSections>
        <section 
        name="applicationConfigurationManagement" 
        type="Microsoft.ApplicationBlocks.ConfigurationManagement.
        ConfigurationManagerSectionHandler,
        SSW.Framework.Configuration"/>
    		
        <section 
        name="FileSettings" 
        type="SSW.Framework.Configuration.DictionarySectionHandlerWriter, 
        SSW.Framework.Configuration"/>
      </configSections>
    
      <applicationConfigurationManagement 
    defaultSection="FileSettings"> <configSection name="FileSettings"> <configCache enabled="true" refresh="1 * * * *" /> <configProvider assembly="SSW.Framework.Configuration" type="Microsoft.ApplicationBlocks.ConfigurationManagement.Storage.XmlFileStorage" signed="false" refreshOnChange="false" encrypted="false" path="Settings.config" /> </configSection> </applicationConfigurationManagement>
    </configuration>
    Figure: App.Config code
    <?xml version="1.0" encoding="utf-8" ?>
    <configuration>
          <configSections>
                <section 
                name="applicationConfigurationManagement" 
                type="Microsoft.ApplicationBlocks.ConfigurationManagement.ConfigurationManagerSectionHandler,
                SSW.Framework.Configuration" />
                <section name="FileSettings" type="SSW.Framework.Configuration.DictionarySectionHandlerWriter, 
                SSW.Framework.Configuration" />
          </configSections>
          <applicationConfigurationManagement  defaultSection="FileSettings">
        	   <configSection name="FileSettings">
                      <configCache enabled="true" refresh="1 * * * *" />
                      <configProvider 
                            assembly="SSW.Framework.Configuration" 
                            type="Microsoft.ApplicationBlocks.ConfigurationManagement.Storage.XmlFileStorage"
                            signed="false" 
                            refreshOnChange="true" 
                            encrypted="false" 
                            path="{base.dir}Settings.config" />
                </configSection>
          </applicationConfigurationManagement>
      <system.web>
    
    Figure: Note the difference in the path when using with the Web.config in a Web Application.
  4. For file settings, the settings is written to "Settings.config" in the application directory. The format is like this:
    <?xml version="1.0" encoding="utf-8" ?>
        <configuration>
         <FileSettings>
           <appSettings>
             <add key="My Setting" value="My Value"/>
             <add key="My Setting 2" value="2"/>
           </appSettings>
         </FileSettings>
        </configuration>
        
    Figure: Settings.Config format

    You'll need to have a copy in your application directory for it to work, the application block can automatically add new key/values, but it will not create the new file if the file doesn't already exist. You can use the one from the zip file available in step 2 as a starting point.

  5. Code in your application is very simple, once you have referenced the files, use this code to read and write to the settings.
    string value = ConfigurationManager.Items["My Setting"];
    ConfigurationManager.Items["My Setting"] = value;
    
    int i = Convert.ToInt32(ConfigurationManager.Items["My Setting 2"]);
    ConfigurationManager.Items["My Setting 2"] = i;
    Figure: Code to read and write to your settings
  6. You should always encapsulate and use the settings in a strong-bound way, so create a class Configuration and do the following:
    public sealed class Configuration
    {
       // Prevent the class from being constructed
       private Configuration() { }
    
       public static string MySetting
       {
          get
          {
             // if the value doesn't exist (e.g. XML node doesn't exist), 
    Configuration will // return (null) instead of empty string ("") // so we need a few more lines of code to handle this situation. object val = ConfigurationManager.Items["My Setting"]; if ( val == null ) return string.Empty; return val.ToString(); } set { ConfigurationManager.Items["My Setting"] = value; } } public static int MySetting2 { get { //Use a try/catch ParseException if the setting isn't a valid integer. //This also catches if the value returned is null try { return Convert.ToInt32(ConfigurationManager.Items["My Setting 2"]); } catch { return 0; } } set { ConfigurationManager.Items["My Setting 2"] = value; }} } } //Then, in your code, write //Configuration.MySetting = "hi"; //int i = Configuration.MySetting2;
    Figure: Use your settings in a Strong-Bound way

Do you have a resetdefault() function in your configuration management application block?

This ensures that a new user on a different computer will always have a working config file. This solves the rule Do you have a ResetDefault() function to handle messed up user settings?

  1. First we need a proper setup of our App.config file, as per the sample above we need to add one more block in our App.config file
    			<?xml version="1.0" encoding="utf-8" ?>
    			<configuration>
    			  <configSections>
    			    <section 
    			    name="applicationConfigurationManagement" 
    			    type="Microsoft.ApplicationBlocks.ConfigurationManagement.
    			    ConfigurationManagerSectionHandler,
    			    SSW.Framework.Configuration"/>
    					
    			    <section 
    			    name="DefaultSettings" 
    			    type="SSW.Framework.Configuration.DictionarySectionHandlerWriter, 
    			    SSW.Framework.Configuration"/>
    			  </configSections>
    			
    			  <applicationConfigurationManagement defaultSection="
    DefaultSettings"> <configSection name="FileSettings"> <configCache enabled="true" refresh="1 * * * *" /> <configProvider assembly="SSW.Framework.Configuration" type="Microsoft.ApplicationBlocks.ConfigurationManagement.Storage.XmlFileStorage" signed="false" refreshOnChange="false" encrypted="false" path="default.config" /> </configSection> </applicationConfigurationManagement>
    </configuration>
    Figure: Code to add in App.Config file.

    Include the following code in ConfigurationManager.cs this will copy all the settings in default.config to settings.config file.

    				#region ResetDefault
    				/// 
    				/// This function will reset your configuration settings to default.
    				/// 
    				public static void ResetDefaults() 
    				{
    					Hashtable ht = ReadDefaults();
    					Hashtable htSection = ConfigurationManager.Read();
    					if (ht == null)
    					{
    						return;
    					}
    				
    					if (htSection == null)
    					{
    						htSection = new Hashtable();
    					}
    					Hashtable dumpHt = ht.Clone() as Hashtable;
    					foreach (Object obj in dumpHt.Keys) 
    					{
    						htSection[ obj ] = ht [ obj ] ;
    					}
    					ConfigurationManager.Write( htSection );
    				}
    				
    				private static Hashtable ReadDefaults()
    				{
    					// Check the static initialization result
    					if( !_isInitialized ) 
    					{
    						throw _initException;
    					}
    					
    					object section = Read( DEFAULTSECTION_NAME );
    					if( section == null ) 
    					{
    						return null;
    					}
    					if( !( section is Hashtable ) ) 
    					{
    					throw new ConfigurationException( 
    						Resource.ResourceManager
    [ "RES_ExceptionConfigurationManagerDefaultSectionIsNotHashtable" ] ); } return (Hashtable)section; } #endregion
    Figure: Code to implement in ConfigurationManager.cs
  2. Call this function in our application.
    			if(ConfigurationManager.Items["ComputerName"] != Environment.MachineName)
    			{
    				ConfigurationManager.ResetDefault();
    				ConfigurationManager.Items["ComputerName"] = Environment.MachineName;
    			}
    			
    Figure: Sample Code to implement resetDefault in our applications

By default we will have an empty setting called "ComputerName" in the settings file. Developers always accidentally package their development setting files in the build. If the machine name is different we should reset the default with the above function.