Create a gist now

Instantly share code, notes, and snippets.

What would you like to do?
Settings Refresh Extension
using System;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Configuration;
using System.Diagnostics;
namespace Spynical.Settings
{
/// <summary>
/// Helper extension class for refreshing Settings from their associated .config file.
/// </summary>
/// <remarks>
/// This method allows DLLs (i.e. Plugins) to manage their own settings in .dll.config
/// files and have those settings override the attributed default settings by placing
/// the modified configuration file in the directory and calling the Reload() method.
/// Eg: Settings.Default.Reload();
/// This also allows executables to reload their modified configuration files at runtime.
/// </remarks>
public static class SettingsExtensions
{
private static Action<string, TraceLevel> _resultListener;
/// <summary>
/// Initializes a results listener so that applications can listen in on how the
/// settings refresh is going and log or record the operation.
/// </summary>
/// <param name="resultListener">Listener action delegate used to call back with status messages and/or errors.</param>
public static void InitializeListener( Action<string, TraceLevel> resultListener )
{
_resultListener = resultListener;
}
/// <summary>
/// Extension method on Settings to refresh their values from a configuration file
/// if present.
/// </summary>
/// <param name="settings">Settings object being reloaded.</param>
/// <remarks>
/// To refresh settings from file, place the .dll.config or .exe.config file in the
/// same folder as the dll/exe with settings to be refreshed.
/// Note that if a dll has a .config file and settings within its parent .exe.config file
/// settings in the .dll.config will override any settings in the .exe.config. This
/// method will not reload dll settings from parent .exe.config files.
/// </remarks>
public static void Refresh( this ApplicationSettingsBase settings )
{
var configName = string.Format( "{0}.config", settings.GetType().Assembly.Location );
fireResultListener( string.Format( "Refreshing settings from {0}({1})", Path.GetFileName( configName ), configName ) );
var configSectionName = string.Format( "{0}.Settings", settings.GetType().Namespace );
if (!File.Exists( configName ))
{
fireResultListener( "No configuration file found. Nothing to do." );
return;
}
try
{
// Look for a valid .config file and open if available.
var configuration = ConfigurationManager.OpenMappedExeConfiguration( new ExeConfigurationFileMap { ExeConfigFilename = configName }, ConfigurationUserLevel.None );
if (configuration == null || !configuration.HasFile)
{
fireResultListener( "Configuration file found, but could not be parsed.", TraceLevel.Warning );
return;
}
var applicationSettingsSection = configuration.GetSectionGroup( "applicationSettings" );
if (applicationSettingsSection == null)
{
fireResultListener( "Application settings section not found in configuration.", TraceLevel.Warning );
return;
}
// DefaultSettingValueAttribute denotes setting properies we'll be interest in.
var properties = settings.GetType().GetProperties( BindingFlags.Public | BindingFlags.Instance )
.Where( p => p.GetCustomAttributes( typeof( DefaultSettingValueAttribute ), false ).Any() );
foreach (var propertyName in properties.Select( p => p.Name ))
{
try
{
var value = ((ClientSettingsSection) applicationSettingsSection.Sections[configSectionName]).Settings.Get( propertyName );
if (value != null)
{
fireResultListener( string.Format( "Updating setting from: \"{0}\" to: \"{1}\".", settings[propertyName], value.Value.ValueXml.InnerText ) );
if (settings[propertyName] is Guid)
settings[propertyName] = Guid.Parse( value.Value.ValueXml.InnerText );
else if (settings[propertyName] is TimeSpan)
settings[propertyName] = TimeSpan.Parse( value.Value.ValueXml.InnerText );
else if (settings[propertyName] is System.Drawing.Color)
settings[propertyName] = System.Drawing.Color.FromName( value.Value.ValueXml.InnerText );
else
settings[propertyName] = Convert.ChangeType( value.Value.ValueXml.InnerText, settings[propertyName].GetType() );
}
}
catch (Exception ex)
{
fireResultListener( ex );
}
}
}
catch (Exception ex)
{
fireResultListener( ex );
}
}
/// <summary>
/// Attempts to raise the result listener with the provided message and trace level.
/// </summary>
/// <param name="message">Message to notify the listener about.</param>
/// <param name="level">A trace level for the type of information. (defaults to "info")</param>
private static void fireResultListener( string message, TraceLevel level = TraceLevel.Info )
{
if (_resultListener != null)
{
try
{
_resultListener( message, level );
}
catch
{ } // Ignore any exception raised by the listener.
}
}
/// <summary>
/// Notifies the result listener of any exception.
/// </summary>
/// <param name="ex">Exception to notify the listener about.</param>
/// <remarks>
/// The exception is raised as an "error" trace level.
/// </remarks>
private static void fireResultListener( Exception ex )
{
fireResultListener( ex.ToString(), TraceLevel.Error );
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment