Nested Configuration Sections

Discussion in 'Software' started by someguy85, May 18, 2013.

  1. someguy85

    someguy85 Private E-2

    I'm currently writing a console app that will allow a user to pass a config section name and a command type (ex: start, stop, pause, etc.) to manipulate WCF services. This is my first time writing an app config and I'm having a little trouble getting it to work while also having a readable and sustainable app config that's not going to grow into an ugly beast. Any help in pointing me in the right direction would be greatly appreciated.

    Things to note:
    1) For any given configuration section, there can be any number of "serviceInstances".

    2) I would like to keep the individual serverNames/serviceNames paired to help prevent user error.

    Custom Configuration Class
    Code:
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Configuration;
    using log4net;
    using ServiceManipulator;
    using System.Collections.Specialized;
    
    namespace ServiceManipulator
    {
        public class ManipulatorConfiguration //: ConfigurationSection
        {
            private static readonly ILog Log = LogManager.GetLogger(typeof(ManipulatorConfiguration));
            public static readonly string configGroup = "CustomConfigs";
            public string configSection = string.Empty;
            public string commandType = string.Empty;
            public CustomConfiguration configValues;
    
    
            /// <summary>
            /// Gets the configuration section settings.
            /// </summary>
            /// <param name="args"></param>The config section and command type</value>
            /// <returns>Configuration of ManipulatorConfiguration type</returns>
            public static ManipulatorConfiguration GetConfiguration(string[] args)
            {
                ManipulatorConfiguration config = new ManipulatorConfiguration();
                Log.Info(string.Format("Retrieving '{0}' configuration section...", config.configSection));
    
                config.ParseCommandLine(args);
                config.configValues = CustomConfiguration.GetCustomConfigSettings(config.configSection);
    
                return config;
            }
    
            /// <summary>
            /// Parses and validates key/value pairs from arguments
            /// </summary>
            /// <param name="args">The config section and command type</param>
            private void ParseCommandLine(string[] args)
            {
                string key = string.Empty;
                string argValue = string.Empty;
                HashSet<string> validCommands = new HashSet<string>();
                validCommands.Add("START");
                validCommands.Add("STOP");
                validCommands.Add("CONTINUE");
                validCommands.Add("PAUSE");
    
                try
                {
                    if (args != null && args.Length == 2)
                    {
                        foreach (string arg in args)
                        {
                            key = arg.ToUpper().Trim();
                            argValue = arg.Trim().Substring(arg.Trim().IndexOf(':') + 1).Trim();
    
                            if (key.StartsWith("CONFIG:") && !string.IsNullOrEmpty(argValue))
                                this.configSection = argValue;
                            else if (key.StartsWith("COMMAND:") && !string.IsNullOrEmpty(argValue) && validCommands.Contains(argValue))
                                this.commandType = argValue;
                            else
                            {
                                Log.Error("One or more user defined arguments are invalid. Exiting console application...");
                                Environment.Exit((int)ManipulatorExitCode.InvalidArguments);
                            }
                        }
                    }
                    else
                    {
                        Log.Error("Config section and command type are required arguments. Exiting console application...");
                        Environment.Exit((int)ManipulatorExitCode.InvalidArguments);
                    }
                }
                catch (Exception ex)
                {
                    Log.Error("An error occurred while parsing the command line.", ex);
                    Environment.Exit((int)ManipulatorExitCode.ConfigLoadError);
                }
            }
        }
    
        public class CustomConfiguration
        {
            private static readonly ILog Log = LogManager.GetLogger(typeof(ManipulatorConfiguration));
            public static readonly string subSection = "ServiceInstances";
    
            public static CustomConfiguration GetCustomConfigSettings(string customSectionName)
            {
                CustomConfiguration config = new CustomConfiguration();
                try
                {
                    string tempString = @"CustomConfigs/" + customSectionName + '/' + subSection;
                    //NameValueCollection manipulatorConfigs = (NameValueCollection)ConfigurationManager.GetSection(tempString);
                    NameValueConfigurationCollection manipulatorConfigs = (NameValueConfigurationCollection)ConfigurationManager.GetSection(tempString);
                }
                catch (Exception ex)
                {
                    Log.Error(ex.ToString());
                    Environment.Exit((int)ManipulatorExitCode.ConfigLoadError);
                }
    
                return config;
            }
        }
    }
    
    Here's the app config setup
    Code:
    <?xml version="1.0"?>
    <configuration>
    	<configSections>		
    		<section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler, log4net"/>
    		<section name="RetrySettings" type="System.Configuration.NameValueSectionHandler"/>
    		<section name="ServiceInstances" type="System.Configuration.NameValueSectionHandler"/>
    		<sectionGroup name="CustomConfigs">
    			<section name="MySection" type="System.Configuration.NameValueSectionHandler"/>
    			<section name="AnotherSection" type="System.Configuration.NameValueSectionHandler"/>
    		</sectionGroup>
    	</configSections>
    
    	<!-- Default Retry Settings. -->
    	<RetrySettings>
    		<add key="Loops" value="3"/>
    		<add key="LoopDelay" value="10"/>
    		<add key="EmailOnFailure" value="true"/>
    		<add key="EmailOnSuccess" value="false"/>
    		<add key="EmailTo" value=""/>
    		<add key="EmailFrom" value=""/>
    		<add key="EmailSmtpHost" value=""/>
    	</RetrySettings>
    	
    	<!-- Custom Configuration Settings -->
    	<CustomConfigs>
    		<MySection>
    			<ServiceInstances>
    				<add key="serverName" value="ServiceNameHere"/>
                    <add key="ServerName2" value="ServiceName"/>
                    <add key="ServerName3" value="ServiceName"/>
    			</ServiceInstances>
    		</MySection>
    		<AnotherSection>
    			<ServiceInstances>
    				<add key="ServerName" value="ServiceName"/>
    				<add key="ServerName4" value="ServiceName"/>
    				<add key="ServerName5" value="ServiceName"/>
    			</ServiceInstances>
    			<!-- Example of overriding the default retry settings.
    			<RetrySettings>
    				<add key="EmailOnFailure" value="false"/>
    			</RetrySettings>
    			-->
    		</AnotherSection>
    	</CustomConfigs>
    	
    	<!-- Logging Configuration -->
    	<log4net debug="false">
    		<appender name="LogFileAppender" type="log4net.Appender.RollingFileAppender">
    			<file value="ServiceManipulator.log"/>
    			<rollingStyle value="Date"/>
    			<maxSizeRollBackups value="10"/>
    			<staticLogFileName value="true"/>
    			<layout type="log4net.Layout.PatternLayout">
    				<conversionPattern value="%date{yyyy/MM/dd HH:mm:ss} %-5level %logger [%thread] %method &lt;%mdc{auth}&gt; - %message%newline"/>
    			</layout>
    		</appender>
    		<appender name="ConsoleAppender" type="log4net.Appender.ColoredConsoleAppender">
    			<layout type="log4net.Layout.PatternLayout">
    				<conversionPattern value="%-5leve - %message%newline"/>
    			</layout>
    			<mapping>
    				<level value="ERROR"/>
    				<foreColor value="White"/>
    				<backColor value="Red, HighIntensity"/>
    			</mapping>
    			<mapping>
    				<level value="DEBUG"/>
    				<foreColor value="White"/>
    				<backColor value="Green"/>
    			</mapping>
    			<mapping>
    				<level value="INFO"/>
    				<foreColor value="White"/>
    				<backColor value="Blue"/>
    			</mapping>
    			<mapping>
    				<level value="WARN"/>
    				<foreColor value="Blue"/>
    				<backColor value="Yellow, HighIntensity"/>
    			</mapping>
    		</appender>
    		<appender name="EventLogAppender" type="log4net.Appender.EventLogAppender">
    			<threshold value="ERROR"/>
    			<logName value="GEDI"/>
    			<applicationName value="ServiceManipulator"/>
    			<layout type="log4net.Layout.PatternLayout">
    				<conversionPattern value="%date{yyyy/MM/dd HH:mm:ss} [%thread] %-5level %logger %message%newline"/>
    			</layout>
    			<mapping>
    				<level value="FATAL"/>
    				<eventLogEntryType value="Error"/>
    			</mapping>
    			<mapping>
    				<level value="ERROR"/>
    				<eventLogEntryType value="Error"/>
    			</mapping>
    			<mapping>
    				<level value="WARN"/>
    				<eventLogEntryType value="Warning"/>
    			</mapping>
    			<mapping>
    				<level value="INFO"/>
    				<eventLogEntryType value="Information"/>
    			</mapping>
    			<mapping>
    				<level value="DEBUG"/>
    				<eventLogEntryType value="Information"/>
    			</mapping>
    		</appender>
    		<!-- Setup the root category to log everything to the rolling file appender-->
    		<!-- SET TO "INFO" for deployment -->
    		<root>
    			<priority value="DEBUG"/>
    			<appender-ref ref="EventLogAppender"/>
    			<!--<appender-ref ref="ConsoleAppender" />-->
    			<appender-ref ref="LogFileAppender"/>
    		</root>
    	</log4net>
    <startup><supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0"/></startup></configuration>
    
     

MajorGeeks.Com Menu

Downloads All In One Tweaks \ Android \ Anti-Malware \ Anti-Virus \ Appearance \ Backup \ Browsers \ CD\DVD\Blu-Ray \ Covert Ops \ Drive Utilities \ Drivers \ Graphics \ Internet Tools \ Multimedia \ Networking \ Office Tools \ PC Games \ System Tools \ Mac/Apple/Ipad Downloads

Other News: Top Downloads \ News (Tech) \ Off Base (Other Websites News) \ Way Off Base (Offbeat Stories and Pics)

Social: Facebook \ YouTube \ Twitter \ Tumblr \ Pintrest \ RSS Feeds