作者:Tobin Titus
介绍
IIS 7 及更高版本中的配置系统与以前版本的 IIS 大有不同,并且其中一些(但并非全部)是基于 .NET Framework 配置系统的概念。 其范围跨越整个 Web 服务器平台(IIS,ASP.NET),并充当 IIS 管理“堆栈”的核心。 本文档介绍了配置系统的设计和体系结构,并在最低级别(本机代码)的入口点介绍了系统的可编程接口。
在运行时很少有实现配置系统的“移动部件”。 配置系统作为一个库实现,该库在客户端应用程序中运行,并与磁盘上的持久存储进行交互。 存储简单说就是文件系统上的一个文件或一组文件。 文件的格式为 XML。 用户可以随时手动编辑文件(如果需要)并且系统会自动获取更改。 没有专门的模型来执行标准操作,如保护设置、备份设置、移动设置,甚至使用新设置扩展系统。 系统严重依赖文件系统,从而简化部署 Web 应用程序和服务的配置等任务。
注意
与以前版本的 IIS 中一样,没有集中式配置服务。 从存储中读取大块数据时,尤其是在启动时,这可以显著提高性能,因为不需要进行进程间通信和缓冲区复制。
安装 IIS 后,有几项配置立即需要设置:
- WAS (Windows 激活服务):读取应用程序池、站点和其他设置的全局默认值。
- 工作进程中的 Web 服务器核心和模块:激活以处理请求时,读取控制其行为的配置设置。
- WMI 提供程序:IIS 脚本接口提供程序在内部使用配置系统来获取和设置设置。
- AppCmd.exe:IIS 命令行工具在内部使用配置系统来获取和设置设置。
- UI:IIS 管理框架在内部使用配置系统来获取和设置设置。
- 旧版:即使用 ABO、ADSI 和 IIS 6.0 WMI 提供程序等接口的应用程序和脚本,其以间接方式使用配置系统(利用某一组件将旧版 ABO API 和模型映射到新配置模型)。 状态始终保持到新的配置系统中。
有几个接口提供对配置设置的访问权限:
接口 | 访问的目标对象 |
---|---|
使用文本编辑器或脚本手动编辑文件。 | 所有配置文件(如果文件 ACL 允许)。 |
本机代码和托管代码中的配置 API。 | 所有配置文件(如果文件 ACL 允许)。 |
基于配置系统(例如 IIS WMI 脚本提供程序、UI 或 appcmd.exe 工具)的更高级别抽象。 | 所有配置文件(如果文件 ACL 和 UI 委派策略允许)。 |
旧版 IIS 接口,如 ABO、ADSI、IIS 6.0 WMI 提供程序。 | 仅限根 IIS 配置文件和旧版 (IIS 6.0) 设置。 .NET Framework 设置和 IIS 7.0 及更高版本的设置不会向这些接口公开。 |
旧版 .NET Framework 接口,如 System.Configuration。 | 仅限 machine.config 和 web.config 文件中的 .NET Framework 2.0 配置设置。 |
配置级别
URL 命名空间的每个级别都有关联的配置。 给定级别的配置将继承到子级别,除非被子级专门替换。 实现按 URL 配置的一种简单方法是在映射到虚拟路径的物理文件系统文件夹中使用 web.config 文件。 在根级别(计算机级别),应使用单独的文件,具体取决于配置节组(稍后将在文档中定义;目前可将其视为包含配置的 XML 元素的名称):
节组 | 说明 | 根文件 |
---|---|---|
system.applicationHost | Windows 激活系统:进程模型 | system32\inetsrv\config\applicationhost.config |
system.webServer | IIS:Web 服务器 | system32\inetsrv\config\applicationhost.config |
system.web | ASP.NET | Windows\microsoft.net\framework\v2.0.50727\config\web.config |
system.* | 其他 .NET Framework | Windows\microsoft.net\framework\v2.0.50727\config\machine.config |
[Microsoft 其他] | Microsoft 其他 | Windows\microsoft.net\framework\v2.0.50727\config\machine.config |
[自定义] | 第三方 | machine.config 或 root web.config 或 applicationHost.config,最多为第三方/客户 |
有时不需要 web.config 文件,或者无法使用。 示例:
- 安全性:有时,计算机管理员希望能够控制服务器上的任何位置的配置。 使用内容目录中的 web.config,对这些内容目录具有写访问权限的站点级管理员(或应用程序开发人员)可以对 Web.config 文件进行 xcopy(或 FTP,或以其他方式修改),这就违反了所要求策略。
- 远程更改通知:内容目录位于远程 (UNC) 共享上,使用 Web.config 会产生性能、可伸缩性或其他问题。 例如,某些非 Windows 后端文件系统不支持 Windows 预期的文件更改通知方式。 另一个示例:系统维护与许多远程目录的打开连接,以便监视对文件的更改,并且它消耗了服务器上的过多资源,从而导致性能问题。
- 单点管理:为了便于配置管理、发现和故障排除,计算机管理员希望根级别的一个文件包含层次结构所有级别的所有配置。 实际上,全局级别将有 3 个文件:用于 .NET Framework 配置设置的 machine.config 和 root web.config,以及用于 IIS 配置设置的 applicationHost.config。 这不止是让层次结构中的每个级别都有自己的 web.config 文件那么简单。
- 共享配置:指向同一物理文件夹的多个虚拟路径,这些虚拟路径共享该文件夹中的同一个 web.config。 显然,此 web.config 文件不能用于为不同的路径指定不同配置。
- 特定于文件的配置:Web.config 文件应用于整个文件夹,即应用于该文件夹中的所有文件。 要为特定文件指定不同配置,应使用另一种方法。
配置层次结构中的 web.config 文件的替代方法是位置标记,这将在下一章节中介绍。
位置标记
位置标记用于指定特定于路径的配置,这样就无需将文件夹中的 Web.config 文件映射到该虚拟路径。 路径的位置标记在配置层次结构中的父级别中设置,并被视为位于该父级别。 当涉及到锁定语义以及哪个级别可以指定哪些节时,这一点很重要。
位置标记中的主要属性是“path”。 值可以是:
- “.”(或 ""):表示当前级别。 典型位置路径在全局级别设置,因此“.”表示全局级别;但是,可以在配置文件层次结构中的任意位置设置位置标记。 如果未设置“path”,则默认值也是“.”。
- “sitename”:特定站点的根应用程序。
- “sitename/application”:特定站点的特定应用程序。
- “sitename/application/vdir”:特定站点的特定应用程序的特定虚拟目录。
- “sitename/application/vdir/physicaldir”:特定的物理目录。 路径可能更为复杂,格式为“sitename/app/vdir/p1/p2/p3”。
- “sitename/application/vdir/file.ext”:特定文件。 路径可能更为复杂,格式为“sitename/app/vdir/p1/p2/file.ext”,也可能是不太复杂的格式,比如“sitename/app/file.ext”或“sitename/file.ext”。
单个配置文件中可以有多个位置标记,但这些位置标记不能引用相同的路径(除非引用不同的节)。 但可以引用子路径,以便每个位置标记引用另一个位置标记的子路径。 位置标记的顺序对配置系统来说无关紧要,但对用户文件可读性至关重要。
<location path="."> <system.webServer> <defaultDocument enabled="false"/> </system.webServer> </location>
<location path="MySite"> <system.webServer> <defaultDocument enabled="true"/> </system.webServer> </location>
<location path="MySite/YourApp/images"> <system.webServer> <defaultDocument enabled="false"/> </system.webServer> </location>
设置的组织方式
在配置文件中,根据名为“节”的单元,以结构化方式组织设置。 配置节是一组逻辑相关的设置,可以整体部署或整体从系统注销,并且通常由一个服务器模块使用。
换句话说,在工作进程中运行的几乎每个运行时模块都有相应的配置节。 配置节也是扩展性的单元:将新设置添加到配置架构是向其添加一个或多个节来完成的。
节无法嵌套。 在体系结构上,节是彼此独立的(在大多数情况下),这意味着它们不会彼此交叉引用。
这些节进一步分组到逻辑相关的集合中,称为“节组”。 节组不是部署单元、注册或其他任何实质性操作(例如锁定、加密)。 它们中没有设置。 其用途是进一步构建设置的组织,并避免配置节的长列表。
它们用于生成设置的层次结构,因此它们之间确实有关系(父/子级)。 换句话说,可以嵌套节组。 给定节始终属于一个节组,不能包含其他节(或节组)。 给定节组可能属于父节组,并且可能包含零个或多个子节组。 它通常包含多个节,否则它就没有存在的必要(但是,客户无论出于何种原因,都可以通过创建只有一个节的自己的节组来扩展架构)。
下面是演示节和节组的示例:
<!-- section group for web server configuration -->
<system.webServer>
<!-- section group for web server security configuration -->
<security>
<!-- section group for web server authentication configuration -->
<authentication>
<!-- three sections for authentication -->
<basicAuthentcation ... />
<windowsAutnentication ... />
<anonymousAuthentication ... />
</authentication>
</security>
</system.webServer>
每个节都有一个名称。 短名称是节本身的名称,长名称是全名,包括包含的所有节组。 例如,“windowsAuthentication”的全名是“system.webServer/security/authentication/windowsAuthentication”。 此分层组织允许将来创建具有相同名称的节(和节组),但在不同的节组下。
组织 <==> XML 映射
配置的持久性格式为 XML;因此,描述配置组织单位与 XML 术语之间的映射非常有用。 节组和节是 XML 元素。 在一个节中,这些设置被组织为与 XML 术语密切相关的较小单元:
配置单位 | XML 术语 | 说明 |
---|---|---|
配置元素 | XML 元素 | 包含其他子单元;没有值。 |
配置集合 | XML 元素 | 元素的专用案例:包含一组 add/remove/clear 格式的元素。 |
配置属性 | XML 属性 | 仅包含一个值;不包含子单元。 |
下面是 applicationHost.config 的示例:
<!-- "windowsAuthentcation" is a configuration section (XML element). -->
<!-- "enabled" is a configuration property (XML attribute). -->
<windowsAuthentication enabled="true">
<!-- "providers" is a configuration collection (XML element). -->
<providers>
<!-- Two configuration elements (XML elements). -->
<!-- "add" is the collection directive. -->
<!-- "value" is a configuration property (XML attribute). -->
<add value="Negotiate"/>
<add value="NTLM"/>
</providers>
</windowsAuthentication>
架构
配置系统的核心是一个声明性架构。 这与 IIS 6.0 不同,例如,在 IIS 6.0 中,实际架构是硬编码的,并非由 ABO 使用,并且 ADSI 提供程序(它是 ABO 之上的高级接口)具有自己的架构,客户可以扩展该架构。 这与 .NET Framework v2.0 配置系统的体系结构大相径庭,其中设置的“架构”主要编码为各个类,这些类实现了用于处理各自节的逻辑(这些类称为“节处理程序”)。 声明性架构还意味着只需要向系统添加声明便可以扩展系统,而无需添加代码(与 .NET Framework 方法的另一个区别)。
配置架构跨越多个文件,这些文件都位于以下已知位置:system32\inetsrv\config\schema。 默认情况下,只有计算机管理员有权访问此文件夹。 客户或第三方可以通过将其复制到该目录中来为其自定义节添加架构文件。 在调用方进行配置的过程中,配置系统会在启动时自动选取它们。 如果配置系统已在运行,则不会选取对架构文件或新文件的更改。
请勿编辑安装到此目录中的 IIS 或其他架构文件,因为错误可能会导致架构损坏,以及服务器无法启动。
注意
没有用于获取和设置架构文件的高级程序设计界面,无需传统文件访问 API 和 XML 分析/编辑。 在对架构文件夹进行任何更改之前,始终建议备份敏感状态(如架构文件夹)。
三个文件构成了 Web 服务器平台的统一架构:
- IIS_schema.xml:涵盖
<system.applicationHost>
和<system.webServer>
节组中的 Windows 激活系统和 IIS Web 服务器设置。 - ASPNET_schema.xml:涵盖
<system.web>
节组中的 ASP.NET 设置。 - FX_schema.xml:涵盖各种节组中的其他 .NET Framework 设置。
架构声明的组织
在架构文件中,组织是基于节的单位。 节由其全名定义,包括包含节组。 节组本身没有定义;它们用作节名称的一部分,以指示层次结构。 每个节架构声明都指定节设置的名称、类型和默认值。 还指定节中的结构:子元素、集合、属性。
我们将在这里回顾一个例子,用 XML 注释来指出一些要点。强烈建议您阅读“ApplicationHost 演练,以更详细了解架构系统的工作方式,并查看每个 IIS 节的架构。
示例:
<!-- The XML element name for defining a section schema is "sectionSchema" -->
<!-- It contains the full name of the section -->
<sectionSchema name="system.webServer/defaultDocument">
<!-- A property schema is defined using an "attribute" XML element -->
<attribute name="enabled" type="bool" defaultValue="true" />
<!-- A sub-element schema is defined using an "element" XML element -->
<!-- In this case, it is also a collection -->
<element name="files">
<!-- This collections uses the traditional "add", "remove", "clear" ->
<!-- for the directive names, and supports all of them; other -->
<!-- collections may use different names, defined here, and support -->
<!-- only some of the directives. Note the "prepend" behavior when -->
<!-- adding elements; most collections use "append" -->
<collection addElement="add" clearElement="clear" removeElement="remove" mergeAppend="false">
<!-- This defines the collection element schema; in this case, it -->
<!-- has one attribute only: "name", e.g. <add name="file1.aspx"> -->
<!-- The value for "name" is of type "string" and it serves as -->
<!-- the collection key, therefore needs to be unique -->
<attribute name="value" type="string" isUniqueKey="true"/>
</collection>
</element>
</sectionSchema>
configSections 中的其他 <架构信息>
架构 XML 文件中不一定包含了所有必需的信息。 其中一些内容位于名为 <configSections>
“特殊”部分,它驻留在配置文件本身中。 这与 .NET Framework 配置系统一致。 默认情况下,machine.config 和 applicationHost.config 中存在 <configSections>
;但客户可能会将其添加到任何 web.config 文件中,以定义其自定义节。 将为命名空间中的该级别和更低级别定义这些节。
注意
客户和第三方不应尝试在 inetsrv\config\schema\ 文件夹或是在 machine.config 和 applicationHost.config 中更改内置节的架构信息。这可能会导致这些节出现意外行为。
以下内容的内容 <configSections>
:
- 定义已向系统“注册”的部分
- 定义节组的层次结构。
- 不定义节中的属性或元素。
还为节定义了一些其他元数据:
- 类型:必需属性。 这是托管代码节处理程序类型;仅在 NET Framework 配置系统访问节(System.Configuration 类)的上下文中有用。 定义适用于强类型,即,它包括程序集名称、版本、区域性和键。
- OverrideModeDefault:可选属性。 如果缺失,则默认值为“Allow”。 这是节的默认锁定状态,即是否其锁定到定义节的级别,还是可以被配置层次结构的较低级别覆盖。 如果值为“Deny”,则更低的 web.config 文件无法覆盖其设置(换句话说:它被锁定到此级别)。 大多数 IIS Web 服务节已锁定,但并非全部锁定。 大多数 .NET Framework 节不会锁定,因为它们被视为应用程序级设置。 如果值为“Allow”,则更低级别可以覆盖设置。
- AllowDefinition:可选属性。 如果缺少,则默认值为“Everywhere”。 这是可在其中设置节的层次结构级别。 如果值为“MachineOnly”,则只能在 applicationHost.config 或 machine.config 中设置。如果它是“MachineToRootWeb”,则可以在上面为“MachineOnly”定义的文件中设置,也可以在 .NET Framework 配置文件夹的根 web.config 文件中设置(此值仅对 .NET Framework 部分有意义)。 如果是“MachineToApplication”,则可以在上面为“MachineToRootWeb”定义的文件或应用程序根文件夹中的 web.config 文件中设置。 如果是“Everywhere”,则可以在任何配置文件中设置,包括在映射到非应用程序根目录的虚拟目录的文件夹以及它们下属的子物理目录中。
下面是 applicationHost.config 中的简化代码片段:
<configSections>
<sectionGroup name="system.applicationHost" type="">
<section name="applicationPools" type="" allowDefinition="MachineOnly" overrideModeDefault="Deny" />
<section name="customMetadata" type="" allowDefinition="MachineOnly" overrideModeDefault="Deny" />
<section name="listenerAdapters" type="" allowDefinition="MachineOnly" overrideModeDefault="Deny" />
<section name="log" type="" allowDefinition="MachineOnly" overrideModeDefault="Deny" />
<section name="sites" type="" allowDefinition="MachineOnly" overrideModeDefault="Deny" />
<section name="webLimits" type="" allowDefinition="MachineOnly" overrideModeDefault="Deny" />
</sectionGroup>
<sectionGroup name="system.webServer" type="">
<section name="asp" type="" overrideModeDefault="Deny" />
<section name="defaultDocument" type="" overrideModeDefault="Allow" />
<sectionGroup name="security" type="">
<section name="access" type="" overrideModeDefault="Deny" />
<section name="applicationDependencies" type="" overrideModeDefault="Deny" />
<sectionGroup name="authentication" type="">
<section name="anonymousAuthentication" type="" overrideModeDefault="Deny" />
</sectionGroup>
</sectionGroup>
</sectionGroup>
</configSections>
锁定
位置标记通常用于锁定或解锁整个节。 配置系统也支持更精细的锁定,即锁定节内的元素和属性,但这与位置标记没有直接关系。
只能在定义锁定的级别完成解锁。 换句话说,某个配置级别永远无法解锁父级别锁定的内容。 例如,节默认未锁定,因此 applicationHost.config 中的这些位置标记将锁定两个特定站点:
<!-- lock down defaultDocument for MySite -->
<location path="MySite" overrideMode="Deny">
<system.webServer>
<defaultDocument/>
</system.webServer>
</location>
<!-- specify a value for defaultDocument.enabled and lock it for YourSite -->
<location path="YourSite" overrideMode="Deny">
<system.webServer>
<defaultDocument enabled="true">
<files>
<clear/>
<add value="default.aspx"/>
</files>
</defaultDocument>
</system.webServer>
</location>
在上面的示例中,第一个位置标记只是锁定 MySite 的节,其中包含已为其定义的任何值。 第二个位置标记会更改值(通过启用节、清除文件集合并向其添加一个元素),并且还会针对 YourSite 将其锁定。 这意味着在 YourSite 级别 (web.config),默认文档功能始终处于打开状态,并且无法关闭,唯一默认的文档是 default.aspx。
上面的示例只是稍作更改,就可以在低级 web.config 文件中进行设置,而不仅仅是在 applicationHost.config 中。配置层次结构的任何级别都可以锁定配置(对于其下层的路径,这就是为什么在示例中需要稍作更改以反映路径的不同值)。
具有相同节的位置标记可以跨越层次结构的多个级别,就像 web.config 文件一样。 将根据继承规则来评估这些位置标记。 我们不会在这里确切地指定如何相对于层次结构中位置标记下面的 web.config 文件来评估位置标记,因为该算法可能会使试图创建清晰的继承层次结构(有时是锁定配置)的人类用户感到困惑。 由于这些原因,位置标记有时可能会令人困惑,或者比简单地使用 Web.config 文件更高深。 但是,如前面在“体系结构”一节中所述,在某些情况下,有充分的理由使用位置标记。
上面的示例中的锁定是使用 overrideMode 属性完成的。 有效值为:
- “Allow”:解锁位置标记中指定的节。
- “Deny”:锁定位置标记中指定的节。
- “Inherit”:如果未指定默认值,则此为默认值。 配置系统将通过以下方式来评估在位置标记中指定的节的锁定状态:遍历继承层次结构并计算出 overrideMode 的父定义,一直到 overrideModeDefault 的节模式定义。 该值最终由 overrideModeDefault 值解析,因为要么在架构信息中指定了该值,要么使用了默认值“allow”。
系统还支持在位置标记中锁定分区的旧属性:allowOverride。 .NET Framework 配置系统中曾经使用过此属性(在 overrideMode 出现之前)。 它以如下方式映射到 overrideMode 语义:
allowOverride 值 | overrideMode 等效值 | 说明 |
---|---|---|
是 | 允许 | 解锁指定的节 |
false | 拒绝 | 锁定指定的节 |
[未设置] | 继承 | 通过遍历继承层次结构来解析 |
allowOverride 模型存在一些限制,而且自身也很复杂,我们在这里不予以介绍。 因此,建议使用新模型 overrideMode。
位置标记不能同时指定 allowOverride 和 overrideMode。 这会被视为非法配置,在运行时会失败并显示相应错误。
取消锁定
此示例演示如何解锁节。 由于节是在 applicationHost.config 级别锁定的,因此只能在该级别解锁。
<location overrideMode="Allow">
<system.webServer>
<modules/>
</system.webServer>
</location>
以下操作在特定情况下很有用:仅对特定路径的节进行解锁,而对所有其他路径保持锁定。 下面的示例在前一个示例的基础上构建,并显示如何仅为两个特定站点解锁该节。对于所有其他站点,该节仍将保持锁定状态。
<location path="TrustedSiteOne" overrideMode="Allow">
<system.webServer>
<modules/>
</system.webServer>
</location>
<location path="TrustedSiteTwo" overrideMode="Allow">
<system.webServer>
<modules/>
</system.webServer>
</location>
对于需要解锁的每个特殊路径,需要有一个不同的位置标记。
当锁定和解锁之间发生冲突时,可能会出现复杂情况。 请看以下示例:
<!-- in applicationHost.config: -->
<location path="MySite/shopping" overrideMode="Allow">
<system.webServer>
<modules/>
</system.webServer>
</location>
<!-- in web.config at MySite root: -->
<location overrideMode="Deny">
<system.webServer>
<modules/>
</system.webServer>
</location>
此冲突发生在 applicationHost.config 级别与 MySite 根目录的 web.config 之间,前者专门为 MySite/shopping 解锁节,后者又锁定了此站点的节。 当不同人员管理这些不同级别的层次结构的配置时,可能会发生这种情况。 在这种情况下,配置系统会将其视为非法配置,配置系统失败并显示相应错误。
总结
本文档概述了 IIS 配置系统的设计和体系结构。 解释了如何使用配置级别层次结构和分布式 web.config 文件来实现配置设置的委托管理。涵盖了 IIS 和 .NET Framework 配置系统之间的集成点(包括限制)。解释了标记的概念,以及在什么情况下标记应该优先于配置文件。还向读者介绍了节级别的基本配置锁定。 建议阅读“如何锁定配置”文档,以更深入地了解配置锁定,包括节中的精细锁定。
本文档还介绍了配置文件中的设置的组织方式,并介绍了节、节组、元素、属性、集合、枚举和标志的概念。
最后,文档介绍了架构系统及其工作原理;这对于使用自定义设置扩展系统时非常有用。 建议阅读“如何扩展配置”文档,以了解详情以及有关将自定义配置节添加到系统以及生成代码以使用自定义配置节的具体说明。