ptg 1534 CHAPTER 34 Configuring Applications NOTE If you open the SDK Command Prompt or the Visual Studio Command Prompt, you don’t need to navigate to the Microsoft.NET folder to execute the aspnet_regiis tool. After you make this modification to a remote server, you can retrieve (and modify) config- uration settings on the remote server by using one of the Open methods exposed by the WebConfigurationManager class. For example, the page in Listing 34.13 contains a form that enables you to enter a server, username, and password. When you submit the form, the page connects to the remote server and retrieves its Machine.config file. The page displays the current value of the remote server’s authentication mode (see Figure 34.8). FIGURE 34.8 Changing configuration settings for a remote server. LISTING 34.13 ShowConfigRemote.aspx <%@ Page Language=”C#” %> <%@ Import Namespace=”System.Web.Configuration” %> <!DOCTYPE html PUBLIC “-//W3C//DTD XHTML 1.0 Transitional//EN” “http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd”> <script runat=”server”> protected void btnSubmit_Click(object sender, EventArgs e) { try From the Library of Wow! eBook ptg 1535 Using the Configuration API 34 { Configuration config = WebConfigurationManager.OpenMachine ➥ Configuration(null, txtServer.Text, txtUserName.Text, txtPassword.Text); AuthenticationSection section = (AuthenticationSection)config. ➥ GetSection(“system.web/authentication”); lblAuthenticationMode.Text = section.Mode.ToString(); } catch (Exception ex) { lblAuthenticationMode.Text = ex.Message; } } </script> <html xmlns=”http://www.w3.org/1999/xhtml” > <head id=”Head1” runat=”server”> <title>Show Config Remote</title> </head> <body> <form id=”form1” runat=”server”> <div> <asp:Label id=”lblServer” Text=”Server:” AssociatedControlID=”txtServer” Runat=”server” /> <br /> <asp:TextBox id=”txtServer” Runat=”server” /> <br /><br /> <asp:Label id=”lblUserName” Text=”User Name:” AssociatedControlID=”txtUserName” Runat=”server” /> <br /> <asp:TextBox id=”txtUserName” Runat=”server” /> <br /><br /> <asp:Label id=”lblPassword” Text=”Password:” AssociatedControlID=”txtPassword” Runat=”server” /> From the Library of Wow! eBook ptg 1536 CHAPTER 34 Configuring Applications <br /> <asp:TextBox id=”txtPassword” TextMode=”Password” Runat=”server” /> <br /><br /> <asp:Button id=”btnSubmit” Text=”Submit” OnClick=”btnSubmit_Click” Runat=”server” /> <hr /> Authentication Mode: <asp:Label id=”lblAuthenticationMode” Runat=”server” /> </div> </form> </body> </html> You can use the page in Listing 34.13 even when the web server is located in some distant part of the Internet. You can enter a domain name or IP address in the server field. Using the Configuration Class When you use one of the WebConfigurationManager Open methods—such as the OpenMachineConfiguration() or OpenWebConfiguration() methods—the method returns an instance of the Configuration class. This class supports the following properties: . AppSettings—Returns the appSettings configuration section. . ConnectionStrings—Returns the connectionStrings configuration section. . EvaluationContext—Returns an instance of the ContextInformation class that enables you to determine the context of the configuration information. . FilePath—Returns the physical file path to the configuration file. . HasFile—Returns True when there is a file that corresponds to the configuration information. . Locations—Returns a list of locations defined by the configuration. . NamespaceDeclared—Returns True when the configuration file includes a namespace declaration. From the Library of Wow! eBook ptg 1537 Using the Configuration API 34 . RootSectionGroup—Returns the root section group. . SectionGroups—Returns the child section groups contained by this configuration. . Sections—Returns the child sections contained by this configuration. The Configuration class also supports the following methods: . GetSection—Enables you to return the specified configuration section. . GetSectionGroup—Enables you to return the specified configuration section group. . Save—Enables you to save any configuration changes. . SaveAs—Enables you to save the configuration as a new file. A configuration file contains two basic types of entities: section groups and sections. For example, the <system.web> element in a configuration file represents a section group. The <system.web> section group contains child sections such as the <authentication> and <httpRuntime> sections. You can use the Configuration.RootSectionGroup property to get the primary section group in a configuration file. You can use the SectionGroups property to return all of a section group’s child section groups and the Sections property to return all of a section group’s child sections. For example, the page in Listing 34.14 recursively displays the contents of the Machine.config file in a TreeView control (see Figure 34.9). FIGURE 34.9 Displaying all configuration sections from the system.web configuration section group. From the Library of Wow! eBook ptg 1538 CHAPTER 34 Configuring Applications LISTING 34.14 ShowConfigContents.aspx <%@ Page Language=”C#” %> <%@ Import Namespace=”System.Web.Configuration” %> <!DOCTYPE html PUBLIC “-//W3C//DTD XHTML 1.0 Transitional//EN” “http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd”> <script runat=”server”> void Page_Load() { // Add first node TreeNode parentNode = new TreeNode(“configuration”); TreeView1.Nodes.Add(parentNode); // Start from the root section group Configuration config = WebConfigurationManager.OpenMachineConfiguration(); // Show child section groups AddChildSectionGroups(parentNode, config.RootSectionGroup); // Show child sections AddChildSections(parentNode, config.RootSectionGroup); } private void AddChildSectionGroups(TreeNode parentNode, ConfigurationSectionGroup parentConfigSectionGroup) { foreach (ConfigurationSectionGroup configSectionGroup ➥ in parentConfigSectionGroup.SectionGroups) { TreeNode childNode = new TreeNode(configSectionGroup.SectionGroupName); parentNode.ChildNodes.Add(childNode); AddChildSectionGroups(childNode, configSectionGroup); AddChildSections(childNode, configSectionGroup); } } private void AddChildSections(TreeNode parentNode, ConfigurationSectionGroup parentConfigSectionGroup) { foreach (ConfigurationSection configSection in parentConfigSectionGroup.Sections) { From the Library of Wow! eBook ptg 1539 Using the Configuration API 34 TreeNode childNode = new TreeNode(configSection.SectionInformation.Name); parentNode.ChildNodes.Add(childNode); } } </script> <html xmlns=”http://www.w3.org/1999/xhtml” > <head id=”Head1” runat=”server”> <title>Show Config Contents</title> </head> <body> <form id=”form1” runat=”server”> <div> <asp:TreeView id=”TreeView1” Runat=”server” /> </div> </form> </body> </html> Modifying Configuration Sections You can use the WebConfigurationManager class not only when opening a configuration file to read the values of various configuration settings, but you also can use the WebConfigurationManager class to modify existing configuration settings or add new ones. The Configuration class supports two methods for saving configuration information: the Save() and SaveAs() methods. For example, the page in Listing 34.15 enables you to turn on and off debugging for an application (see Figure 34.10). From the Library of Wow! eBook ptg 1540 CHAPTER 34 Configuring Applications LISTING 34.15 ShowConfigModify.aspx <%@ Page Language=”C#” %> <%@ Import Namespace=”System.Web.Configuration” %> <!DOCTYPE html PUBLIC “-//W3C//DTD XHTML 1.0 Transitional//EN” “http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd”> <script runat=”server”> void Page_Load() { if (!Page.IsPostBack) { Configuration config = WebConfigurationManager.OpenWebConfiguration(Request.ApplicationPath); CompilationSection section = (CompilationSection)config.GetSection(“system.web/compilation”); chkDebug.Checked = section.Debug; } } protected void btnUpdate_Click(object sender, EventArgs e) { FIGURE 34.10 Modifying the value of the Debug configuration setting. From the Library of Wow! eBook ptg 1541 Using the Configuration API 34 Configuration config = WebConfigurationManager.OpenWebConfiguration(Request.ApplicationPath); CompilationSection section = (CompilationSection)config.GetSection(“system.web/compilation”); section.Debug = chkDebug.Checked; config.Save(ConfigurationSaveMode.Modified); } </script> <html xmlns=”http://www.w3.org/1999/xhtml” > <head id=”Head1” runat=”server”> <title>Show Config Modify</title> </head> <body> <form id=”form1” runat=”server”> <div> <asp:CheckBox id=”chkDebug” Text=”Enable Debugging?” Runat=”server” /> <br /><br /> <asp:Button id=”btnUpdate” Text=”Update” OnClick=”btnUpdate_Click” Runat=”server” /> </div> </form> </body> </html> The page in Listing 34.15 loads the application root Web.config file with the help of the OpenWebConfiguration() method. (The Nothing parameter causes the root Web.config file to be loaded.) Next, the value of the Compilation.Debug property is modified. Finally, the Save() method is called to save this change. When you call the Save() method, you can pass a ConfigurationSaveMode parameter to the method. This parameter can have the following values: . Full—Saves all configuration settings, regardless of whether they have been modified. . Minimal—Saves only those configuration settings that are different from their inherited value. . Modified—Saves only those configuration settings that have been modified. From the Library of Wow! eBook ptg 1542 CHAPTER 34 Configuring Applications To use the Save() or SaveAs() methods, the account associated with the page must have Write permissions for the folder in which the configuration file is saved. By default, when pages are served from Internet Information Server, ASP.NET pages execute in the security context of the NETWORK SERVICE account (for Windows Server 2003) or the ASPNET account (for other operating systems). By default, neither of these accounts have permis- sions to save configuration changes. NOTE To ma ke things more confusin g , when pages are ser ved from the web ser ver inc luded with Visual Web Developer, the pages are always served in the security context of the current user. There are multiple ways that you can get around this permission problem. First, remember that you can use many of the methods of the WebConfigurationManager class from a console application or a Windows Forms application. If you build this type of application, you can sidestep these security issues. Another option is to enable per-request impersonation for your ASP.NET application. When impersonation is enabled, an ASP.NET page executes within the security context of the user making the page request. If the user account has permissions to write to the file system, the page has permissions to write to the file system. The web configuration file in Listing 34.16 enables impersonation. LISTING 34.16 Web.config <?xml version=”1.0”?> <configuration> <system.web> <identity impersonate=”true” /> </system.web> </configuration> If you add the configuration file in Listing 34.16 to the same folder that contains the file in Listing 34.15, you can make modifications to configuration files. WARNING Most changes to a configuration file result in an application restart. When an ASP.NET application restarts, all data stored in memory is blown away. For example, all data cached in the Cache object or Session state is lost. Also keep in mind that allowing remote configuration changes on a production server can result in a big security hole, so this type of arrangement is only advisable for development and testing environments. From the Library of Wow! eBook ptg 1543 Using the Configuration API 34 Provisioning a New Website When you provision new websites, you often need to create a new virtual directory. The Configuration API doesn’t provide you with any help here; however, you can create new virtual directories (and applications) by taking advantage of the classes in the System.DirectoryServices namespace. These classes enable you to use Active Directory Services Interface (ADSI) to modify properties of Internet Information Server. NOTE You c an also manipulate Inter net I nform ation Ser ver proper ties by using Wi ndows Management Instrumentation (WMI). For more information, see the topic “Using WMI to Configure IIS” at the Microsoft MSDN website (msdn.microsoft.com). Before you can use the classes from the System.DirectoryServices namespace, you need to add a reference to the System.DirectoryServices.dll assembly. In Visual Web Developer, select Website, Add Reference, and select System.DirectoryServices.dll. For example, the page in Listing 34.17 enables you to provision a new ASP.NET applica- tion (see Figure 34.11). The page creates a new virtual directory and a new application. The page also creates a new web configuration file in the virtual directory that contains the default language and debug settings you specify. FIGURE 34.11 Creating a new ASP.NET application. From the Library of Wow! eBook . Forms application. If you build this type of application, you can sidestep these security issues. Another option is to enable per-request impersonation for your ASP. NET application. When impersonation. example, the page in Listing 34. 17 enables you to provision a new ASP. NET applica- tion (see Figure 34. 11). The page creates a new virtual directory and a new application. The page also creates. (see Figure 34. 10). From the Library of Wow! eBook ptg 1 540 CHAPTER 34 Configuring Applications LISTING 34. 15 ShowConfigModify.aspx <%@ Page Language=”C#” %> <%@ Import Namespace=”System.Web.Configuration”