所有的请求都要经过HttpApplication管道的处理。HttpApplication的作用是请求到达处理程序和离开处理程序的一个管道,这个管道提供了统一处理所有请求的机制,使得我们可以在请求被真正处理之前和处理之后进行预处理和处理后的工作。
在ASP.NET中,所有的处理程序类必须实现IHttpHandler接口或者实现IHttpAsyncHandler接口,这两个接口的区别是前者是一个同步接口,后者是一个异步处理模式的接口。我们通常使用同步模式的接口。
两个接口都定义在命名空间System.Web下,IHttpHandler定义如下:
Public interface IHttpHandler
{
Void ProcessRequest(HttpContext context);
Bool IsReusable{get;}
}
//异步的处理程序接口定义如下,它派生自同步的处理程序接口。
Public interface IHttpAsyncHandler:IHttpHandler
{
IAsyncResult BeginProcessRequest(HttpContext context,AsyncCallback cb,object extraData);
Void EndProcessRequest(IAsyncResult result);
Void ProcessRequest(HttpContext context);
Bool IsReusable{get;}
}
增加了两个方法BeginProcessRequest和EndProcessRequest方法,分别用来将当前的请求处理过程转移到线程池中和当前线程池完成处理过程之后,用来接收处理的结果。
没有任何成员的接口,被称为标记接口,由于在.Net中类只有单继承,但是可以实现多个接口,所以在.Net通过标记接口来表示类的某些特征,提供了一个更加直接和简单的技术来解决这种问题,就是标签(Attribute)。
在实现了处理程序接口的类就可以被用来创建处理程序对象直接使用,如果再配合一个处理程序工厂,就可以实现处理程序对象的管理。比如创建一个处理程序对象池,就可以不用在每次使用处理程序的时候创建一个新的对象,而是从池中取一个现有的对象直接使用,以提高效率。
作为处理程序工厂的类必须实现接口IHttpHandlerFactory,这个接口定义在命名空间system.web下:
Public interface IHttpHandlerFactory
{
IHttpHandler GetHandler(HttpContext context,string requestType,string url,string pathTranslated);
Void ReleaseHandler(IHttpHandler handler);
}
其中GetHandler方法用来通过这个处理程序工厂获取一个处理程序对象,ReleaseHandler方法用来释放一个处理程序对象:
每一种处理程序用来处理一类的请求,不同的请求类别通过请求的扩展名来进行区分,处理程序与请求之间的匹配关系在网站的配置文件web.config中通过配置参数进行设置。System.web配置元素的子元素httpHandler用来配置网站所使用的处理程序。httpHandlers元素可以包含三种元素:add、remove、clear。Add子元素有三个必选的属性:
Verb通过一个逗号分(,)隔的http请求类型列表来表示处理请求的类型,比如get,post,使用星号(*)表示处理所有类型的请求;
Path通过一个固定的URL路径或者一个使用星号(*)的通配符来匹配请求的URL;
Type处理程序的类型名称,或者是处理程序工厂的类型名称,这个类型必须是类型的全名,如果类定义在一个命名空间中,那么必须包含这个命名空间,如果定义一个私有的应用程序集中,那么必须在类名之后,附加一个通过符号(,)分隔的程序集名称,这个程序集的扩展名可以省略;
Validate为可选的属性,如果设置为假,那么在第一次匹配的请求调用之前,不会试图加载这个类。
在ashx文件中实现IHttpHandler接口的类:
Using System;
Using System.Web;
Namespace BusinessRule.CommonService
{
///
/// 函数处理入口
///
///
public void ProcessRequest(HttpContext context)
{
context.Response.ContentType = "text/plain";
var type = WebRequestHelper.GetStringFromParameters(ActionType);
var assemblyName = AssemblyName;
if (assemblyName == null) { return; }
var assembly = Assembly.Load(assemblyName);
var tp = assembly.GetType(this.GetType().FullName, false, false);
if (tp == null) { return; }
var mi = tp.GetMethod(type);
if (mi == null) { return; }
var obj = Activator.CreateInstance(tp);
if (obj == null) { return; }
mi.Invoke(obj, null);
}
public bool IsReusable
{
get
{
return false;
}
}
}
一般处理程序实际上就是一个处理程序类,这个处理程序被ASP.NET直接在系统的配置文件中映射到了ashx扩展名的请求上,这样不需要在配置文件中进行配置了。
对于一般处理程序来说,扩展名请求的处理程序并不需要程序员在web.config中进行配置,实际上这个处理程序已经在定义在系统配置文件的web.config中:
通过配置可以看到ashx的请求是通过定义在命名空间System.Web.UI下的SimpleHandlerFactory处理程序工厂来完成的。当请求一个ashx扩展名的服务器上的资源的时候,SimpleHandlerFactory将找到对应的ashx文件,通过这个文件找到对应的处理程序,最后SimpleHandlerFactory通过反射创建一个此类型的处理程序对象实例,并通过GetHandler方法返回给HttpApplication,完成最终的请求处理过程。
使用场合,生成网页的工作通常使用扩展为aspx的web窗体来完成。对于处理结果不是HTML的请求,都可以通过一般处理程序完成,例如生成RSS Feed、XML、图片。
使用模板的方式来生成一个处理程序,模板的扩展名为aspx,通过一个内置的处理程序工厂PageHandlerFactory将aspx形式的模板编译生成处理程序代码,然后,将这个处理程序返回给HttpApplication完成请求的处理。
扩展名为aspx的请求,将有PageHandlerFactory这个处理程序工厂进行处理。这个类定义在命名空间System.Web.UI下,具体的定义如下:
Public class PageHandlerFactory:IHttpHandlerFactory
{
}
这个页面派生自Page类,Page类定义在命名空间System.Web.UI下,类的定义如下:
Public class Page:TemplateControl,IHttpHandler;
在PageHandlerFactory的内部,通过PageParser这个类解析指定的aspx文件生成Page类的派生类,这个派生类用来创建页面处理程序的对象实例。这个类定义在命名空间system.Web.UI中,完整的定义:
Public sealed class PageParser;
PageParse的静态方法GetCompiledPageInstance方法可以通过一个aspx文件创建一个相应的页面处理程序对象实例,用于处理请求。这个方法是一个公共的静态方法,可以在程序中直接使用。
Public static IHttpHandler GetCompiledPageInstance(string virtualPath,string inputFile,HttpContext context)
而GetCompiledPageInstance方法内部又使用了BuildManager类来创建页面对象实例,这个类定义在命名空间System.Web.Compilation下,
Public sealed class BuildManager
BuildManager的CreateInstanceFromVirtualPath方法通过页面的虚拟路径通过代码生成得到派生的页面类,然后通过反射创建这个页面对象:
Public static Object CreateInstanceFromVirtualPath(string virtualPath,Type requiredBaseType)
每个web服务将在服务器上创建一个对应的asmx扩展名的标记文件,新创建一个web服务WebService1.asmx中可能包含内容:
<%@WebService Language=”C#” CodeBehind=”WebService1.asmx.cs” class=”WebService1” %>CodeBehind和Class说明了处理这个服务的代码文件和实现服务的类名。当接收到请求是,通过反射来创建class中说明的类的对象实例,并调用对应的方法完成服务的处理。
[WebService(Namespace=”http://tempura.org/”)]
[WebServiceBinding(ConformsTo=WsiProfiles.BasicProfile1_1)]
在MVC2下,引入了Controller,请求被首先路由到Controller进行处理,然后由Controller分配到相应的Action完成,处理结果就是Modal。这个Modal传给View转换为界面元素,最终发送到客户端完成处理任务。
路由处理程序必须实现接口IRouteHandler,定义在System.Web.Routing下,定义了一个获取MVC处理程序的方法GetHttpHandler
Public interface IRouteHandler
{
IHttpHandler GetHttpHandler{RequestContext requestContext};
}
对禁止访问的资源进行配置,
网站应用程序中的资源可以分为两类,一类是固定定位的,另一类是可通过虚拟目录动态访问的。第一类的资源都是必须保存在固定的位置,使用固定命名规则的资源:
Global.asax,全局应用程序类;
Web.config,网站配置文件;
使用XMLSiteMapProvider的长点地图文件;
Bin文件夹下面的程序集,App_Code文件夹下面的代码文件,全局资源文件夹App_GlobalResources下面的资源,任何的本地资源App_LocalResources;
App_Data,网站应用程序的数据文件夹;
第二类资源是通过虚拟目录访问的资源,包括以下类型:
ASP.NET页面,母版页,用户空间,以及其他生产的对象;
标准的Web资源,扩展名为.htm和.jpg的资源;
任何映射到BuildProvider实例的自定义扩展;
在App_Theme文件夹中的命名主题;
从ASP.NET3.5开始提供了一个新的特征PreApplicationStartMethod,允许我们在网站初始化之前完成网站的初始化,这样,我们可以在一个类库项目中使用这个特征来标记需要在网站中提前初始化的方法,但是在多个程序集的情况下,不能保证调用程序集定义的应用程序启动方法的顺序,因此每个注册的开始方法应该讲代码编写为分开运行,不应该依赖于其他注册开始方法的副作用。需要注意的是方法必须是一个没有参数的公共、静态方法。
[assembly:System.Web.PreApplicationStartMethod(typeof(AppStart),”AppInitialize”)]
Public class AppStart
{
Public static void AppInitialize()
{
ZipVirtualPathProvider virtualPathProvider=new ZipVirtualPathProvider();
System.Web.Hosting.HostingEnvironment.RegisterVirtualPathProvider(virtualPathProvider);
}
}