Tuesday, July 31, 2007

Extending IIS7 Schema for Configuration

Last time we talked about IIS7 schema and how IIS7 uses it itself.  Well, one of the exciting changes that comes with IIS7 is the ability to easily customize the schema that ships with IIS7 to add things like our own configuration settings.  Furthermore, this is just a configuration process now as we no longer have to write any custom code to use it!

Previously, we could only extend our web.config if we also wrote an IConfigurationSectionHandler class (in v1.x) or a ConfigurationSection (in v2.x) that did the work of translating the XML node into something useful (maybe a strongly-typed class).  In this post, I am going to be talking about creating static configuration.

Creating our Schema

Let's walk through a quick sample to show how all this works.  Create a new .xml file in your text editor of choice and enter the following:

<configSchema>
  <sectionSchema name="system.webServer/userCredentials">
    <attribute name="username" type="string" />
    <attribute name="password" type="string" />
  </sectionSchema>
</configSchema>

Notice that we are defining a sectionSchema tag that tells IIS7 that we are going to add our new section called 'userCredentials' under the main IIS7 'system.webServer' section grouping.  We are using two attributes for our new section that will hold the user name and password.  Save this file as 'usercredentials_schema.xml' in the '%windir%\system32\inetsrv\config\schema' directory.

Next, we need to tell IIS7 where this section can apply.  You can do this a few ways, by simply editing the 'applicationHost.config' file to add the new section, or via code (scripting or managed code).  For our purposes, it is probably easiest to just manually add the "section" element as below:

<sectionGroup name="system.webServer">
    <!-- Add this line below-->
    <section name="userCredentials" />

This setting tells IIS7 where our schema applies and it has other attributes that can limit where this can be set or if it can be delegated for instance. 

Setting the Configuration

Once your configuration has been added, you can set this new setting in your configuration files.  Here is an example web.config:

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <system.webServer>
      <userCredentials username="superuser" password="password" />
    </system.webServer>
</configuration>

You can manually put this into your web.config file of course, but it is much easier to just use the appcmd.exe tool to do this.  Appcmd also has the additional benefit of doing it right every time and adjusting for schema changes (as we will see later).  From the command line:

%windir%\system32\inetsrv\appcmd set config "Default Web Site/MyApp" -section:userCredentials -username:"superuser" -password:"password"

This will update the web.config file located under the site called "Default Web Site" in the application called "MyApp" and set the new userCredentials schema and the username and password attributes.  This is much easier with practice than manually editing the files.

Reading the Configuration

Your application can now easily read back this information using the new Microsoft.Web.Administration API .

ConfigurationSection section = 
    WebConfigurationManager.GetSection("system.webServer/userCredentials");
string username = (string)section["username"];
string password = (string)section["password"];

We didn't have to write our own section handler or configuration section in order to do this.

Protecting the Configuration

Clever readers of course will shout, "I would never, ever, put a password in my configuration files, that would be [censored]!".  Of course, they are right.  Wouldn't it be nice if there was an easy way to have IIS7 encrypt and manage sensitive information for you?  Well, if you simply update the definition of the 'password' attribute we defined initially like this, you can get it:

<attribute name="password" type="string" encrypted="true" />

Notice, we just added the "encrypted" attribute to our "attribute" element.  Once again, if we run the exact same command line as before to set the values, we get our new encrypted behavior instead.

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
  <system.webServer>
        <userCredentials username="superuser"
                         password="[enc:RsaProtectedConfigurationProvider:jAA...wqBz0=:enc]" />
  </system.webServer>
</configuration>

IIS7 will still be able to read this value using the exact same code as before, but this time it is strongly encrypted and not stored in cleartext. Pretty convenient, no?

Summary

I hope this post has given you a flavor of the new configuration and schema that ships with IIS7 and prepares you to take the next step and leverage it to simplify your own configuration needs.