Son of XmlSerializerSectionHandler

Quite a few people seemed to like the XmlSerializer-based IConfigurationSectionHandler I wrote. Cool! A few people asked about how we could use this same technology to write to the config file, though. Of course, this is a Bad Idea. As anyone who has taken the plunge knows, normal users do not have permission to write to the application configuration file. What you are supposed to do is to write to one of the special folders under Documents and Settings. Here’s a simple helper class to help you do exactly that:

using System; using System.IO; using System.Xml; using System.Xml.XPath; using System.Xml.Serialization; namespace Craig.Utilities { public class SettingsSerializer { public static void Serialize( string company, string app, string file, Environment.SpecialFolder folder, object data) { XmlSerializer ser = new XmlSerializer(data.GetType()); FileStream fs = new FileStream(GetSettingsPath(company, app, file, folder), FileMode.Create); try { ser.Serialize(fs, data); } finally { fs.Close(); } } public static object Deserialize( string company, string app, string file, Environment.SpecialFolder folder, Type type) { XmlSerializer ser = new XmlSerializer(type); FileStream fs = new FileStream(GetSettingsPath(company, app, file, folder), FileMode.Open); object o = null; try { o = ser.Deserialize(fs); } finally { fs.Close(); } return o; } private static string GetSettingsPath( string company, string app, string file, Environment.SpecialFolder folder) { string specialPath = Environment.GetFolderPath(folder); string intendedDir = Path.Combine(specialPath, company); intendedDir = Path.Combine(intendedDir, app); if (!Directory.Exists(intendedDir)) { Directory.CreateDirectory(intendedDir); } return Path.Combine(intendedDir, file); } } }

It’s not quite as clever (ahem) as my configuration section handler, but it gets the job done. Just hand Serialize the name of your company, the name of the app, a simple filename, one of the Environment.SpecialFolder enumeration values (probably ApplicationData), and an object to save, and it’ll automatically save it in the Windows standard location. Give the same information (minus the object, but with a Type object that describes what you’re looking for) to Deserialize, and it’ll rehydrate it for you.

Here’s an object we might want to save to a settings file :

public class UserAuthInfo { private int userid; private string[] roles; private bool isAuthentic; [XmlArray("Roles")] [XmlArrayItem("Role")] public string[] Roles { get { return roles; } set { roles = value; } } public int UserID { get { return userid; } set { userid = value; } } [XmlIgnore] public bool IsAuthentic { get { return isAuthentic; } set { isAuthentic = value; } } }

Note the use of the XmlIgnore attribute to suppress XML generation for the IsAuthentic property.

Here’s how we’d serialize the object:

UserAuthInfo uai = new UserAuthInfo(); uai.Roles = new string[] { "Craig", "Kevin", "Kristin", "Clint", "Kyle" } ; uai.UserID = 23; uai.IsAuthentic = true; SettingsSerializer.Serialize("DM", "tester", "settings.xml", Environment.SpecialFolder.ApplicationData, uai);

On my machine, that creates a file called C:\Documents and Settings\candera\Application Data\Pluralsight\tester\settings.xml, with this content:

<?xml version="1.0"?> <UserAuthInfo xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <Roles> <Role>Craig</Role> <Role>Kevin</Role> <Role>Kristin</Role> <Role>Clint</Role> <Role>Kyle</Role> </Roles> <UserID>23</UserID> </UserAuthInfo>

To deserialize it, it’s a simple matter of making this call:

UserAuthInfo uai = (UserAuthInfo) SettingsSerializer.Deserialize("Pluralsight", "tester", "settings.xml", Environment.SpecialFolder.ApplicationData, typeof(UserAuthInfo));

Easy as pie, and since we’re using the standard Windows folders, this application’s data would actually roam with a roaming user!

Some people have suggested using Isolated Storage for this, but I’ve heard that it can have major problems with long filenames on some systems. Still, if you prefer that, it would be pretty trivial to make a similar implementation that was based on Isolated Storage instead.