C# Application Settings Utility Class

Please note that a revised version of this code is now located here .

I wanted to create a self-contained (I’ll explain what I mean by this later) and re-usable template class that I could add to any C# application for the purpose of saving and loading application settings (user preferences, path names, etc.) in XML.

My goal was to be able to add new properties to the class without having to write additional code to have them load. This way, I would only need to add the necessary private variable and the associated public property (e.g. get & set) for each new applicatoin setting.

Yes, I know that .NET 2.0 and Visual Studio 2005 have a similar function built in, but I prefer to have full control of my application. Also I wanted to customize an event that could notify my application if/when the settings did not save or were not loaded successfully.

I wanted the class to be “self-contained”, that is, I wanted all of the code necessary to load and save the settings built into the class. That way, I could just add the appSettings class to my project and go.

This solution uses XML Serialization to store my application settings in an XML document. On retrieval, in the Load method, it uses Reflection to enumerate the properties of the class and assign their values to the local “this” instance of the class.

For illustration purposes, I also included a GetAppSettings method. This method loads the settings into a new instance of the class. But this method has a disadvantage: Because GetAppSettings returns a new instance of the appSettings class, to use it I would first have to instantiate an instance of the class. For example, to use GetAppSettings my application’s code would look something like this:

appSettings thowAwaySettings = new appSettings();
appSettings theRealSettings = throwAwaySettings.GetSettings("C:\some path");
thowAwaySettings = null;	// dispose of the first class

I was not satisfied with the GetAppSettings approach because of the need for an initial “helper” instance of the class which would be thown away. I also thought that this approach diminished the “self-contained” aspect I was trying to achieve.

A better approach would be have the class be able to “self load”. Eliminating the need for the second instance. I implemented the self load using Reflection in the Load method.

Using the Load method my application code can look like this:

appSettings appSet = new appSettings();
appSet.Load("C:\Some Path");

But wait, yet another enhancement is a custom constructor for the class that accepts a path parameter. When called with a valid path, the class could automatically Load itself. So then my applications code can look like this:

appSettings appSet = new appSettings("C:\Some Path");

Much better I think.

Here’s my code. Feel free to use and re-distribute. Comments welcome.

———————————————————————————————

using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Xml.Serialization;

namespace foo
{

    public class appSettings
    {
        public delegate void AppSettingsEventHander(object o, AppSettingsEventArgs e);

        // Declare Class Events
        public event AppSettingsEventHander SettingsEvent;

        private string _myPath;
        public string myPath
        {
            get { return _myPath; }
            set { _myPath = value; }
        }

        // Additional Application specific setting properties can be added here as needed...

        public appSettings(string sPath)
        {
            this.Load(sPath);
        }

        public bool SaveAppSettings(string thePath)
        // Returns True if Saved successfully, False otherwise.
        // Raises Event that includes exception and reason if case of error
        {
            try
            {
                XmlSerializer xs = new XmlSerializer(this.GetType());
                FileStream fs = new FileStream(thePath, FileMode.Create);
                xs.Serialize(fs, this);
                fs.Close();
            }
            catch (FileNotFoundException fex)
            {
                AppSettingsEventArgs e = new AppSettingsEventArgs(settingsEventReason.FileNotFound, fex);
                SettingsEvent(this, e);
                return false;
            }
            catch (Exception ex)
            {
                AppSettingsEventArgs e = new AppSettingsEventArgs(settingsEventReason.OtherException, ex);
                SettingsEvent(this, e);
                return false;
            }
            return true;
        }

        public appSettings GetAppSettings(string thePath)
        {
            // Returns new appSettings object if successfull, null appSettings otherwise
            // Raises Event that includes exception and reason if case of error

            try
            {
                appSettings appSet;
                XmlSerializer xs = new XmlSerializer(this.GetType());
                FileStream fs = new FileStream(thePath, FileMode.Open);
                appSet = (appSettings)xs.Deserialize(fs);
                return appSet;
                fs.Close();
            }

            catch (FileNotFoundException fex)
            {
                AppSettingsEventArgs e = new AppSettingsEventArgs(settingsEventReason.OtherException, fex);
                SettingsEvent(this, e);
                return (appSettings)null;
                ;
            }
            catch (Exception ex)
            {
                AppSettingsEventArgs e = new AppSettingsEventArgs(settingsEventReason.OtherException, ex);
                SettingsEvent(this, e);
                return (appSettings)null;
            }
        }

        public bool Load(string thePath)
        {
            // This function loads the settings file directly to "this" instance of appSettings
            // instead of returning the appSettings Object
            // Returns true on success, false otherwise
            // Raises Event that includes exception and reason if case of error

            try
            {
                appSettings appSet;
                XmlSerializer xs = new XmlSerializer(this.GetType());
                FileStream fs = new FileStream(thePath, FileMode.Open);
                appSet = (appSettings)xs.Deserialize(fs);
                foreach (System.Reflection.PropertyInfo pi in this.GetType().GetProperties())
                {
                    if (pi.CanWrite)
                    {
                        try
                        {
                            pi.SetValue(this, pi.GetValue(appSet,null),null);
                        }
                        catch (Exception ex)
                        {
                            pi.SetValue(this, null, null);
                        }
                    }
                }
                fs.Close();
            }

            catch (FileNotFoundException fex)
            {
                AppSettingsEventArgs e = new AppSettingsEventArgs(settingsEventReason.OtherException, fex);
                SettingsEvent(this, e);
                return false;
                ;
            }
            catch (Exception ex)
            {
                AppSettingsEventArgs e = new AppSettingsEventArgs(settingsEventReason.OtherException, ex);
                SettingsEvent(this, e);
                return false;
            }
            return true;
          }

    }  //  </class appSettings>

    public class AppSettingsEventArgs : EventArgs
    {
        // Constructor
        public AppSettingsEventArgs(settingsEventReason reason, object objInfo)
        {
            this._settingsEvent = reason;
            this._objInfo = objInfo;
        }

        private object _objInfo;
        private settingsEventReason _settingsEvent;

        // Public Property(s) to return value(s)
        public object objInfo
        {
            get { return _objInfo; }
        }

        public settingsEventReason eventReason
        {
            get { return (settingsEventReason)_settingsEvent; }
        }
    }   // </ ChangeEventArgs> 

    public enum settingsEventReason
    {

        FileNotFound = 1,
        // Add additional event reasons to enum here
        OtherException = 99
    }

} // </namespace>

—————————————————————————————————

Glenn Carney is a software developer, trainer, consultant and leader based in Overland Park, Kansas.

3 Responses to “C# Application Settings Utility Class”


  1. 1 caderoux October 12, 2007 at 9:44 am

    Doesn’t look like you can inherit from this. I was looking for something along the lines of this type of usage:

    public class MyAppSettings : AppSettingsBase {
    public int myappSetting1;
    public string myappSetting1;
    }

  2. 2 glenncarney October 12, 2007 at 11:15 am

    caderoux,
    You are correct. Using the class as an abstract to inherit from is a simple change and improves the implementation. Thanks for pointing this out.

    With your permission, I will re-post the code including your idea. The changes are simple to make:

    Add the abstract keyword to the appsettings declaration as shown below:

    public abstract class appSettings
    {

    }

    Make one change in the Load Method (which are only necessary due to an oversight on my part origianlly:

    In the load (lines 119-120) method change:

    appSettings appSet = new appSettings();
    XmlSerializer xs = new XmlSerializer(appSet.GetType());

    to this:

    appSettings appSet;
    XmlSerializer xs = new XmlSerializer(this.GetType());

    Finally, create a class declaration similar to the one you proposed in your comment in your application.

    And you are good to go. I tested this implementaion and it works fine and includes your new public settings.

    Thanks again for pointing this out.
    G

    Then,


  1. 1 Updated C# Application Settings Utility Class « glennCarney’s blog Trackback on October 13, 2007 at 2:04 pm

Leave a Reply

You must login to post a comment.