Wednesday, April 04, 2007 3:04 PM bart

Extending IIS 7.0 - Part 3: Extending and using the configuration system


Note: This post is part of the follow-up for the Developer & IT Pro Days 2007 session entitled "Internet Information Services (IIS) 7.0 - End-to-End Overview of Microsoft's New Web Application Server". Attendees will be able to download the slides and will get the video recording of the entire session as well. Using these posts, attendees should be capable of reproducing the entire demo part of the session. Furthermore, others who didn't attend the session will be able to get a better idea of what IIS 7.0 provides by following the demo steps outlined in these posts. In order to implement the demos, one should have IIS 7.0 installed on Windows Vista (or Windows "Longhorn" Server).



In the previous part of this series, a simple HTTP handler was created to resize images dynamically and to put copyright messages on images dynamically. Of course, we don't want to hardcode all of the settings for these copyright messages, including the color and the message itself. Instead, it's a much more desirable to have these values come from some kind of configuration. In today's post, we'll focus on the configuration system in IIS 7.0 in more detail.


IIS 7.0 Configuration

As you probably know, IIS 6.0 and earlier stored their configuration settings in a centralized database called the metabase. Before the advent of IIS 6.0, the metabase was a binary file; as of IIS 6.0, it's also possible to use an XML-based metabase. As you can imagine, centralization of the configuration is quite easy from the web server developer's point of view, but for the end-users the story is quite different. In case (re)configuration of a deployed application is required, one has to make a call to the support department of the company or to the hosting company in order to apply the change to the app's or site's configuration, which is far from ideal. Even for simple settings like the order of the default pages (default.aspx, default.htm, ...) or custom error pages, one has to touch the metabase. Luckily, different (web-based) tools were created to overcome this issue, but there's no such thing as a unified approach to configuration.

In contrast to the IIS metabase story, there's the power of the web.config file in the wonderful world of ASP.NET, which makes it possible to xcopy-deploy settings together with the application's binaries and static content. Furthermore, this approach allows for easy overriding of settings in subapplications or for given "locations" by means of a hierarchy of web.config files, stored in subdirecties.

IIS 7.0 gets rid of the metabase (the metabase is DEAD) and replaces it by a hierarchical configuration mechanism based on web.config files, that also allows for delegation. This means that IT admins can control which sections of the configuration can be overriden by who. For example, you might allow people to register their own handlers, while you don't like them to hook up a module or touch the authentication configuration. The picture below illustrates the hierarchical model:

In the previous posts, we've already been faced with the web.config file repeatedly. Today, we'll extend the schema of the configuration with our own entries and we'll see how the IIS 7.0 APIs allow for easy querying of settings.


Extending and testing the schema

Let's get started by extending the schema with a custom definition. In order to do so, follow the steps outlined below. Continue from the result obtained in the previous post:

  1. Inside Visual Studio 2005, running as Administrator, right-click the Solution node in Solution Explorer and choose Add, New Item...:

  2. Choose XML file as the template and specify ImageCopyright.xml as the file name:

  3. In the XML file, put the following schema definition:
    <configSchema> <sectionSchema name="system.webServer/imageCopyright"> <attribute name="enabled" type="bool" defaultValue="false" /> <attribute name="message" type="string" defaultValue="Your Copyright Message" /> <attribute name="color" type="string" defaultValue="Yellow" /> </sectionSchema> </configSchema>

    This schema is hooked up in the system.webServer/imageCopyright section (see sectionSchema) and has three attributes specified, all with their type and the default value specified.
  4. Save the schema via File, Save ImageCopyright.xml As... and go to the %windir%\system32\inetsrv\config\schema folder. Save the file with the original file name:

    Notice the other files that reside in this folder, including the IIS schema, the WCF schema and the ASP.NET schema. Open these files to get a better idea of the flexibility the IIS 7.0 configuration schema definition capability offers, including validation settings, the use of enums and flags, element nesting, uniqueness checks, etc.
  5. Now go to File, Open, File (CTRL-O) and open the ApplicationHost.config file from %windir%\system32\inetsrv\config. This is the place where IIS 7.0 keeps references to the registered schemas. That is, putting a schema definition file in the config\schema folder isn't enough to make it work. Additionally, you need to register the schema with the server's configuration. To do this, locate the <configuration>/<configSections>/<sectionGroup name="system.webServer"> section and add a section element to it, as shown below:
    <sectionGroup name="system.webServer"> <section name="imageCopyright" overrideModeDefault="Allow" />

    Make sure that the imageCopyright entry isn't misspelled, casing matters!
  6. Now, open a command line running as administrator (right-click the shortcut to cmd.exe, choose Run as Administrator), go to the %windir%\system32\inetsrv folder and execute appcmd list config -section:system.webServer/imageCopyright. The result should look like this:

    This indicates that IIS 7.0 has found the entry in the schema together with the schema definition inside the schema directory. If the result doesn't look as bright as the one shown above, revisit steps 3 to 5 and check all spelling carefully.
  7. At this point in time, we can already apply settings to a web.config file by changing the web.config file either manually or via some tool like appcmd. As an example, execute the following commands:

    appcmd set config "Default Web Site" -section:system.webServer/imageCopyright -enabled:true -color:Blue
    appcmd set config "Default Web Site/devdays" -section:system.webServer/imageCopyright -color:Red -message:"Copyright (C) Developer & IT Pro Days 2007"

  8. Check whether the settings were applied successfully by taking a look at the %SystemDrive%\inetpub\wwwroot\web.config file as well as the %SystemDrive%\inetpub\wwwroot\devdays\web.config file:


The settings applied in step 7 use the concept of overriding. If you'd request an image on the Default Web Site root level, the handler would be enabled and the color would be set to Blue, overriding the default values of enabled=false and color=Yellow. However, the message would still be "Your Copyright Message" (see step 3). One level deeper in the hierarchy, inside the devdays app, the color setting has been overridden to Red and the message has been set to "Copyright (C) Developer & IT Pro Days 2007". We'll see the result in a minute when we've changed our code to incorporate the settings.


Consuming the configuration in code

The next step in our configuration journey is to use the settings in our handler effectively. Let's take a look, starting from the handler's implementation from the previous post:

  1. In the web site project, right-click and choose Add Reference...

    Go to the Browse tab and navigate to %windir%\system32\inetsrv. Select Microsoft.Web.Administration.dll and click OK:

  2. At the bottom of the PictureHandler.cs file, outside the class definition, add the following class:
    class PictureHandlerSettings : ConfigurationSection { public bool Enabled { get { return (bool)base["enabled"]; } set { base["enabled"] = value; } } public string Message { get { return (string)base["message"]; } set { base["message"] = value; } } public System.Drawing.Color Color { get { return System.Drawing.Color.FromName((string)base["color"]); } set { base["color"] = value.Name; } } }

    This is a strongly-typed configuration class definition which we'll use to get our settings back. Instead we could also get the settings without a class wrapper, but this approach pays off over time; for example, take a look at the added functioanlity in the Color property to convert a string representation of the color to a Color instance and vice versa. In order for this code to work correctly, you'll need to import the Microsoft.Web.Administration namespace:

  3. Next, locate the ProcessRequest method of the handler's implementation and add a few lines of code at the top of the method as shown below:
    public void ProcessRequest(HttpContext context) { ServerManager mgr = new ServerManager(); Configuration config = mgr.GetWebConfiguration( System.Web.Hosting.HostingEnvironment.SiteName, context.Request.Path); PictureHandlerSettings settings = (PictureHandlerSettings)config.GetSection( "system.webServer/imageCopyright", typeof(PictureHandlerSettings));

    This code connects to the IIS 7.0 machine by means of the ServerManager instance, then retrieves the configuration that applies to the current site (HostingEnvironment.SiteName) and the current request (Request.Path) and finally retrieves the settings section for system.webServer/imageCopyright using the strongly typed settings class from step 2. This is incredibly powerful indeed since it does all of the overriding stuff for you. For example, for the Default Web Site root, the settings would be combined from applicationHost.config and web.config since only the enabled attribute was overridden on the web site root's level. Similarly, settings form the Default Web Site root and the devdays application are combined when requesting something like http://localhost/devdays/waterfall.jpg.
  4. Finally, change the ProcessRequest method to consume the settings. The complete code listing for ProcessRequest looks like this (changes marked in comments):
    public void ProcessRequest(HttpContext context) { ServerManager mgr = new ServerManager(); Configuration config = mgr.GetWebConfiguration( System.Web.Hosting.HostingEnvironment.SiteName, context.Request.Path); PictureHandlerSettings settings = (PictureHandlerSettings)config.GetSection( "system.webServer/imageCopyright", typeof(PictureHandlerSettings)); string path = context.Request.PhysicalPath; Image img = Bitmap.FromFile(path); string p = context.Request.QueryString["percent"]; int percent; if (p != null && int.TryParse(p, out percent) && percent > 0 && percent < 100) { Image t = img; img = new Bitmap(img.GetThumbnailImage(img.Width * percent / 100, img.Height * percent / 100, null, IntPtr.Zero)); t.Dispose(); } //<NEW> if (settings.Enabled) { //string msg = "Copyright Microsoft (C) 2007"; string msg = settings.Message; using (Graphics g = Graphics.FromImage(img)) { Font f = new Font("Arial", 10, FontStyle.Bold); SizeF s = g.MeasureString(msg, f); PointF pos = new PointF(img.Width - s.Width - 5, img.Height - s.Height - 5); //g.DrawString(msg, f, Brushes.Yellow, pos); g.DrawString(msg, f, new SolidBrush(settings.Color), pos); } } //</NEW> img.Save(context.Response.OutputStream, ImageFormat.Jpeg); img.Dispose(); }

    Notice we didn't disable the zooming functionality if the enabled attribute is set to false.

  5. Compile the application by pressing CTRL-SHIFT-B and navigate to http://localhost/devdays/waterfall.jpg?percent=30 in the browser. Observe that the settings from step 7 (above) have taken effect:

  6. Feel free to play around with the configuration and the overriding functionality.

The code for this post can be downloaded over here. In the next post in this series, we'll put the crowne on our work by extending the IIS Manager with a module that allows easy configuration for our IT Pro friends. Stay tuned! | Digg It | Technorati | Blinklist | Furl | reddit | DotNetKicks

Filed under:


# Extending IIS 7.0 - Part 4: Creating a custom module for IIS Manager

Wednesday, April 04, 2007 3:08 PM by B# .NET Blog

Note: This post is part of the follow-up for the Developer &amp; IT Pro Days 2007 session entitled "Internet

# Extending IIS 7.0 - Part 4: Creating a custom module for IIS Manager

Wednesday, April 04, 2007 3:36 PM by B# .NET Blog

Note: This post is part of the follow-up for the Developer &amp; IT Pro Days 2007 session entitled "Internet