} // InitializeInstance /// <summary> /// Enumeate missing configuration values, if any. /// </summary> /// <returns> /// This method returns a message suitable for display on a console or a /// Windows message box. The returned message summarises the state of /// affairs, even when all defined values are represented in the /// configuration file. /// </returns> public string EnumerateMissingConfigurationValues ( ) { MissingConfigSettings = MissingConfigSettings ?? UnconfiguredDLLSettings.GetTheSingleInstance ( ); List<UnconfiguredDLLSettings.UnconfiguredSetting> missing = MissingConfigSettings.GetMissingPropsForFile ( System.IO.Path.GetFileName ( _strAssemblyLocation ) ); if ( missing.Count > ListInfo.LIST_IS_EMPTY ) { System.Text.StringBuilder sbMessages = new System.Text.StringBuilder ( MagicNumbers.CAPACITY_04KB ); // ------------------------------------------------------------ // Start with a heading. // ------------------------------------------------------------ sbMessages.AppendFormat ( Properties.Resources.MSG_SOME_CONFIG_SETTINGS_OMITTED , MissingConfigSettings.Count , _DllConfigSettings.Count , AssemblyLocation , Environment.NewLine ); // ------------------------------------------------------------ // List each item in turn. // ------------------------------------------------------------ for ( int intJ = ArrayInfo.ARRAY_FIRST_ELEMENT ; intJ < MissingConfigSettings.Count ; intJ++ ) { sbMessages.AppendFormat ( Properties.Resources.MSG_ACCEPTED_DEFAULT_VALUE , // Format Control String: {0} of {1}: {2} = {3}{4} ArrayInfo.OrdinalFromIndex ( intJ ) , // Format Item 0: {0} of MissingConfigSettings.Count , // Format Item 1: of {1} missing [ intJ ].PropName , // Format Item 2: : {2} missing [ intJ ].PropValue , // Format Item 3: = {3} Environment.NewLine ); // Format Item 4: newline } // for ( int intJ = ArrayInfo.ARRAY_FIRST_ELEMENT ; intJ < MissingConfigSettings.Count ; intJ++ ) // ------------------------------------------------------------ // End with a footing. // ------------------------------------------------------------ sbMessages.AppendFormat ( Properties.Resources.MSG_ACCEPTED_LIST_END , Environment.NewLine ); return sbMessages.ToString ( ); } // TRUE (One or more settings is missing from the configuration file.) block, if ( base.MissingConfigSettings.Count > ListInfo.LIST_IS_EMPTY ) else { return string.Format ( Properties.Resources.MSG_ALL_CONFIG_SETTINGS_COVERED , _DllConfigSettings.Count , AssemblyLocation ); } // FALSE (All configuration settings are covered by the configuration file.) block, if ( base.MissingConfigSettings.Count > ListInfo.LIST_IS_EMPTY ) } // public string EnumerateMissingConfigurationValues
} // public string GetDLLSetting /// <summary> /// Set the like named properties from the linked configuration file. /// </summary> /// <param name="pderivedType"> /// When the derived class constructor calls this method, it must pass in a /// reference to its own Type property. /// </param> /// <returns> /// The return value is the count of properties that were set. /// </returns> /// <remarks> /// This can almost certainly be simplified by enumerating the settings, /// but either way risks a NOT FOUND exception. /// /// This method uses some fairly tricky Reflection gymnastics to map the /// key names in a configuration file to property names on an object. /// </remarks> protected PropertySourceCounts SetPropertiesFromDLLConfiguration ( Type pderivedType ) { const BindingFlags BASELINE_BINDING_FLAGS = BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public; PropertySourceCounts rutpCounts = new PropertySourceCounts ( ); rutpCounts.Defaulted = MagicNumbers.ZERO; rutpCounts.SpecifiedInConfiguration = MagicNumbers.ZERO; string [ ] astrDefaultErrorMessageColors = DLLSettings.AllKeys; for ( int intJ = ArrayInfo.ARRAY_FIRST_ELEMENT ; intJ < astrDefaultErrorMessageColors.Length ; intJ++ ) { string strPropertyName = null; // This must be visible to the catch block. try { strPropertyName = astrDefaultErrorMessageColors [ intJ ]; string strConfigValueString = DLLSettings [ strPropertyName ].Value; TraceLogger.WriteWithBothTimesLabeledLocalFirst ( string.Format ( @"At iteration {0} in {1}: {2} = {3}" , // Format control string new object [ ] // Array of values to substitute for tokens in format control string { ArrayInfo.OrdinalFromIndex ( intJ ) , // Format Item 0: At iteration {0} MethodBase.GetCurrentMethod ( ).Name , // Format Item 1: in {1} strPropertyName , // Format Item 2: : {2} strConfigValueString // Format Item 3: = {3} } ) ); PropertyInfo piThisProperty = this.GetType ( ).GetProperty ( strPropertyName , // string name = The string containing the name of the property to get BASELINE_BINDING_FLAGS ); // bindingAttr BindingFlags = A bitmask comprised of one or more BindingFlags that specify how the search is conducted if ( piThisProperty != null ) { piThisProperty.SetValue ( this , // Object obj = Object to which to apply setting FromString ( piThisProperty , strConfigValueString ) , // Object value = Value to assign to the property to which piThisProperty refers BASELINE_BINDING_FLAGS | BindingFlags.SetProperty , // invokeAttr invokeAtt = A bitwise combination of the following enumeration members that specify the invocation attribute: InvokeMethod, reateInstance, Static, GetField, SetField, GetProperty, or SetProperty. You must specify a suitable invocation attribute. null , // Binder binder = An object that enables the binding, coercion of argument types, invocation of members, and retrieval of MemberInfo objects through reflection. If binder is null, the default binder is used. null , // Object[] index = Optional index values for indexed properties. This value should be null for non-indexed properties. null ); // CultureInfo culture = The culture for which the resource is to be localized. If the resource is not localized for this culture, the Parent property will be called successively in search of a match. If this value is null, the culture-specific information is obtained from the CurrentUICulture property. rutpCounts.SpecifiedInConfiguration++; // Count properties successfully set; the final value is returned as the function value. } // TRUE (The configuration file has a value for this property.) block, if ( piThisProperty != null ) else { MissingConfigSettings = MissingConfigSettings ?? UnconfiguredDLLSettings.GetTheSingleInstance ( ); MissingConfigSettings.Add ( Path.GetFileName ( _strAssemblyLocation ) , strPropertyName , // Format Item 0: property {1} default value strConfigValueString ); // Format Item 1: default value of {2} accepted rutpCounts.Defaulted++; // Count properties that retained their hard coded default values. } // FALSE (A value for this property is absent from the configuration file.) block, if ( piThisProperty != null ) } catch ( Exception exAllKinds ) { // Since the catch block is within the body of the For loop, processing advances to the next item. TraceLogger.WriteWithBothTimesLabeledLocalFirst ( string.Format ( @"{0}.{1} = {2}" , nameof ( Environment ) , nameof ( Environment.StackTrace ) , Environment.StackTrace ) ); if ( RecoveredConfigurationExceptions == null ) { // Create as and when needed. RecoveredConfigurationExceptions = new System.Collections.Generic.List<RecoveredException> ( ); } // if ( RecoveredConfigurationExceptions == null ) RecoveredConfigurationExceptions.Add ( new RecoveredException ( string.Format ( Properties.Resources.ERRMSG_EXCEPTION_NOT_THROWN , SaveErrorReport ( this.GetType ( ) , strPropertyName , exAllKinds ).Message ) , exAllKinds.Source , exAllKinds.StackTrace , exAllKinds.TargetSite.Name ) ); Exception exWrapped = RecoveredConfigurationExceptions [ ArrayInfo.IndexFromOrdinal ( RecoveredConfigurationExceptions.Count ) ]; TraceLogger.WriteWithBothTimesLabeledLocalFirst ( string.Format ( Properties.Resources.TRACEMSG_EXCEPTION_NOT_THROWN_1 , exWrapped.Message ) ); TraceLogger.WriteWithBothTimesLabeledLocalFirst ( string.Format ( Properties.Resources.TRACEMSG_EXCEPTION_NOT_THROWN_2 , exWrapped.Source ?? Common.Properties.Resources.MSG_OBJECT_REFERENCE_IS_NULL ) ); TraceLogger.WriteWithBothTimesLabeledLocalFirst ( string.Format ( Properties.Resources.TRACEMSG_EXCEPTION_NOT_THROWN_3 , exWrapped.TargetSite != null ? exWrapped.TargetSite.Name : Common.Properties.Resources.MSG_OBJECT_REFERENCE_IS_NULL ) ); TraceLogger.WriteWithBothTimesLabeledLocalFirst ( string.Format ( Properties.Resources.TRACEMSG_EXCEPTION_NOT_THROWN_4 , exWrapped.StackTrace ?? Common.Properties.Resources.MSG_OBJECT_REFERENCE_IS_NULL ) ); // -------------------------------------------------------- // Since SaveErrorReport appends the inner exception, this // test is technically redundant, but I chose to leave it, // as a reminder that new exceptions are not necessarily // so decordated. Hence, with the test, this code is a bit // more portable. // -------------------------------------------------------- if ( exWrapped.InnerException != null ) { TraceLogger.WriteWithBothTimesLabeledLocalFirst ( string.Format ( Properties.Resources.TRACEMSG_EXCEPTION_NOT_THROWN_5 , exWrapped.InnerException.Message ?? Common.Properties.Resources.MSG_OBJECT_REFERENCE_IS_NULL ) ); TraceLogger.WriteWithBothTimesLabeledLocalFirst ( string.Format ( Properties.Resources.TRACEMSG_EXCEPTION_NOT_THROWN_6 , exWrapped.InnerException.Source ?? Common.Properties.Resources.MSG_OBJECT_REFERENCE_IS_NULL ) ); TraceLogger.WriteWithBothTimesLabeledLocalFirst ( string.Format ( Properties.Resources.TRACEMSG_EXCEPTION_NOT_THROWN_7 , exWrapped.InnerException.TargetSite.Name ?? Common.Properties.Resources.MSG_OBJECT_REFERENCE_IS_NULL ) ); TraceLogger.WriteWithBothTimesLabeledLocalFirst ( string.Format ( Properties.Resources.TRACEMSG_EXCEPTION_NOT_THROWN_8 , exWrapped.InnerException.StackTrace ?? Common.Properties.Resources.MSG_OBJECT_REFERENCE_IS_NULL ) ); } // TRUE (anticipated outcome) block, if ( exWrapped.InnerException != null ) else { TraceLogger.WriteWithBothTimesLabeledLocalFirst ( Properties.Resources.TRACEMSG_EXCEPTION_NOT_THROWN_9 ); } // FALSE (unanticipated outcome) block, if ( exWrapped.InnerException != null ) } // catch ( Exception exAllKinds ) } // for ( int intJ = ArrayInfo.ARRAY_FIRST_ELEMENT ; intJ < astrDefaultErrorMessageColors.Length ; intJ++ ) return rutpCounts; } // SetPropertiesFromDLLConfiguration