Skip to content

Overridable Configuration

smhinsey edited this page Jun 14, 2011 · 16 revisions

Summary

Euclid's OverridableSettings system provides a straightforward mechanism for defining arbitrary sets of configuration settings, providing default values in code, and optionally overriding them from external sources, such as App.config or remote services.

Location

Defined in the Euclid.Common project with a default implementation provided in Euclid.Common.Configuration project.

Usage

In your application initialization code, such as App_OnStart, or a Composite App's Initialize method, you create an instance of your configuration settings object in order to provide it to your container. If all of your configuration options are overridden with external values, there will be an alternate approach not described here.

	var config = OverridableSettings<FakeSettings>
		.Build(settings =>
		       	{
		       		settings.FakeConfigSetting.WithDefault(fakeSettingDefaultValue);
		       		settings.AnotherFakeConfigSetting.WithDefault(anotherFakeSettingDefaultValue);
		       	});

Settings are defined using classes which inherit from OverridableSettings. All properties implement IOverridableSetting or derivative interfaces in order to enable them to be overridden as well as to enable the fluent API.

	public class FakeSettings : IOverridableSettings
	{
		public FakeSettings()
		{
			AnotherFakeConfigSetting = new OverridableSetting<bool>();
			FakeConfigSetting = new OverridableSetting<string>();
			ListOfAssemblies = new OverridableSettingList<Assembly>();
		}

		public OverridableSetting<bool> AnotherFakeConfigSetting { get; set; }
		public OverridableSetting<string> FakeConfigSetting { get; set; }
		public OverridableSettingList<Assembly> ListOfAssemblies { get; set; }
	}

This example configures setting values in code and overrides one from AppSettings. You can implement your own custom overrides for sources such as databases, web services, or even systems like Apache ZooKeeper, if desired.

	<configuration>
		<appSettings>
			<add key="FakeSettings.FakeConfigSetting" value="Overriden value"/>
		</appSettings>
	</configuration>

Consuming a boolean config setting:

	if(config.AnotherFakeConfigSetting.Value){...}

or a string:

	page.Title = config.FakeConfigSetting.Value; // Title would be "Overriden value"

Checking if a setting has changed from the default value:

	if(config.FakeConfigSettingValue.WasOverridden){...}

Obtaining a setting's default value, regardless of its current value:

	var fakeConfigDefault = config.FakeConfigSettingValue.DefaultValue

It's not recommended that you use the configuration system to manage complex types, although it provides hooks to allow it to do so.

We might be able to infer the above config class via dynamic proxy from the below interface, but that's a down the road feature.

	public interface FakeSettings : IOverridableSettings
	{
		IList<Assembly> ListOfAssemblies { get; set;}	
		string FakeConfigSetting { get; set; }
		bool AnotherFakeConfigSetting { get; set;}
	}

You can implement your own settings override source as an extension method of IOverridableSettings. This is a bare bones implementation of the app settings override source.

	public static IOverridableSettings OverrideFromAppSettings(this IOverridableSettings settings)
	{
		foreach (var propertyInfo in settings.GetType().GetProperties())
		{
			var name = string.Format("{1}.{0}", propertyInfo.Name, settings.GetType().Name);
			var newValue = ConfigurationManager.AppSettings[name];

			if(newValue != null)
			{
				var propertyReference = propertyInfo.GetValue(settings, null);

				if(propertyReference is IOverridableSetting<string>)
				{
					((IOverridableSetting<string>)propertyReference)
					.ApplyOverride(newValue);
				}
				else if (propertyReference is IOverridableSetting<bool>)
				{
					((IOverridableSetting<bool>)propertyReference)
					.ApplyOverride(bool.Parse(newValue));
				}
				else if (propertyReference is IOverridableSetting<int>)
				{
					((IOverridableSetting<int>)propertyReference)
					.ApplyOverride(int.Parse(newValue));
				}

				propertyInfo.SetValue(settings, propertyReference, null);
			}
		}

		return settings;
	}

Now it can be used during initial configuration setup.

	var config = OverridableSettings<FakeSettings>
		.Build(settings =>
		{
			settings.FakeConfigSetting.WithDefault(fakeSettingDefaultValue);
			settings.AnotherFakeConfigSetting.WithDefault(anotherFakeSettingDefaultValue);
		});

	config.OverrideFromAppSettings();

Overrides can be chained. They are applied in the order that they are chained. In the below example, a setting which is overriden is both sources comes from the web service, since it is the last in the chain.

	var config = OverridableSettings<FakeSettings>
		.Build(settings =>
		{
			settings.FakeConfigSetting.WithDefault(fakeSettingDefaultValue);
			settings.AnotherFakeConfigSetting.WithDefault(anotherFakeSettingDefaultValue);
		});

	config.OverrideFromAppSettings();
	config.OverrideFromWebService();