I created a Web API web service that’s part of a shrink wrapped application. The service has a web.config that the end user will need to configure some settings in.  Editing a web.config manually is, at best, annoying.

Man Screaming

If your app requires manual XML editing, then you failed

I usually provide a desktop app for editing the web.config file.  I want the user to be able to point and click as much of the settings as possible. It’s also possible for this web service to be deployed as multiple instances on the same server, so I wanted to make easier for the user to configure the files.

I wrote a simple WPF app that would let the user edit a specific type of web.config  and that user could edit the settings and not have to worry about the syntax issues that come with the angle bracket tax.  I’m a firm believer in Steve Krug’s “Don’t make me think” philosophy. And editing XML is about as far away as you can get from that.

Instead of hard coding the path to the web.config file I made the config editor a little smarter and gave it the ability to locate all instances of the web.config that it knows how to edit.   I created a helper class with a few methods that would return a list of web.config files with the full path.  That list was bound to the dropdown list and the code would load the correct web.config when the selection changed.

The first step was to locate all of the web.config files.  In the Microsoft.Web.Administration namespace, we have the ServerManager class.  The ServerManager class is documented as “Provides read and write access to the IIS 7 configuration system.” .  That’s exactly what I need.

Take the following method;

public List GetWebApiFolders()
{
    List folders = new List();

    ServerManager iisManager = new ServerManager();

    foreach (var s in iisManager.Sites)
    {
        foreach (var app in s.Applications)
        {
            foreach (var dir in app.VirtualDirectories)
            {
                if (IsWebApiFolder(dir.PhysicalPath))
                {
                    if (!folders.Contains(dir.PhysicalPath))
                        folders.Add(dir.PhysicalPath);
                }
            }
        }
    }

    return folders;
}

We iterate through each site in the Sites collection. Then for all of the apps for each site. Then for all of the virtual directories for each app. I call a method called IsWebApiFolder() and pass in the physical path to that virtual directory.  The IsWebApiFolder() method will return true if this folder contains a web.config that my config editor can edit.

Let’s take a look at IsWebApiFolder()

private Boolean IsWebApiFolder(string folderName)
{
    Boolean result = File.Exists(
      Path.Combine(folderName, "SomeCustomHandler.ashx"));

    if (result)
    {
        XDocument doc = 
          XDocument.Load(
           Path.Combine(folderName, "web.config"));

        var node = doc.Descendants("appSettings")
          .Elements("add")
          .Where(n => n.Attribute("key")
          .Value == "Crazy.App");

        result = node.Count() > 0;
    }

    return result;
}

The first thing it does is to look for a file with an uncommon name.  It doesn’t matter which file you  pick, just make it fairly unique to your app.  It could even be an empty text file named “ThisIsTheFooBar.txt”.  After finding a folder that has what could be my app’s files, I parse the web.config and look for a specific setting.  If it has that setting, then I’m pretty confident that I have found the right file. When I find the right file, I return true back to the caller, which then adds that file to the list of web.config files that can be edited.

Screaming Man image By Crosa (Flickr: Scream) [CC-BY-2.0], via Wikimedia Commons