Previous posts already dealt with the topic of checking configuration data stored in web.config and app.config.
Checking web.config on Application Start sketched how to use XmlDocument and XPath to check required entries in the <serviceModel> section used by web service clients.
Complex Data in .Net .config Files mentioned the built-in validators in the System.Configuration namespace as subclasses of ConfigurationValidatorAttribute. These validators are invoked as soon as the configuration section is accessed.
However, after deployment we also want to check other configuration data:
- app.config, web.config (connection strings, etc.)
- Properties.Settings sections
- Configuration data stored in a database
The data to be checked should be accessible via an object of a typed class, such as the Properties.Settings class or a configuration class mirroring a database record.
We can then define a delegate to check whether an object’s property is a valid value (the example handles string values, but can be extended for any data type):
delegate string CheckFunction<T>(T data, Expression<Func<T, string>> property);
A method handling the check and logging the result is defined as
void Log<T>(T data, string prefix, Expression<Func<T, string>> property, CheckFunction<T> fn) { var propertyName = prefix + "." + property.GetPropertyName(); var propertyValue = property.Compile().Invoke(data); var errorMessage = fn(data, property); if (string.IsNullOrEmpty(errorMessage)) LogResult(propertyName, propertyValue, "ok", true); else LogResult(propertyName, propertyValue, errorMessage, false); }
with the LogResult() method defined as
void LogResult(string propertyName, string propertyValue, string errorMessage, bool isValid);
and the GetPropertyName() extension method as previously defined.
Let’s say we want to check a .config setting identifying an existing directory, such as an upload directory for a web application:
var webconfig = Properties.Settings.Default; Log(webconfig, "My.Namespace.Properties.Settings", w => w.UploadTempPath, CheckDirectory);
The CheckDirectory method may be implemented like this:
string CheckDirectory<T>(T conf, Expression<Func<T, string>> property) { string value = property.Compile().Invoke(conf); if (string.IsNullOrEmpty(value)) return "null or empty"; if (!Directory.Exists(value)) return "directory does not exist"; return null; }
For data stored in the AppSettings section, we can define similar checks:
var appsettings = System.Configuration.ConfigurationManager.AppSettings; Log(appsettings, "AppSettings", a => a["AppHelpLink"], CheckUrl);
with CheckUrl() defined as
string CheckUrl<T>(T conf, Expression<Func<T, string>> property) { string value = property.Compile().Invoke(conf); if (string.IsNullOrEmpty(value)) return "null or empty"; try { Uri uri = new Uri(value); } catch(Exception ex) { return ex.GetType() + " " + ex.Message; } value = value.ToLower(); if (!value.StartsWith("http://") && !value.StartsWith("https://")) return "not http:// or https://"; return null; }
Of course, these checks can be applied to any structured configuration data, and the check methods can be implemented as required by the system to be deployed.