To read the article online, visit http://www.4GuysFromRolla.com/articles/011204-1.aspx

Improving Using XML to Share Constants Across Projects

By Rachael Schoenbaum


Introduction


In an earlier article of mine, Using XML to Share Constants Across Projects, I looked at how to share common constants across multiple ASP.NET Web projects using a "constants XML file" and a custom class (ConstantsManager) to read this file and pick out particular constant values. Since publishing that article, I've improved the class and file structure to allow for constants specific to a particular development phase or environment. For example, a constant that you might need to have access to is the mail server to use to send emails. However, the mail server to use might be different when testing, staging, and when the site goes live. In this article we'll look at how to extend my earlier article to allow for the constants file to have versioned constants.

The ConstantsManager Class and Multiple Environments


The problem with the ConstantsManager class as it exists in the first article, is that every time you roll your application out to staging or to production, you have to go in a modify the config file for values that are different across the different environments (like database connection strings, paths on the file server, and URLs). It's easy to forget which variables need to be modified and what they should be modified to. Plus, every time you touch the code, the likelihood for introducing errors grows.

An additional consideration is that not all constants are affected by different staging environments. For example, things like the number of search results that display per page or length of the columns in the database will remain the same across environments. My challenge, then, was to come up with a way to modify the ConstantsManager class to allow for an optional tag that indicated which environment (if any) the constant applied to without requiring modifications to the projects. The rest of the article describes in detail I accomplished this.

Modifying the Config File


To prepare the config file for this new concept, I first decided that I needed some mechanism to specify what version should be used. I decided to add a single new tag to the config file - THIS_VERSION - that would indicate what version of the constants to use. That way, when moving from one environment to another, all I would have to do was modify the value of this tag.

<THIS_VERSION>1</THIS_VERSION>

Next, for those constants that need to have different values for different versions, I added a version attribute. Imagine we had a constant named APPLICATION_URL, that had three different versions for, say, testing, staging, and production servers. The constant file, then, would contain three APPLICATION_URL elements, each with a differing version attribute like so:

<APPLICATION_URL version="1">http://localhost</APPLICATION_URL> 
<APPLICATION_URL version="2">http://staging.company.com</APPLICATION_URL> 
<APPLICATION_URL version="3">http://production.company.com</APPLICATION_URL> 

Of course not all constants require different values for different versions. For those constants, you can simply use just one tag and omit the version attribute altogether:

<RESULTS_PER_PAGE>10</ RESULTS_PER_PAGE>

To handle the versioned constants, the ConstantsManager code needs to be changed slightly. The following shows the complete code for this class, with the changes from my first article shown in red.

'***************************************************************
' 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"
    Private Shared thisVersion As Integer = getConstant("THIS_VERSION")
    

    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
        Dim node As XmlNode 

        'If there is only 1 element in the list, then the element doesn't
        'have a version number and can be returned as is.
        If elementList.Count = 1 Then
          node = elementList.Item(0)

          'If there is more than 1 element in the list, find the element for
          'the version of the application
        Else
          node = xmlFile.SelectSingleNode("descendant::" & key & _
                      "[@version=" & thisVersion & "]")
        End If

        'Retrieve the value behind the node that matched the key/version
        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

Using the New ConstantsManager Class


Using the new ConstantsManager class is absolutely no different than before. It's no different because the current version information is stored in the <THIS_VERSION> element in the constants file itself. An example of using the ConstantsManager class in an ASP.NET Web page is shown below:

If userType = ConstantsManager.getConstant("MEMBER") Then 
  'Do something...
End If

The manager pulls the value for the tag indicated. If the tag has a version, it only uses the version that matches what's in the <THIS_VERSION> element.

The best part of this enhancement is that if you're already using the ConstantsManager class, upgrading to this improved implementation requires no changes to your existing code base. The benefit to this methodology are that all of your constants for all different environments live in one file and you only have to change one value in the constants file to update your config file for your new environment. This makes roll outs easier and less error-prone.

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.

  • Article Information
    Article Title: ASP.NET.Improving Using XML to Share Constants Across Projects
    Article Author: Rachael Schoenbaum
    Published Date: January 12, 2004
    Article URL: http://www.4GuysFromRolla.com/articles/011204-1.aspx


    Copyright 2017 QuinStreet Inc. All Rights Reserved.
    Legal Notices, Licensing, Permissions, Privacy Policy.
    Advertise | Newsletters | E-mail Offers