Click here to Skip to main content
16,021,288 members
Articles / Programming Languages / C#
Article

The CFGLite Project

Rate me:
Please Sign up or sign in to vote.
3.58/5 (5 votes)
27 Aug 20039 min read 34.3K   780   14   1
The CFGLite Project, for managing configuration files in .NET

Image 1

Table of Contents

Introduction

I've been playing around with .NET, and C# for a while now. I haven't set-up a true client-server environment at home yet, and it's not clear yet if the company I work for will embrace .NET or not. So I figured I'd put together a simple project as an exercise. Since I'd like to re-use the project, I looked for something that I knew would come handy down the line. Hence the idea of working with Configuration parameters and Configuration files. After all, I don't know of any non-trivial application that doesn't have a .ini, .cfg or such file to store configuration parameters.

Overview

When thinking about configuration files, I recognize at least two possible implementations. The "classic" configuration files look like a list of parameter_name=parameter_value entries, one per line. The more "modern" configuration files, on the other hand, may use XML to provide some structure. The CFGLite project works with the "classical" configuration files. There's a number of improvements that could be implemented to the current CFGLite project (hence the "Lite" postfix :-), and it might very well be that the next version of the project will work with XML-structured configuration files (see "The Road Goes on and on..." below). What I wanted to accomplish was to produce a simple library that I could import in any project and would allow me to quickly deal with configuration files.

Content of the CFGLite Library

Currently, the CFGLite library contains a few things:

  • The Parameter class: This is used to represent a single Parameter you wish to read from a configuration file;
  • The Engine class: This is really the heart of the library;
  • ParameterDisplay: A custom control to display a Parameter and, optionally, let the user change the parameter's name, value and type;
  • ParameterLister: A more complex custom control to let the user manage a collection of parameters. Each of these classes comes with documentation in the source code, so I won't spend too much time describing them here. Rather, I'll focus on the usage of the library, and let the public (that's *you* :-) send me feedback in regard to the details. Feedback on the usage of the library is appreciated as well ! I'm also including a "Lesson Learned" section to analyze a few pointers, if you're interested.

Using the CFGLite library

Assume that you are implementing a new application, and that you wish to read configuration parameters from a configuration file. We'll say that this file is found at C:\My Documents\myFile.cfg for example's sake. Furthermore, say that you are working with the following configuration parameters

  • Version: This is a Required Parameter (i.e. if the configuration file does not include this parameter, your application should bail);
  • Trace: This is an optional parameter, and, if the configuration file does not include it, its default value is "NONE";
So, in your application, you could do something like this:

C#
using CFGLite;

//...

Engine engine = new Engine("C:\\My Documents\\myFile.cfg");
engine.AddParameter(new Parameter(  "Version",
            ParameterType.REQUIRED));
engine.AddParameter(new Parameter(  "Trace",
            ParameterType.OPTIONAL,
            "NONE"));
EngineStatus es = engine.ReadFile();
if(es==EngineStatus.FAIL)
{
  //Uh-oh: something went wrong...
  //Handle issue as needed; for instance, report to user:
  MessageBox.Show(this, engine.Details(), "Configuration Error");

  //Bail out as you see fit.
}
//Else the configuration parameters have been read.

string version = engine["Version"];
string trace = engine["Trace"];

//go on as you need.

I hope this is simple enough. Feel free to contact me with any question, of course.

Lessons Learned

Here's a few interesting points, class by class. I started out writing a long description of each class, but I now realize this would be boring to most readers. Thus, forgive me if I point out only the most interesting things for each class.

The Parameter class

Nothing really interesting here.

The Engine class

I guess some might ask why I added the checks on the engine's status on most public methods. For instance, in AddParameter(Parameter) you find:

C#
if(status==EngineStatus.WORKING) 
  throw new ApplicationException( 
  "CFGLite: [Engine::AddParameter(Parameter)]\n"+ 
  "The Engine is currently Working."); 

It may seem very redundant at this point, but if an Engine instance was shared between multiple threads, it may happen that someone would try to add a parameter to the engine while the engine is reading a configuration file for another thread => difficult situation to handle. Hence the whole deal with the WORKING status. [ For those of you really interested on the internals of this class, and the assumptions I made while developing it, see the comments to the source of the ProcessLine method. ]

The ParameterDisplay control

Ah.. my first attempt at a custom control ! This was fun, and easy. While displaying a Parameter in two text boxes and a group of radio buttons was easy, I figured that sometimes you may wish to simply display the Parameter, while other times you may wish to provide a full-blown control for the user to change the parameter's name, value and type. Hence the ReadOnlyName, ReadOnlyType, and ReadOnlyValue attributes.

Also, if you let your users change stuff, you should keep track of it. Hence the Changes attribute (which is a get-only), and the matching ClearChanged method. The theory is that, with a ParameterDisplay that lets the user modify stuff, you will eventually do something like this:

C#
if(myParameterDisplay.Changed) 
{ 
  Parameter newParameter = myParameterDisplay.TheParameter; 
  //do whatever you need with the new Parameter 
  myParameterDisplay.ClearChanged(); 
} 

It might be more elegant to implement this with delegates, but I figured I could use the simple solution in this case and let the client application developer be responsible :-) In order to get the Changed attribute to work, of course, I had to capture the TextChanged events on the text boxes, and the CheckedChanged event on the radio buttons. Some might find interesting the fact that I used a single event handler to capture the CheckedChanged event on both radio buttons (type_CheckedChanged method), and used the sender object (cast to RadioButton) to figure out which radio button sent the event.

The ParameterLister control

Since the ParameterDisplay control was so easy to implement, I decided to build upon it. No, not really... in truth, I figured out that I needed something to present a list of Parameters (for the Test_CFGLite application), and I could either leave this task up to the application using the CFGLite Library, or provide a custom control for it. Since it seems that this would be a common need for applications using the CFGLite library, I figured I'd provide the custom control. If you don't like it, you don't need to use it :-)

Basically, it includes a list box and a ParameterDisplay. When you select a parameter in the list box, it pops up in the ParameterDisplay. Buttons are included to add a new Parameter to the list and delete a Parameter from the list. The ParameterLister lets you set up the user's "access rights" via the AllowAdd, AllowDel, and AllowChange public attributes, and manages the GUI elements accordingly. Note that, in the ParameterLister, if you can "Change" parameters, you can change all of their attributes (name, value, type). To properly handle the SelectedIndexChanged event on the list box, I had to include the currSelection and suspendIndexChangedHandler private fields in this control. This last one, in particular, was added after I realized that adding items to the list box's Items collection, apparently, raises the SelectedIndexChanged event (further research needed, but that's what it looked like !). What else? You can retrieve the Parameters from this control as you need, in the form of an Array of Parameters (ParametersArray attribute) or in the form of an Hashtable (ParametersHash attribute). I needed only the Hashtable form, but I figured someone else may prefer arrays.

The Test_CFGLite application

This is a simple testing application. It includes a button leading to a ParametersDialog dialog, and a button to perform a test with the parameters defined in the above dialog. The ParametersDialog dialog uses the ParameterLister control to let the user manage the list of Parameters that will be passed to the Engine during the test. Note that the dialog itself implements the "OK" and "Cancel" buttons we are used to see in dialogues, while the ParameterLister control didn't have either one. The "Test" button lets the user pick a file to read, and uses the Engine class to try and read the file.

The Road Goes on and on...

Feedback is very appreciated, and I wouldn't mind it if anyone was to like this CFGLite library and build on it. Here's a few ideas I am considering for the next version of the library.

  • XML files: Aside from the "classic" parameter_name = parameter_value format, configuration files are more and more XML-oriented (see the application.config files of the .NET environment, for instance). The next version of the library could let the user specify which form should be assumed.
  • Regexes for the parameters names and values: This version of the library assumes that your parameter names will contain no spaces, and splits the lines from the configuration files on the first '=' character found. Spaces, before and in between the parameter names, the '=' character, and the parameter value are ignored. This is acceptable for most applications I worked on, but may not suite everyone. The next version of the library may let a user define parameter names and values with Regular expressions. The fact that the '=' character is the "separator" between the parameter names and values is also an assumption, and should be something a user may modify as needed.
  • Facets for the parameter values: Often, I found that some (but not all) of the configuration parameters in an application are assumed to be assigned a value from a predefined list. For instance, the "trace" configuration parameter should be one of the following: "none", "low", "medium", "full". The next version of the library may let a user define this list of acceptable parameters and catch as an un-acceptable situation the case where the value assigned to the parameter in the configuration file does not match any of these values.
  • Configuration manager: A different problem, that may be solved by some class/control in the library is that of letting us manage configuration files, specifying the parameters to be included, and the format of the file.
  • Configuration manager: Similarly, an application may wish to display the current configuration parameters to the user, and let him change them as needed.

Just a few ideas, and I am sure that even this first version of the library can be drastically improved.

History

  • v.1.0 24-AUG-2K3 First Draft.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
Web Developer
United States United States
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
Generalconfiguration files Pin
Member 122766711-Dec-04 3:03
Member 122766711-Dec-04 3:03 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.