One of the things which was not clear to me when IIS7 configuration system was written was how configuration system merges all the configuration data available and then decide what values are effective for the current request. One of confusions came from the fact that I assumed that IIS modules try to read the values for the current URL and then keep moving up till it finds the attribute explicitly defined in a configuration file. This is part true for the configuration system but never for the modules. All modules do is ask the configuration system for a merged view of a particular configuration section for a configuration path which usually corresponds to the URL of the requested page. If you are familiar with AhAdmin, this corresponds to the following call.
Section names are full section names as defined in schema.xml and configuration path is of the form “MACHINE/WEBROOT/APPHOST/Default Web Site/Application/VirtualDirectory/Folder/file.php”. Configuration system gives a merged view of the section for the configuration path passed in GetAdminSection call. Modules can ask for a non-merged view of a section as well using IAppHostConfigFile::GetAdminSection but this is not done in any of the modules which is shipped as part of IIS. If invalid configuration is detected (may be because xml is invalid or section is locked at parent level), configuration system returns an error to modules. Modules don’t try to read the configuration at parent level paths if see an error while reading configuration for current URL. Some modules do try to read the configuration at server/site level rather than configuration for current URL path. One reason for this is because some sections are supposed to be “AppHostOnly” and are valid at server level only. HttpCompression and isapiCgiRestrictionList sections are such sections and are marked “AppHostOnly” in the section definitions by IIS setup. If you define these sections at site level or below, configuration system will generate an error. You can get around this error by changing allowDefinition attribute in section definition of these sections but that won’t make modules read the section at levels below server. Another reason why modules sometimes don’t read configuration for current URL is that few properties cannot be varied per URL and are constant for an application pool. An example of such property is system.webServer/caching@maxCacheSize which defines maximum memory size which can be used by caching module. As this property is constant for an application pool, caching module just read this property at server level and not for request URL.
When a merged view of a section is requested, here is what happens in the configuration system. On call to IAppHostAdminManager::GetAdminSection, configuration system reads all configuration files up to the URL path starting with machine.config, root web.config, redirection.config, and applicationHost.config. If allowSubDirConfig property of virtual directory is set to false, configuration system don’t read configuration files below virtual directory paths. As soon as the configuration files are read, few global validations are performed which are done irrespective of which section is requested. If any of global validations fail, configuration system generates an error as soon as it encounters one. Here are the global validations which are made by the configuration system.
è Schema errors, invalid or duplicate section groups or section definitions are global errors.
è Multiple <configSections>, <configProtectedData> elements in applicationHost.config or if they are not the first and second child elements of the root <configuration> in applicationHost.config, it is reported as error.
è Errors in sites section are seen when requesting any section as configuration system reads this section to get list of virtual directories.
è If configuration system finds a configuration file which doesn’t contain a <configuration> tag or which contains invalid xml, it will result in a configuration error regardless of which section is requested.
è If a section for which section definition is missing is used in a configuration file, a configuration error is generated.
è A section defined more than once for a configuration path is treated as global error. If none of the global errors are seen by the configuration system, it proceeds to build merged view of the requested section.
Configuration system starts from applicationHost.config and builds a IAppHostConfigElement object based on defaults defined in schema. It then reads the section at root level using IAppHostConfigFile::GetAdminSection and also reads the section under all location paths defined in that file using IAppHostConfigLocation::get_Item and replace existing values with new ones whenever a property which is explicitly defined is seen. If a section level error is encountered a configuration error is generated. Examples of errors which are generated only when requesting a section with error are invalid attribute/element, section locked at parent level, duplicate element in a collection, missing required attributes etc. This makes configuration system report errors at root first followed by errors in sections defined under location paths and then sections in web.config files at lower levels. Child elements and collections are handled similarly. Add/remove/clear for collections gets evaluated from root to the current path. If a duplicate element is found for a collection at any path till current path, an error is generated.
I hope this blog helps you debug configuration errors more easily and understand what to expect from IIS configuration system. This blog post might be little difficult to understand. Let me know if you have some suggestions to make it more readable.