Introduction
The Compact Framework does not include native support for a .config file. This article will explain how simple it is to build that support back into your application.
Creating the app.config
What you first need is an app.config file in your Project. Since .config is not available for adding new items to your Project select anything (.cs is fine) and name it app.config. Your new app.config file will have the default namespace/class junk in it. Delete all that and create your .config. This sample one looks like this:
="1.0"="utf-8"
<configuration>
<appSettings>
<add key="Username" value="user"/>
<add key="Password" value="pass"/>
<add key="Port" value="1234"/>
</appSettings>
</configuration>
While .NET CF doesn't contain any libraries to read a .config at least when you compile your application the app.config is renamed correctly:
before you use your application you will need to copy/paste this renamed .config into your application directory or make sure its included in your .CAB Setup Project.
Using the code
The included ConfigurationManager
class in the CompactFrameworkSupplements.dll can be referenced and used in any Windows Mobile 6 application with just a few lines of code:
private void LoadAppSettings()
{
string error = string.Empty;
var cm = new ConfigurationManager();
if (cm.ValidateAppSettings(out error, new AppSettings()))
{
_appSettings = new AppSettings();
cm.LoadAppSettings(_appSettings);
textBox1.Text = "AppSettings loaded!";
}
else
textBox1.Text = error;
}
the _appSettings object is now loaded with all the values from your .config file. When its time to extend your application and you need additional information from the .config file. Simply add a key/value pair to the .config and a matching Property to your AppSettings class. That's it!
Lets see how the magic happens:
ValidateAppSettings
passes any errors out and takes an instance of your class that will be used in your application to hold the contents of the app.config. In this example my class is called AppSettings
and looks like this:
public class AppSettings
{
[Required(true)]
public string Username { get; set; }
[Required(true)]
public string Password { get; set; }
public int Port { get; set; }
}
ValidateAppSettings
has 3 main purposes in life:
- Does the .config contain a Key for every Property defined in the
AppSettings
class? - Do all the marked
Required
properties in the AppSettings
class have values in the .config? - Do the values match the expected data types of the properties in
AppSettings
?
and it looks like this:
public bool ValidateAppSettings(out string error, object classInstanceToReadAppSettingNamesAndTypesFrom)
{
error = string.Empty;
var expectedSettings = new Dictionary<string, Type>();
var attrDictionary = new Dictionary<string, object[]>();
var pis = classInstanceToReadAppSettingNamesAndTypesFrom.GetType().GetProperties();
foreach (var pi in pis)
{
expectedSettings.Add(pi.Name, pi.PropertyType);
attrDictionary.Add(pi.Name, pi.GetCustomAttributes(false));
}
foreach (var expectedSetting in expectedSettings)
{
var invalidValueError = "Config contains an invalid value for " + expectedSetting.Key;
if (!AppSettings.ContainsKey(expectedSetting.Key))
{
error = "Config does not contain " + expectedSetting.Key;
return false;
}
bool isRequired = IsConfigSettingRequired(attrDictionary, expectedSetting);
switch (expectedSetting.Value.FullName)
{
case "System.String":
if (isRequired && String.IsNullOrEmpty(AppSettings[expectedSetting.Key]))
error = invalidValueError;
break;
case "System.Int32":
if (isRequired && !AppSettings[expectedSetting.Key].IsInt32())
error = invalidValueError;
break;
case "System.Int64":
if (isRequired && !AppSettings[expectedSetting.Key].IsInt64())
error = invalidValueError;
break;
case "System.Double":
if (isRequired && !AppSettings[expectedSetting.Key].IsDouble())
error = invalidValueError;
break;
case "System.Boolean":
if (isRequired && !AppSettings[expectedSetting.Key].IsBoolean())
error = invalidValueError;
break;
case "System.DateTime":
if (isRequired && !AppSettings[expectedSetting.Key].IsDateTime())
error = invalidValueError;
break;
}
}
return error == string.Empty;
}
LoadAppSettings
takes the instance of your AppSettings
class that will be used in your application and uses reflection to set the values of the Properties:
public void LoadAppSettings(object classInstanceToLoadAppSettingsInto)
{
try
{
var pis = classInstanceToLoadAppSettingsInto.GetType().GetProperties();
foreach (var pi in pis)
{
if (String.IsNullOrEmpty(AppSettings[pi.Name])) continue;
pi.SetValue(classInstanceToLoadAppSettingsInto, Convert.ChangeType(AppSettings[pi.Name], pi.PropertyType, null), null);
}
}
catch (Exception)
{
throw new InvalidOperationException("Failed to load App Settings. Verify .config and class properties.");
}
}
Points of Interest
Reflection is amazing and super powerful even in the handycapped .NET 2.0 compact framework.
History