HTTP处理程序是真正负责处理请求的组件,它实现了IHttpHandler接口。该接口的ProcessRequest方法是控制请求处理的“中央控制台”。如,Page类实现IHttpHandler接口,它的ProcessRequest方法负责加载和保存视图状态,还负责引发一些常见的事件(Init、Load、PreRender等)。
ASP.NET会将每个传入的HTTP请求映射到相应的HTTP处理程序。HTTP处理程序工厂创建这些处理程序的实例对象(如,PageHandlerFactory类能解析被请求的aspx资源的源代码,编译后返回代表相应页面的类实例)。
HTTP模块是实现IHttpModule接口的类,用于处理运行时事件。模块能处理两种类型的公共事件,分别是HttpApplication引发的事件(包括异步事件)和其他HTTP模块引发的事件。如,SessionStateModule是ASP.NET内建的模块之一,用于为应用程序提供会话状态服务。它能引发End和Start事件,而其他模块可通过Session_End和Session_Start这样的签名来对其进行处理。
HTTP处理程序和HTTP模块分别对应的于ISAPI扩展和ISAPI筛选器。虽然功能相同,但处理程序和模块的编程模型要简单得多。
ISAPI代表“Internet服务器应用程序编程接口”(Internet Server Application Programming Interface),用于IIS与外部组件交互的协议。ISAPI模型基于一种Microsoft Win32非托管动态链接库,暴露两个函数。该模型在IIS 7.0中获得了显著的扩展,基于HTTP处理程序和模块,在很大程度上对应于ASP.NET可扩展模型。
IIS可扩展API概述
从根本上讲,WEB服务器是一种服务器应用程序,可通过多种Internet协议与之连接(如HTTP、FTP、NNTP、SMTP等)。
Web服务器一般还提供应用程序编程接口(API),用于对服务器的功能进行改进和定制。历史上出现的第一种扩展API是通过网关接口(Common Getway Interface,CGI)。CGI应用程序处理每个请求都要建立新的进程,不适于高吞量的Web站点,在现代的应用程序中不再使用它了。IIS支持CGI应用程序,但如果需要向后兼容,应避免使用该功能。新版本的Web服务器提供了一种更高效的替代品模型来扩展这种模块的功能。在IIS中,这种替代模型采用了ISAPI接口的形式。
ISAPI模型
IIS将ISAPI组件(Win32 DLL)加载到自己的进程中,随后,IIS会调用该DLL上的公共入口点对请求进行处理。ISAPI组件在IIS关闭前会一直被保留,处理请求不会对Web服务器的活动有进一步的影响。这种模型的弊端在于,由于组件加载到Web服务器的进程中,它发生的任何错误都会对整个服务器及所有安装的应用程序产生致使的影响。但从IIS 4.0开始已经采取了一些措施来解决这个问题。在IIS 6.0出现之前,我们可以为新安装的应用程序设置保护级别,其中含有低、中、高3个选项。
如果选择低级保护,应用程序(及其扩展)会运行在Web服务器的进程(inetinfo.exe)中;如果选择中级保护,所有应用程序会集中在池中,由另一个工作进程(dllhost.exe)的实例管理;如果选择高级保护,每个被设为High的应用程序会由各自的工作进程(dllhost.exe)来管理。
运行在IIS 6.0下的应用程序可以按应用程序池进行分组,我们能选择利用现有的池还是创建新的。处于同一个池中的应用程序共享相同的运行时设置和相同的工作进程,即w3wp.exe。
ISAPI模型在编程模型上有一个严重缺陷。ISAPI组件必须使用C或C++开发,还应考虑多线程,错误和运行时故障会影响整个应用程序,因而编写这种程序应极为谨慎。
从IIS 6.0开始,构建于IIS之上的所有功能,其编程必须遵循ISAPI模型的规范。ASP和ASP.NET也不例外。如今,整个ASP.NET平台与IIS紧密集成,但二者并不是一体的。核心组件aspnet_isapi.dll是IIS与ASP.NET运行时环境的桥梁。在aspx资源的请求传入时,IIS会将控制权交给aspnet_isapi.dll,而该组件再将请求交给公共语言运行时(CLR)实例中的ASP.NET管道。
ISAPI组件的结构
ISAPI扩展通过DLL结尾的URL进行调用,如下所示:
http://www.contoso.com/apps/hello.dll
该DLL必须暴露两个函数:GetExtensionVersion和HttpExtensionProc。GetExtensionVersion函数用于设置ISAPI服务器扩展的版本和名称。当该扩展被加载时,GetExtensionVersion函数会最先被调用。但它只调用一次,用于对内部变量进行初始化。如果一切正常,该函数会返回true。如果发生错误,该函数会返回false,Web服务器会终止相应DLL的加载,并向系统日志发送一条消息。
HttpExtensionProc函数为ISAPI组件的核心。该函数能够接收请求的基本HTTP信息(如,查询字符串和标头),执行期望的操作,并准备将响应发送给浏览器。
ISAPI编程模型由两种组件构成:ISAPI扩展和ISAPI筛选器。
ISAPI扩展
ISAPI扩展是CGI应用程序的IIS进程内版本。IIS扩展的工作方式与ASP或ASP.NET页面相同,它会获取与HTTP请求相关的信息,并生成有效和HTTP响应。
ISAPI扩展由已编译的代码构成,如果要对其进行修改,每次都需要重新编译并重新加载。如果DLL加载到Web服务器的内存中,Web服务器必须停止运行;如果DLL被加载到单独进程的上下文中,那么该进程必须停止运行;若使用外部进行,ISAPI扩展的执行速度不像在进程内那样快,但不会影响到IIS的稳定性。
ISAPI筛选器
ISAPI筛选器是一种组件,能够捕获特定的服务器事件并对其进行处理。在加载时,筛选器会指示它能够处理的事件。如果其中的某个事件被引发,筛选器便会处理它们,或将其传给其他筛选器。
筛选器只能在进程内模式下运行。它可以被整个Web服务器共享,也可以针对特定的Web站点。
ISAPI筛选器能够实现自定义身份验证模式、压缩、加密、日志记录及请求分析之类的功能。在处理传入和传出数据流方面,ISAPI筛选器有非常大的开发潜力,且非常灵活。
IIS 7.0的革新
1. 统一的运行时环境
IIS 7.0在某种程序上体现了ASP.NET与IIS平台的统一。HTTP处理程序、HTTP模块、运行管道和配置文件成为公共环境的组成元素。IIS内部的整个管道被组件化,能包容多个独立且可配置的组件。ASP.NET应用程序的web.config文件中加入了一个新区段,专门用于配置IIS环境。因此,ASP.NET运行库得到了扩展,能与外围Web服务器环境进行交互,还能替换其中的组件。
2. 托管的ISAPI扩展和筛选器
若希望在IIS 7.0之前的版本中控制传入的请求,除了通过MFC或活动模板库(ATL)来编写C或C++ DLL以外,别无他法。HTTP处理程序和模块是ASP.NET特有的功能,但仅能处理ASP.NET特定的资源,且请求经IIS验证后才会交给ASP.NET。
在IIS 7.0中,我们可以编写HTTP处理程序和模块来对任何请求进行筛选,通过.NET代码为Web服务器能够处理的所有资源添加新功能。确切地讲,我们照旧编写HTTP处理程序和模块,但可以为任何类型注册它们。