从IIS6新增应用程序池的概念,到现在IIS7,对HTTP请求处理功能已经越来越精确化和不断改善,IIS7应用程序池新增了经典模式和集成模式可供选择。经典模式是为了与之前的版本兼容,使用ISAPI扩展来调用ASP.NET运行库,原先运行于IIS6.0下的Web应用程序迁移到IIS7.0中只要将应用程序配置成经典模式,代码基本不用修改就可以正常运行。集成模式是一种统一的请求处理管道,它将ASP.NET请求管道与IIS核心管道组合在一起,这种模式能够提供更好的性能,能够实现配置和治理的模块化,而且增加了使用托管代码模块扩展IIS时的灵活性。假如老的Web应用程序运行于IIS7.0的集成模式下,可能需要对应用程序的web.config文件进行修改,尤其是使用了实现IHttpHandler接口的自定义模块的情况。IIS7.0在同一个服务器上能够同时支持两种模式的应用程序。
例如演示一个简单的HttpModule
创建一个asp.net 应用程序 ModuleIISTests
,里面包括 aspx 和 htm 文件,default.aspx 文件内容为空,a.htm 文件内容为 aaaaaa ,下面一个TestIISModule
是一个类库,TestModule.cs 是继承自IHttpModule
的一个自定义的HtppModule
,主要代码如下:
public class TestModule : IHttpModule
{
public void Init(HttpApplication context)
{
context.BeginRequest +=new EventHandler(context_BeginRequest);
}
public void context_BeginRequest(object sender, EventArgs e)
{
HttpApplication application = (HttpApplication)sender;
application.Response.Write("test module!!!");
}
}
然后配置网站的web.config
如下:
[...]
<system.web>
[...]
<httpmodules>
<add name="testModule" type="TestIISModule.TestModule,TestIISModule" />
</httpmodules>
</system.web>
[...]
然后部署到 iis7中,将应用程序池配置为 .net2.0经典模式,分别访问 default.aspx 和 a.htm,其结果为:default.aspx 输出 test module!!!
, a.htm 输出 aaaaaa
。
Default.aspx 被 module 拦截了,输出了文字内容,但 a.htm 还是保持文件内容不变输出。
现在更改下web.config
,首先删除刚才system.web
节点下的httpModule
节点,修改配置如下:
[...]
<system.webServer>
[...]
<httpModules>
<add name="testModule" type="TestIISModule.TestModule,TestIISModule"/>
</httpModules>
</system.webServer>
[...]
这里是在system.webServer
节点下配置的,IIS集成模式下会读取该大节点下的modules,handlers
等节点,然后把应用程序池改为集成模式,再刷新IIS,重新访问访问d efault.aspx 和 a.htm :
default.aspx 输出 test module!!!
, a.htm 输出 test module!!!aaaaaa
。
可以看出 Default.aspx 还是被拦截到了,但是这里 a.htm 也被拦截了。
集成模式下不管托管代码还是本机代码,都可以在身份验证和执行处理程序被插入到内核代码的托管代码拦截。在IIS6下,要想拦截本机代码,比如Htm文件,需要编写WIN32的非托管代码,但它也保留扩展的ISAPI
,我们可以写托管代码拦截托管文件的请求。虽然IIS6也可以通过IIS插入ISAPI
为aspnet_isapi.dll
的扩展,处理对htm文件的拦截,但它实际会走两个通道,首先是IIS内部的本机代码拦截,然后是托管代码ISAPI的拦截。经典模式就是为了保留和IIS6一样的处理方式,以前开发的代码,可以方便的移植到IIS7上。
IIS7集成模式还增加了MapRequestHandler
、LogRequest
和 PostLogRequest
事件,如果在经典模式下加了这些处理事件,会抛出:此操作要求使用 IIS 集成管线模式。如果集成模式下不让IIS处理不兼容集成模式的配置以及处理方式,可以在web.config
中配置:
<system.webServer>
<validation validateIntegratedModeConfiguration="false" />
</system.webServer>
实际上IIS7集成模式,就是让用户可以通过编写托管代码的handler
等,把托管代码插入到IIS内核代码中来解析,方便大家精确控制任意请求,带来更好的扩展性。
上述两种管道模式使用的web.config
文件存在重大的区别,许多在经典管道模式下能够正常工作的web.config
文件都无法在集成管道模式下正常工作。利用AppCmd.exe
,我们可以将经典管道模式下的配置文件格式自动转换为集成管道模式下的配置文件格式。
我们有必要首先看看各种模式的结构,并且研究两种模式之间的区别。
在IIS 6.0中的经典模式中,ASP.NET是一个添加到IIS中的ISAPI。IIS 7.0之所以支持这种模式,是为了做到向后兼容。但是,经典模式缺少许多集成模式才能提供的特性。在经典模式中,IIS拥有自身的管道,这些管道可以通过创建一个ISAPI扩展进行扩充,而ISAPI扩展是以难以开发而著称的。ASP.NET作为一个ISAPI扩展运行,只是IIS管道中的一项组成部分。
下图很好地解释了上述情况。注意,在这种情况下,ASP.NET似乎是一种类似于马后炮的成果,仅当IIS处理ISAPI扩展时才能够发挥作用。
利用文件扩展名,可以判断使用哪个ISAPI处理程序。例如,可以将扩展名为.aspx
和.ascx
的文件映射到aspnet_isapi.dll
;并且将扩展名为.asp
的文件映射到asp.dll
,这样就可以处理传统的ASP页面;此外,将扩展名为.php
的文件映射到php.dll
,这样就可以处理PHP页面,前提是已经安装了php.dll
。
此外,在IIS 6.0和IIS 7.0的经典模式中,某些特性是重复的。例如,错误处理就是一种重复的特性,因为IIS可以处理非ASP.NET页面,而ASP.NET可以处理所有将处理程序映射为aspnet_isapi.dll
的页面。
在IIS 6.0中,我们可以将所有文件类型都映射到ASP.NET,但是这样做存在一些限制。最大的限制就是如何处理默认文档:一个默认文档仅当在global.asax
中或者在一个HTTP模块中被指定为默认文档时,这个默认文档才能够得到处理。某些自定义的配置需要使用aspnet_isapi.dll
处理所有的文件类型。IIS 7.0可以轻易地解决这个问题。
经典模式可以在无须修改web.config
的前提下运行现有的Web网站,因此,如果使用的Web farm中既包括IIS 6.0服务器,也包括IIS 7.0服务器,或者因为某些原因无法将web.config
文件转换为遵循新语法的web.config
文件,那么就可以使用经典模式。
利用集成模式,可以将ASP.NET作为IIS的有机组成部分。现在,IIS服务器的功能被划分为40多个模块,因此也就将IIS和ASP.NET的功能划分为不同的组成部分。诸如StaticFileModule
、BasicAuthenticationModule
、FormsAuthentication
、Session
、Profile
,以及RoleManager
等模块都是IIS管道的组成部分。
注意,FormsAuthentication
、Session
、Profile
,以及RoleManager
原本就是ASP.NET的组成部分,与IIS并无关系。
下图使用模块解释了IIS管道。这些模块原本是ASP.NET的组成部分,现在已经是IIS管道的有机组成部分。
IIS管道提供了二十多种事件,开发人员可以利用这些事件来扩展Web服务器的功能。实际上,通过创建定制模块,同时更新applicationHost.config
,可以仅使用自定义模块,而无须再使用微软公司提供的内置模块,我们可以将IIS 7.0中的模块替换为自定义的模块。
IIS 7.0对配置文件进行了一些修改,Web开发人员可以使用这些修改内容。例如,<system.webServer>
节就是这样一项修改,无论是经典模式还是集成模式都可以识别<system.webServer>
节,同时,<system.webServer>
节既可以在applicationHost.config
文件中设置,也可以在web.config
文件中设置。<system.webServer>
节既可以控制静态页面,也可以控制动态页面。即使在经典模式中,<system.webServer>
节也具有重要作用,它可以帮助Web开发人员在web.config
文件中设置不同的IIS配置。
在集成模式中,HTTP模块和HTTP处理程序不再定义于<system.web>
中,而是定义于<system.webServer>
中。如果在集成模式中运行一个包括了HTTP模块或HTTP处理程序的web.config
文件,那么将会发生失效。幸运的是,微软公司已经详细规定了一个编号为500.22的错误信息,这个错误信息说明了如何一步步地迁移web.config
文件。
在 IIS7.5 中配置 节点的404页面不起作用
<system.web>
节点是iis7.0之前版本的主要配置节点,在II7.0以后IIS管道处理与ASP.NET管道处理进行了集成,提高了ASP.NET的处理性能。由于程序运行在IIS7.5集成模式下,需要在<system.webServer>
节点中配置,新增加的<system.webServer>
节点中需要进行哪些修改以程序在IIS7的集成模式下能完全生效呢,主要包含以下几个方面:
<modules>
—– 相当于<system.web>
中的<httpModules>
<handlers>
—– 相当于<system.web>
中的<httpHandlers>
<customError>
下的<error>
—– 相当于<system.web>
中的<httpErrors>
以上三点中,如果你的程序中有自定义的httpModules
或者httpHandlers
的话,那么第一点和第二点非常重要,具体资料请MSDN。
<httpErrors errorMode="DetailedLocalOnly">
<remove statusCode="404" />
<error statusCode="404" path="/404.htm" responseMode="ExecuteURL" />
</httpErrors>
errorMode
有三个值,分别为Custom
、DetailedLocalOnly
、Detailed
,意思为对用户与服务器端始终显示自定义页面、只能服务器端显示详细出错信息、对用户与服务器端始终显示详细出错信息。responseMode
有File
、ExecuteUrl
、Redirect
三个层,分别表示使用服务器端静态文件、可执行的URL、URL转向。
注意:<httpErrors>
与<customErrors>
是不同的,前者主要用于处理http相关的错误信息,而后者主要是处理应用程序级的错误页转向。
同样,如果Application_Error
和<customerErrors>
同时存在,也存在执行顺序的问题。因为优先级Application_Error
事件<customErrors>
配置项,所以发生应用程序级错误时,优先执行Application_Error
事件中的代码,如果Application_Error
事件中调用了Server.ClearError()
函数,<customerErrors>
配置节中的defaultRedirect
不起作用,因为Exception
已经被清除;如果Application_Error
事件中没用调用了Server.ClearError()
函数,错误页会重新定位到defaultRedict
指定的URL页面,为用户显示友好出错信息。
通过对.NET提供的以上四种错误处理机制的分析,我们可以把它们从不同的角度分类,便于我们理解和使用。
Page_Error
事件和Application_Error
事件;用户错误页面重定向(Redirecting the user to an error page)的是ErrorPage
属性 和 <customErrors>
配置项。Page_Error
事件 和 ErrorPage
属性;用于应用程序级(Application level)错误处理的是Application_Error
事件 和 <customErrors>
配置项。