Application-specific configuration information has historically been stored in INI files, which are plain-text files that contain key/value data within sections. In Windows, the registry has replaced INI files for configuration information. However, a lot of applications still use INI files.
In a Web application, configuration information is sometimes hard-coded, leaving the configuration information scattered and difficult to maintain. If you implement your own INI file for Web application configuration information, it provides a central repository for this information to which you can provide a Web front-end to make configuration changes.
INI files usually contain information in the following format:
[Section]
key=value
Also, the Windows' API includes some functions for getting and storing INI information. Two of these functions are getPrivateProfileString() and writePrivateProfileString(). These functions wrap up the steps to export and import configuration data to/from an INI file. You can mimic this same functionality in your INI files; but instead of using the INI format as above, you can implement an XML-based INI file.
In the following example, I'll create a class in ASP to wrap up the functionality for collecting and writing configuration information. The class will contain two methods, getPrivateProfileString() and writePrivateProfileString(), through which I'll mimic the interface of the two Windows' API functions. Here's the code:
Class CINI
Private m_dom
Public Function getApplicationPath()
Dim sURL
sURL = Request.ServerVariables("URL")
getApplicationPath = Mid(sURL, 1, InStr(2, sURL, "/"))
End Function
Public Function getPrivateProfileString(sDomain, sKeyName, sDefault,
sFileName)
Dim m_result
m_result = ""
If m_dom.load(sFileName) Then
Dim domain_node
Set domain_node = m_dom.selectSingleNode("//domain[@domain_name='"
& LCase(sDomain) & "']")
If domain_node Is Nothing Then
m_result = sDefault
Err.Raise vbObjectError, "", "no domain"
Else
Dim node
Set node = domain_node.selectSingleNode(sKeyName)
If node Is Nothing Then
m_result = sDefault
Err.Raise vbObjectError, "", "no node"
Else
m_result = Unescape(node.text)
End If
Set node = Nothing
End If
Set domain_node = Nothing
Else
m_result = sDefault
Err.Raise vbObjectError, "", "File Error: Cannot open or find " &
sFileName
& "."
End If
getPrivateProfileString = m_result
End Function
Public Function writePrivateProfileString(sDomain, sKeyName, sString,
sFileName)
If m_dom.load(sFileName) Then
Dim domain_node, node
Set domain_node =
m_dom.selectSingleNode("//domain[@domain_name='" & LCase(sDomain) &
"']")
If domain_node Is Nothing Then
Dim domain_attr, map
Set domain_node = m_dom.createNode(1, "domain", "")
Set domain_attr = m_dom.createNode(2, "domain_name", "")
domain_attr.text = LCase(sDomain)
Set map = domain_node.Attributes
map.setNamedItem domain_attr
Set domain_node =
m_dom.documentElement.appendChild(domain_node)
Set map = Nothing
Set domain_attr = Nothing
End If
Set node = domain_node.selectSingleNode(sKeyName)
If node Is Nothing Then
Set node = m_dom.createNode(1, sKeyName, "")
Set node = domain_node.appendChild(node)
End If
node.text = Escape(sString)
If m_dom.save(sFileName) <> 0 Then _
Err.Raise vbObjectError, "CToolbox::writePrivateProfileString(.., "
&
sFileName & ")", "Cannot save file for some reason."
Set domain_node = Nothing
Set node = Nothing
Else
Err.Raise vbObjectError, "", "File Error: Cannot open or find " &
sFileName
& "."
End If
End Function
Private Sub Class_Initialize
Set m_dom = Server.CreateObject("MSXML2.DOMDocument")
m_dom.async = False
End Sub
Private Sub Class_Terminate
Set m_dom = Nothing
End Sub
End Class
The first thing to note is that application information will be stored in the following XML format:
<root>
<domain domain_name="my_domain">
<key>value</key>
</domain>
</root>
From this example, you can see that information is stored relative to a domain. The domain is like the Section part of the INI file so you can store information specific to the Web application. Web applications exist under a given domain, which you can find at the root of the HTTP environment variable "URL."
After reviewing the code, you'll see that I included a simple little function called getApplicationPath() to get the domain name of the current script. If you look at the method writePrivateProfileString(), you'll see that the method expects four parameters: sDomain, sKeyName, sString, and sFileName. This method loads the XML file specified by the sFileName parameter. Once it loads successfully, it searches for the domain node by the sDomain parameter. It does this by selecting the node based on the XPath query "domain[@domain_name='sDomain']". The sDomain parameter is converted to lowercase to avoid problems with case sensitivity. If the domain node doesn't exist, a domain node is created, the domain_name attribute value is set, and the domain node is appended to the documentElement of the XML document. The domain node is then used to create the key/value pairs.
A sKeyName node is created in the XML document. The only drawback to sKeyName is that it must be a qualified name, which means that it must abide by the rules of XML convention for qualified names. When the node is created, it's appended to the domain node. The sKeyName node's text is then set to the escaped sString parameter value, which is escaped to avoid possible special characters from causing parsing errors in the XML document. Once all the changes occur, the XML document is saved back to sFileName.
The getPrivateProfileString() method also accepts four parameters: sDomain, sKeyName, sDefault, and sFileName. The XML document is loaded from sFileName. The domain node is located using the same logic as writePrivateProfileString(). If the domain node is found, the sKeyName node is located, and, upon location, the return value of the method is the text of the sKeyName node. If the sKeyName node isn't located, the return value is the value of the sDefault parameter.
In order to utilize this functionality, you must provide explicit permission for file access to the INI file. There are several ways you can do this. One way to do this is to set the anonymous user of the accessing page to an account with the appropriate privileges. Another way is to allow read/write access privileges of the INI file to the IIS anonymous user account, which is usually IUSR_[COMPUTERNAME]. And yet a third way is to restrict the Web page's usage through Basic or NTLM authentication (note that Basic authentication isn't recommended).
You can also use this logic to create the same functionality in other languages. However, the specifics of the DOM Document interface are different for different languages, as is the language syntax.
Keep your developer skills sharp by automatically signing up for TechRepublic's free Web Development Zone newsletter, delivered each Tuesday.



