Before ASP.NET, a file with a hard-coded location, the INI file, the Registry, and the IIS metabase were some of the most frequently used locations for storing the database connection string. These solutions are no longer needed because ASP.NET provides a more elegant solution: web.config.
Basically, the web.config file is an XML file that stores all the configuration information for an ASP.NET Web application. It's only appropriate to add the database connection string here because it is a piece of configuration information. In fact, the web.config file has an optional predefined element, <appSettings>, to address such user-defined
configuration information.
<appSettings> is made up of one or more <add> elements containing key/value attribute pairs. These elements are perfect for CMS.NET to store database connection information, and they look like Listing 10-4 when finally implemented by the setup procedure.
<!--APPSETTINGS
This section sets all the custom application settings -->
<appSettings>
<add key="setup" value="true"/>
<add key="database" value="CMSNET"/> <add key="datasource" value="localhost"/> <add key="userid" value="sa"/>
<add key="password" value=""/> <add key="timeout" value=""/> </appSettings>
Adding the <appSettings> element to the web.config XML file is the purpose of Setup/setup2.aspx.
The Setup/setup2.aspx Web Page
Setup/setup2.aspx is a Web form designed to capture all the information needed to determine where CMS.NET's database is located as well as the username and
password needed to get access. It is a very simple form that looks like Figure 10-3. As you can see, there is not much to the form except that it validates that Database and
Data Source both have values and that the optional Connection Timeout is numeric if entered.
Figure 10-3: Setup/setup2.aspx
Processing a Web Form—Setup/setup2.cs
What is really interesting about this Web page is what happens behind the scenes in the Codebehind.
The first thing the Codebehind for setup2 does is repopulate the values in the edit fields of the form (if this is a return visit to the setup procedure) or, more likely, set the edit fields to their default value.
private void Page_Load(object sender, System.EventArgs e) {
if (!IsPostBack) {
AppEnv appEnv = new AppEnv(Context);
txtDatabase.Text = appEnv.GetAppSetting("database"); if (txtDatabase.Text.Length <= 0) { txtDatabase.Text = "CMSNET"; } txtDataSource.Text = appEnv.GetAppSetting("datasource"); txtUserID.Text = appEnv.GetAppSetting("userid"); txtPassword.Text = appEnv.GetAppSetting("password"); txtTimeout.Text = appEnv.GetAppSetting("timeout"); }
The user first enters the appropriate values into the edit fields and clicks the Make Connection button. The Codebehind then does a page validation checking to see whether the information is valid for connecting to the database by actually attempting to connect using the entered values. By using exception handling, the code is able to catch any errors that occur and present them back to the user for correction.
If all is well, the values are added to the web.config XML file, and you then navigate to the next step in the setup process.
else { Page.Validate(); lblConnectError.Text = ""; if (Page.IsValid) { try {
SqlConnection myConnection = new SqlConnection();
myConnection.ConnectionString = "server=" + txtDataSource.Text + ";database=" + txtDatabase.Text + ";uid=" + txtUserID.Text +
((txtTimeout.Text.Length > 0) ?
";Connection Timeout=" + txtTimeout.Text : "");
SqlDataAdapter myCommand =
new SqlDataAdapter("select * from Account", myConnection); // Can we get to the database?
DataSet ds = new DataSet(); myCommand.Fill(ds, "Account"); UpdateConfigWeb(txtDatabase.Text, txtDataSource.Text, txtUserID.Text, txtPassword.Text, txtTimeout.Text); Response.Redirect("setup3.aspx"); return; }
catch (Exception err) {
lblConnectError.Text = err.Message; }
}
lblErrorHeader.Text =
"Sorry, cannot connect to your database the following errors occurred:"; }
Programmatically Updating a web.config File—Setup/setup2.cs
The UpdateConfigWeb() method handles all the gory details of updating the
web.config file. It takes as parameters all the values that will be placed in the web.config file.
public void UpdateConfigWeb(String database, String datasource, String userid, String password, String timeout)
{
It then opens the web.config file, loads it into an XmlDocument for processing, and closes it so that it may be opened later for writing.
XmlReader xtr = new
XmlTextReader(File.OpenRead(Server.MapPath("..\\web.config")));
XmlDocument doc = new XmlDocument(); doc.Load(xtr);
xtr.Close();
The first thing it does is look for the <appSettings> tag. If it doesn't find it, the method dumps the key/values into the web.config file wholesale.
XmlNodeList nodes = root.GetElementsByTagName("appSettings");
if (nodes.Count <= 0) {
// place in complete appSettings section
XmlDocumentFragment newAppSettings = doc.CreateDocumentFragment(); newAppSettings.InnerXml=
("<!-- APPSETTINGS\n "+
"This section sets all the custom application settings\n -->" + "<appSettings>\n" +
" <add key=\"setup\" value=\"false\" />\n" +
" <add key=\" database\" value=\"" + database + "\" />\n" + " <add key=\" datasource\" value=\"" + datasource + "\" />\n" + " <add key=\" userid\" value=\"" + userid + "\" />\n" +
" <add key=\" password\" value=\"" + password + "\" />\n" + " <add key=\" timeout\" value=\"" + timeout + "\" />\n" + " </appSettings>");
//add the new appSettings to the doc root.AppendChild(newAppSettings); }
On the other hand, if there is an <appSettings> tag, the method has the arduous task of going through all the key/value pairs one by one, looking for the values it needs to update while noting the ones that are missing.
You might note that this code shows how to update attributes in an element. The process is simple because each element gets all its attributes in a collection using the
Attributes property. Get the specific attributes you want by name using the
GetNamedItem() method, in this case the key and value attributes. Finally, check which key you have and update its value appropriately.
else {
bool issetup = false; bool isdatabase = false; bool isdatasource = false; bool isuserid = false; bool ispassword = false; bool istimeout = false;
for (int i=0; i < nodes.Count; i++) {
XmlNodeList appnodes =
for (int j=0; j < appnodes.Count; j++) {
// replace with new values
// record to make sure none are missing
XmlAttributeCollection attrColl = appnodes.Item(j).Attributes; XmlAttribute tmpNode = (XmlAttribute)attrColl.GetNamedItem("key"); XmlAttribute tmpNodeValue = (XmlAttribute)attrColl.GetNamedItem("value"); if (tmpNode.Value.Equals("setup")) {
// will be set to true later tmpNodeValue.Value = false"; issetup = true; } else if (tmpNode.Value.Equals("database")) { tmpNodeValue.Value = database; isdatabase = true; } else if (tmpNode.Value.Equals("datasource")) { tmpNodeValue.Value = datasource; isdatasource = true; } else if (tmpNode.Value.Equals("userid")) { tmpNodeValue.Value = userid; isuserid = true; } else if (tmpNode.Value.Equals("password")) { tmpNodeValue.Value = password; ispassword = true; } else if (tmpNode.Value.Equals("timeout")) { tmpNodeValue.Value = timeout; istimeout = true; } }