![]() |
Languages »
C# »
General
Intermediate
The CFGLite ProjectBy Frank Olorin RizziThe CFGLite Project, for managing configuration files in .NET |
C#, Windows, .NET 1.0, Dev
|
|
Advanced Search |
|
|
|
||||||||||||||||
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.
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.
Currently, the CFGLite library contains a few things:
Parameter class: This is used to represent a single Parameter you wish to read from a configuration file;
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. 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";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.
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.
Nothing really interesting here.
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:
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. ]
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:
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.
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.
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.
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.
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.
Just a few ideas, and I am sure that even this first version of the library can be drastically improved.
| You must Sign In to use this message board. | ||||||||
|
||||||||
|
||||||||
|
||||||||
|
||||||||
General
News
Question
Answer
Joke
Rant
Admin
|
PermaLink |
Privacy |
Terms of Use
Last Updated: 27 Aug 2003 Editor: Nishant Sivakumar |
Copyright 2003 by Frank Olorin Rizzi Everything else Copyright © CodeProject, 1999-2009 Web18 | Advertise on the Code Project |