Custom configuration Data from DataSets: Less is More

Sometimes it's easier and faster to do things "the easy way" with custom configuration data saved from a DataSet instead of slaving over Custom ConfigurationSections in the App.Config or web.config file.

"Imagine if every Thursday your shoes exploded if you tied them the usual way. This happens all the time with computers, and nobody thinks of complaining."  - Jef Raskin

"Less is more" - this is a credo that I try my best to live by every single day. It's both amusing and sad to see how people can complicate the utterly simple to the point of absurdity. I remember a newsgroup post I responded to recently that had some 30 lines of HttpWebRequest / Response code to get an XmlDocument from a remote Uri. I responded with this suggestion:

XmlDocument doc = new XmlDocument();
doc.Load(RemoteUri);

Currently I'm writing an FTP "Concentrator" for extensible future use that will run as a scheduled task and will FTP webserver log files from a number of different sites, preprocess the log files to remove unnecessary lines (WebTrends licensing charges "by the line", so you really don't need to pay for Jpegs, css or whatever), and then it will save the processed log files in specific folders for Webtrends to analyze. Clients will be able to log on and see their specific reports.

So the first thing is of course, we need a configuration file that can handle a collection of the same element or node - each node holds the information for a particular FTP session such as, "Name", "HostAddress", "UserName", "Password", "RemotePath", "LocalPath" and so on. You could have 10 of these, each one responsible for concentrating the server log files into a specific local folder on which WebTrends has been configured to use as a Data Source for reports. The "concentrator" app will be a .NET console app that will be run daily via Task Scheduler; it will start, do it's thing, deposit all the files, write status messages to the Application Event Log, and then quit.

So I started out thinking that I needed to study up on Custom Configuration handlers and sections. Let me tell you, this is not easy stuff. There is a lot to know, and you have to write custom classes to represent your "stuff". On top of that, if you want to expose collections in the app.config or web.config, you have to write even more code.

"But wait a minute", I thought. "Why does this stuff have to be in the standard configuration file? My app can load it from any file, Xml or other."

So, being a firm believer in "Less is more", I stopped and put on my Green Thinking Hat (a - la Edward de Bono). I said, "Let's have a little Green Hat (creative) thinking here..."

Turns out that the first thing I came up with was the best - our old friend, the DataSet. Here's the deal: if a user needs to be able to edit data, we can provide them with a windows forms utility app that will:

1) create a new DataSet with exactly the schema needed for our application.
2) Show this in a DataGridView so the user can easily add rows, edit a row, or even delete a row, and
3) Save the DataSet via WriteXml to the filename of the user's choice.
4) We can also Load an existing DataSet's Xml representation so it can be edited.

At runtime, we can get the DataSet very easily:

DataSet configDs = new DataSet();
configDs.ReadXml(System.Environment.CurrentDirectory + @"\config.xml");

So here's the basic code to pull this off.:

using System;
using System.Data;
using System.Windows.Forms;

namespace FtpConfigUtility
{
    public partial class Form1 : Form
    {
        private DataSet ds = null;
        private string fileNameAndPath = null;
        public Form1()
        {
            InitializeComponent();
        }

        private void btnNew_Click(object sender, EventArgs e)
        {
            ds = new DataSet();
            ds.DataSetName = "config";
            DataTable cfgTable = new DataTable();
            cfgTable.TableName = "FtpConfig";
            cfgTable.Columns.Add("Name");
            cfgTable.Columns.Add("HostAddress");
            cfgTable.Columns.Add("UserName");
            cfgTable.Columns.Add("Password");
            cfgTable.Columns.Add("RemotePath");
            cfgTable.Columns.Add("LocalPath");
            ds.Tables.Add(cfgTable);
            dataGridView1.DataSource = cfgTable;
        }
   
        private void btnSave_Click(object sender, EventArgs e)
        {
            DialogResult res = saveFileDialog1.ShowDialog();
            if (res == DialogResult.OK)
                ds.WriteXml(saveFileDialog1.FileName);
        }

        private void btnLoad_Click(object sender, EventArgs e)
        {
            webBrowser1.Visible = false;
            dataGridView1.Visible = true;
            openFileDialog1.Filter = "Xml files (*.xml)|*.xml|All files (*.*)|*.*";
            DialogResult res = openFileDialog1.ShowDialog();
            if (res == DialogResult.OK)
            {
               fileNameAndPath = openFileDialog1.FileName;
                ds = new DataSet();
                ds.ReadXml(fileNameAndPath);
                dataGridView1.DataSource = ds.Tables[0];
            }
        }

        private void button1_Click(object sender, EventArgs e)
        {
            webBrowser1.Visible = true;
            this.dataGridView1.Visible = false;
            webBrowser1.Navigate("about:blank");
            webBrowser1.Navigate(fileNameAndPath);
        }
    }
}
Yep, Less is More! You can download the Visual Studio 2008 sample solution here.

Einstein said it best:
"Solutions should be made as simple as possible, but no simpler".
By Peter Bromberg   Popularity  (1407 Views)