September 2, 2014
Hot Topics:
RSS RSS feed Download our iPhone app

Concrete Code for a Quick Configuration

  • October 25, 2005
  • By Robert Bogue
  • Send Email »
  • More Articles »

In my last article, " Caught Up in Code, or Quick Configuration", I proposed that you build more configuration based software solutions and less software that is governed by the relatively rigid rules of code alone. That article focused on the concept of configuration-based development. In this article the focus is on using the patterns for implementing a configuration-based solution.

A Few Examples

Before we drop into the details of a code sample, here are a few quick examples of how you can apply the configuration based pattern in the code you're writing.:

  • Factory Pattern - Using reflection, generics, interfaces, and a configuration file, you can create a strongly typed factory that can generate objects of any type. You wouldn't have to worry about ever building another factory class.
  • Optional Display - User Interface trimming, in other words, removing items from a menu when the user doesn't have access to them is a time consuming process. However, a control can be built uses a list to determine the menu options and performs the security check as a part of drawing the menu. You wouldn't have to worry about trimming my UI because the control manages security automatically.
  • Every Command Line Utility with Parameters - I tend to write dozens of little command line utilities to help systems administrators with their day-to-day work and make sure that the systems that I build can be maintained. Every command line utility that you create which takes command line parameters can exhibit the same configuration based approach to code. The code doesn't have to be rewritten each time the code is placed in a different environment.
  • Skins and Themes - User interfaces are being developed with skins or themes more and more frequently these days. These interfaces illustrate the configuration-based approach. The code identifies the things that can be drawn and the skin or theme changes how those things are drawn. You write the code once and configure it to the look and feel you want.

There are dozens of examples of how to use this pattern. Let's take a look at one in particular.

The Simplest Example

Making this concept concrete, take the following code example:

if (!currrentUser.IsAuthorized(this))
{
   // Not Authorized
   Response.Redirect("./accessdenied.aspx");
}

The example checks to see whether a user is authorized to view the current page (the variable this is the current page in this context.). If the user isn't authorized, then the user is sent to a redirect page (accessdenied.aspx). Here's the same code, but this time with a configuration based approach.

if (!currentUser.IsAuthorized(this))
{
   // Not Authorized
   string redirect2 = System.Configuration.ConfigurationSettings
                        .AppSettings["AuthorizationDenied"];
   Response.Redirect(redirect2);
}

This time the redirect url (redirect2) is contained in the configuration of the web application. The code is precisely one line longer but creates a great deal of flexibility.

One might ask why you would ever change the URL of an access denied page.

One reason would be if you had multiple subdirectories in your application and decided that you wanted one and only one access denied page. Less code is a good thing. Less copies of the same code is even better.

Another reason for changing the redirect URL when a user isn't authorized to the page is to give them a chance to request access. With a configuration based approach you can add a new page to the solution (or to another solution) and change the configuration file and presto the new authorization request page can become a part of your solution-without the need to change the existing pages.

Building a Dynamic Questionnaire

Of course, the preceding is an overly simplistic example. A more complex example is a questionnaire system that allows you to ask an arbitrary set of questions. The complete code for the example is available here but let's look at the basic components of the solution.

We have a Question class that contains the question text and what the next question is if the response to this question is yes and where to go if the question is answered with no. In our simple example there are only two responses to any question. We also have a QuestionCollection class that contains an arbitrary number of questions.

Next we have an Answer class that takes the question ID and the answer that was provided. There is an AnswerCollection class that records an arbitrary number of Answer class objects.

The overall process for the program is to 1) load the questionnaire, 2) get the user responses, and 3) print the results.

In the configuration based world we take our questionnaire from a configuration file. In this case, a simple text file that is semicolon delimited. The file I quickly put together for this example is:

1;Do you love configuration?;2;20
2;Do you love it bushels?;3;20
3;Do you love it bunches?;4;20
4;Would you tell a friend about it?;-1;20
20;Do you think you have a negative attitude?;-1;21
21;Do you want this questionnaire to end?;-1;22
22;I don't care what you think, you're outta here - believe me?;-1;-1

The code to read the file in is trivially simple (without any kind of error handling.) It is shown below.

QuestionCollection qc = new QuestionCollection();
AnswerCollection ac = new AnswerCollection();
StreamReader sr = File.OpenText(args[0]);
string line = sr.ReadLine();
while (line != null)
{
   string[] lineParts = line.Split(';');
   qc.Add(new Question(int.Parse(lineParts[0]), lineParts[1], int.Parse(lineParts[2]), int.Parse(lineParts[3])));
   line = sr.ReadLine();
}

All that is happening is each line is read, broken up, constructed into an object and added to the question collection.

The next part, which reads the responses, is also trivially easy. It's shown below:

int nextQuestion = 1;
Question q;
do
{
   q = qc[Convert.ToString(nextQuestion)];
   Console.WriteLine(q.QuestionText);
   string response;
   while((response = Console.ReadLine()) == null || response.Length == 0)
        ; 
   if (response[0] == 'y' || response[0] == 'Y')
   {
      ac.Add(new Answer(nextQuestion, true));
      nextQuestion = q.NextYesQuestionID;
   }
   else
   {
      ac.Add(new Answer(nextQuestion, false));
      nextQuestion = q.NextNoQuestionID;
   }
} while (nextQuestion != -1);

All that it's doing is writing out the question text and reading back in a line of text - presumably with the answer. It then processes the answer, records it, and sets up for the next question. When the sentinel value of -1 is detected as the next question the questionnaire ends.

The final step is to write out the results, which is a scant three lines of code, shown here:

foreach(string key in ac.Keys)
{
   Answer ans = ac[key];
   Console.WriteLine("Question ID:{0} Answer: {1}",
      ans.QuestionID, ans.Response);
}




Page 1 of 2



Comment and Contribute

 


(Maximum characters: 1200). You have characters left.

 

 


Sitemap | Contact Us

Rocket Fuel