When you think ASP, think...
Recent Articles
All Articles
ASP.NET Articles
ASPFAQs.com
Message Board
Related Web Technologies
User Tips!
Coding Tips
Search

Sections:
Book Reviews
Sample Chapters
Commonly Asked Message Board Questions
JavaScript Tutorials
MSDN Communities Hub
Official Docs
Security
Stump the SQL Guru!
Web Hosts
XML
Information:
Advertise
Feedback
Author an Article
Jobs

ASP ASP.NET ASP FAQs Message Board Feedback ASP Jobs
 
Print this Page!
Published: Wednesday, December 10, 2003

Using XML to Share Constants Across Projects

By Rachael Schoenbaum


Introduction


XML is the new "buzz" word out there being bandied about by bigwigs and top execs, but what does it mean for you as the developer? How can you use XML in your applications to produce code that is both faster to produce and easier to modify? This article highlights a case where using XML helped cut down on development time and made modification of the application a snap. (For information on what, exactly, XML is, be sure to read: What is XML?, and check out the XML FAQs section.)

- continued -

Background


I was working on a project that had a library of code (a compiled DLL) and a Web front end that leveraged the DLL. I had constants that both applications used and didn't want to try and maintain two separate constants files for each application. The pain involved in making sure changes were made to both files was too high. In addition, the constants I was using would have to be changed every time I deployed the applications since they differed in the development environment, the staging environment, and the production environment. Compiling the constants into the DLL would make deployment a big hassle. I needed a way to share the constants across both applications and make deployment simple.

Why Not Use Web.Config for Constants?


In Specifying Configuration Settings in Web.config, author Scott Mitchell looks at storing configuration information, like database connection strings, in the Web application's Web.config file. Initially I considered using Web.config as a place to store my constants, but decided against it for the following reasons:

  • Changing Web.config causes the Web application to restart, thus slowing down changes that need to be rolled out.
  • Values in Web.config are all stored as strings, making the storage of different and more complex types difficult or impossible.
  • While values can be shared between Web.config and the DLL, the only way to test the DLL is through the Web context. This methodology requires a recompile and re-deploy for every change, which is a huge hassle. (At my company, we often build stand-alone WinForms applications to test the DLL.)

XML to the Rescue


While using Web.config was not ideal for my situation, I came up with the idea of using XML to store my constants in a manner similar to the way Web.config does. I chose to use XML as the constants repository since, being a text file, it made changes very easy to incorporate, whether they were additions or modifications. Too, XML can be created quickly and easily with any text editor, is human-readable, and can be annotated via comments (<!-- comments -->).

Below is a sample XML configuration file:

<?xml version="1.0" encoding="utf-8" standalone="yes" ?> 
<applicationSettings>
  <!--Database settings-->
  <DB_CONN>server=mySrv;uid=myUser;pwd=myPwd;database=myDB</DB_CONN> 

  <!--Administrative settings-->
  <APPLICATION_URL>http://localhost</APPLICATION_URL> 
  <DELETE_LOGS_OLDER_THAN_X_DAYS>30</DELETE_LOGS_OLDER_THAN_X_DAYS> 
  <EMAIL_SERVER_ADDRESS>email.server.com</EMAIL_SERVER_ADDRESS> 

  <!--UI Settings-->
  <RESULTS_PER_PAGE>10</RESULTS_PER_PAGE> 
  <SITE_MAP_DEPTH>2</SITE_MAP_DEPTH> 
  <MAX_LOGIN_LENGTH>238</MAX_LOGIN_LENGTH> 

  <!--Directories -->
  <LOG_FILE_PATH>c:\inetpub\wwwroot\logfiles\</LOG_FILE_PATH> 
</applicationSettings>

Accessing the Constants


Defining and populating an XML file is all well and good, but I needed a way to access the values. In my first attempt, I was hitting the XML file directly every time someone requested a constant. This made the class really slow (file IO is a time consuming process) and I wanted it to be faster. Then I came across the Cache object, which provides access to the .NET Framework data cache. Because the Cache object allows you to make objects dependant on files, it was the perfect solution. The dependency ensures that any changes made to the XML file will force the Cache entry to be dropped. (For more information on caching XML files, read Scott Mitchell's article Displaying Cached XML Data in a DataGrid, and Intelligently Refreshing the Data; for general information on cachiing in an ASP.NET Web application, see Scott McFarland's article, Caching with ASP.NET.)

I created a class, ConstantsManager, to provide read access to the constants. The class checks to see if the Cache has an entry for the constant in question. If so, it returns that entry. If not, it looks for the entry in the XML file and stores it in the Cache for future use. If the entry doesn't exist in the Cache or XML file, it returns a 0.

'***************************************************************
' ConstantsManager
' Description: Manages the constants that live in the 
'          applicationConstants.config file.  These get stored
'          in memory and when the file changes, the file is 
'          removed from memory and re-read back into memory
'
' NOTE: Constants file must live in the webroot
'  on the web server for the web application to run.
'
' Author: Rachael Schoenbaum
' Create date: 12/4/2002
'***************************************************************
Imports System, System.Web.Caching, System.Xml, Microsoft.VisualBasic

  Public Class ConstantsManager
    
    ' Cache object that will be used to store and retrieve items from
    ' the cache and constants used within this object
    Protected Friend Shared myCache as _
             System.Web.Caching.Cache = System.Web.HttpRuntime.Cache() 
    Private Shared applicationConstantsFile _
             As String = "ApplicationConstantsFile"
    Public Shared applicationConstantsFileName As String = _
         String.Replace(System.AppDomain.CurrentDomain.BaseDirectory, "/", "\") & _
         "applicationConstants.config"
    Private Shared xmlFile As New XmlDocument()
        Private Shared constantIdentifier As String = "constant"
    Private shared constantKey As String = "cacheDependencyKey"
    

    Public Shared Function getConstant(ByRef key As String) As Object
            Dim tmpObj As Object
        If Not (myCache(constantIdentifier & key) Is Nothing) Then
          tmpObj = CType(myCache(constantIdentifier & key), Object)
        Else
          tmpObj = pullConstantFromFile(key)

          'Create the cache dependencies and insert the object into the cache
          If Not IsNothing(tmpObj) Then
            If myCache(constantKey) Is Nothing Then
              myCache.Insert(constantKey, now)
            End If                  
            myCache.Insert(constantIdentifier & key, tmpObj, _
                        New CacheDependency(applicationConstantsFileName))
          End If
        End If
      Return tmpObj
    End Function

    Private Shared Function pullConstantFromFile(ByRef key As String) As Object
      Dim obj As Object = 0
      If myCache(applicationConstantsFile) Is Nothing Then
        PopulateCache()
      End If

      'Attempt to find the element given the "key" for that tag
      Dim elementList As XmlNodeList = xmlFile.GetElementsByTagName(key)
      
      'If the key is found, the element list will have a count greater than
      'zero and we retrieve the value of the tag...
      If elementList.Count > 0 Then
        
        'Gets the node for the first element in the list of elements with
        'this tag name.  There should only be 1 so we return the first and
        'ignore the others.  If the node has a value, we retrieve the text        
        Dim node As XmlNode = elementList.Item(0)
        If Not (node Is Nothing) Then
          obj = node.InnerText()
        End If
                
        'If the value is a numeric, convert it to a number; otherwise
        'convert it to a string (we don't store values other than strings
        'and numbers).
        If IsNumeric(obj) Then
          obj = CType(obj,Integer)
        Else
          obj = CType(obj, String)
        End If
      End If
      Return obj
    End Function
    
    Private Shared Sub PopulateCache()
      'With a try around the entire event, the object attempts to load the XML
      'file and store it in the cache with a dependency on the XML file itself.
      'This means that any time the XML file changes, it is removed from the 
      'cache.  When the "getConstant" method is called again, the XML file won't
      'exist in memory and the PopulateCache will be re-called.
      Try
        xmlFile.Load(applicationConstantsFileName)
        myCache.Insert(applicationConstantsFile, xmlFile, _
                        New CacheDependency(applicationConstantsFileName))
      Catch e As Exception
        System.Diagnostics.Debug.WriteLine("Error: " & e.Message)
      End Try
    End Sub    
    
  End Class

Reading the Constants from the Web Application


To retrieve a constant value from the XML constants store, I just added a reference to the compiled code that has the ConstantsManager class in it. Because it's a public class with shared members, you don't have to instantiate a new object to use the methods. The following code shows an example of reading the DB_CONN constant from the constants class:

Dim databaseConnection As String = ConstantsManager.getConstant("DB_CONN")

To create constants for a Web application, simply create a file called applicationConstants.config that lives in the root directory of the Web site. That's all there is to it!

Protecting Your Constants
Since the constants XML file will likely contain sensitive data, such as database connection strings, it is vitally important that the constants XML file cannot be accessed by an anonymous Web visitor. To protect against this, I gave my XML constants file a .config extension. With ASP.NET, when files with the .config extension are requested, a This type of page is not served error message is returned, thereby protecting the constants from prying eyes!

Pros, Cons, and Ideas for Improvement


After having used this XML configuration file technique in numerous Web applications at my company, I've identified a number of pros and cons for this approach, as well as some ideas for improvement. What I really like about this approach includes:

  • Changes are automatic and don't require a recompile – deployments to multiple environments are easier, as is maintaining the code.
  • The constants file can be shared in both the testing DLL and the Web application – recall that my company uses a separate DLL for testing purposes. With this approach, you don't have to hard-code constants into the DLL - both the DLL and the Web application can share the same constants store.
  • Return value is data type specific – the class returns integers or strings, depending on the value of the tag. While it wasn't necessary in my case to store Booleans, dates, longs, doubles, etc, it would be fairly easy to extend the class to return these or other data types.
  • File is only accessed the first time a constant is requested – Because the values are stored in the data cache, the XML file is only accessed the first time a new constant is requested. This improves performance since file IO tends to be slow.

Along with advantages of this system, I have found a shortcoming. The structure of the XML file is fairly rigid. That is, the code expects each XML tag to have no attributes and no nested or children tags. This limits the structure of the XML and your configured constants to flat values. This is a nice segue into the ideas for improvements.

Along the lines of the first con, one of the ways this concept could be expanded or improved would be to allow the XML file to allow more flexible data descriptors i.e., "groups" of constants that logically belong together like the 50 states and their abbreviations or the possible member types in the system. Such a grouping would also allow for versioning. That is, you could group constants by application version, with an XML file like:

<?xml version="1.0" encoding="utf-8" standalone="yes" ?> 
<applicationSettings>
  <version value="1.0">
    <!--Database settings-->
    <DB_CONN>server=mySrv;uid=myUser;pwd=myPwd;database=myDB</DB_CONN> 

    <!--Administrative settings-->
    <APPLICATION_URL>http://localhost</APPLICATION_URL> 
    <DELETE_LOGS_OLDER_THAN_X_DAYS>30</DELETE_LOGS_OLDER_THAN_X_DAYS> 
    <EMAIL_SERVER_ADDRESS>email.server.com</EMAIL_SERVER_ADDRESS> 
  </version>
  
  <version value="2.0">
    <!--Database settings-->
    <DB_CONN>server=mySrv;uid=myUser;pwd=myPwd;database=myDB</DB_CONN> 

    <!--Administrative settings-->
    <APPLICATION_URL>http://localhost/v2</APPLICATION_URL> 
    <DELETE_LOGS_OLDER_THAN_X_DAYS>10</DELETE_LOGS_OLDER_THAN_X_DAYS> 
    <EMAIL_SERVER_ADDRESS>someOtherEmail.server.com</EMAIL_SERVER_ADDRESS> 
  </version>
</applicationSettings>

Another possible enhancement would be to have the ConstantsManager load all constant values from the XML file into memory when the Web application loads. Restarting the application or making changes to the XML file would make the application recompile take longer than normal, but all the values in the XML file would be immediately available via memory and the file would be accessed as infrequently as possible.

An Update for this Article is Available!
About a month after publishing this article, I updated the ConstantsManager class so that its constants can have an optional version attribute. This allows for the constants file to contain different values for specific constants based on the version of the application. For example, the SMTP server to use to send emails might differ as the project moves from the testing servers to the staging servers to the production servers. My addition allows a single constant, like EMAIL_SERVER to have different values for different version or stages of production. For more on this be sure to read: Improving Using XML to Share Constants Across Projects!

Conclusion


In this article I introduced a means to store constants for a Web application using a single XML file. The advantage of this approach is that you can store an entire Web application's constants in a single, easy to read and easy to edit XML file. This is useful when you have a single Web application that requires different constants when in different locations, such as when the Web application is on the production server versus when the Web application is on a development server.

The constants from the XML file can be easily accessed via the ConstantsManager class, which caches the constant results in the .NET data cache to improve performance. I have been using this constant-storing technique at my company for some time now, and invite you to do the same. If you have any questions, feedback, or recommendations, please don't hesitate to contact me.

Happy Programming!

  • By Rachael Schoenbaum


    About the Author


    Rachael Schoenbaum is a developer specializing in ASP and VB.NET, ASP/Visual Basic, SQL Server, XML, and related technologies. She consults for Lucidea and has been programming since 1999.



  • ASP.NET [1.x] [2.0] | ASPMessageboard.com | ASPFAQs.com | Advertise | Feedback | Author an Article