ASP.NET运行时模型的源码解析

来源 :电脑知识与技术·学术交流 | 被引量 : 0次 | 上传用户:sufaya0505
下载到本地 , 更方便阅读
声明 : 本文档内容版权归属内容提供方 , 如果您对本文有版权争议 , 可与客服联系进行内容授权或下架
论文部分内容阅读
  摘要:ASP.NET是微软公司推出的基于DotNet平台的网络开发技术,对B/S模式应用的开发提供了强大的支持,该文从源代码级别进入ASP.NET底层,分析ASP.NET运行时模型,揭开ASP.NET应用程序运行的幕后细节。
  关键词:ASP.NET;DotNet平台;网络开发;B/S模式应用;运行时模型
  中图分类号:TP311文献标识码:A文章编号:1009-3044(2008)33-1415-04
  SourceCode Analyzing for ASP.NET Runtime Model
  ZHANG Jia-qing
  (Fujian Institude of Economics Management, Fuzhou 350002, China)
  Abstract: Based on DotNet platform, Microsoft Proposed the network developing technology called ASP.NET which provides strong support to the development of B/S pattern application programs. This paper enters into the bottom of ASP.NET from the level of source code so as to analyze the runtime model of ASP.NET, so that running details behind the curtain of ASP.NET application programs are uncovered.
  Key words: ASP.NET; DotNet platform; network developing; B/S pattern application; runtime model
  1 引言
  ASP.NET运行时模型指的是ASP.NET 框架在接收到客户端请求,到获取合适的HttpHandler接管请求之间,以及从HttpHandlers生成处理结果到发送处理结果给客户端之间,ASP.NET 框架所完成的一系列工作和处理逻辑[1]。本文将通过源代码级别的分析,深入讨论ASP.NET 2.0运行时模型,解析ASP.NET应用程序运行时模型的工作原理。
  2 ISAPI接口标准与IIS服务器的可扩展性
  IIS服务器是部署ASP.NET应用的标准Web服务器,由于IIS服务器在设计时引入了开放的ISAPI接口标准,具备极高的可扩展性,在核心组件不变的情况下可灵活支持不同类型不同版本的应用,例如IIS 5.1版能够同时支持ASP.NET 1.0、1.1、2.0,甚至可以支持部署基于DotNetFramework 3.5的ASP.NET应用程序。ISAPI的全称是:Internet Server Application Programming Interface,即Internet服务器应用编程接口,它为开发人员提供了强大的可编程能力,只要按照标准接口开发不同类型Web应用程序的ISAPI扩展程序,就能实现对IIS功能上的扩展,从而使IIS可以处理不同类型的客户端请求,例如让IIS处理Perl或PHP应用程序[2]。
  IIS管理器提供了应用程序配置功能,可以对不同的客户端请求配置不同的ISAPI扩展程序。ISAPI扩展程序通常以DLL的形式存在,可以被IIS加载并调用。在ASP.NET2.0下,对应于.aspx的ASP.NET应用程序,其ISAPI扩展程序默认情况下位于C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\目录下,以aspnet_isapi.dll(下文简称aspnet_isapi)文件的形式存在[3]。
  有了ISAPI扩展,IIS服务器就可以根据客户端请求的资源扩展名,来决定应由哪个ISAPI扩展来处理客户端请求,然后就可以将请求转发给合适的ISAPI扩展。例如当访问资源的扩展名为.aspx、.ascx、.ashx 和 .asmx时,IIS服务器会自动将请求转发给缺省情况下位于C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\目录下aspnet_isapi.dll进行处理[4],这个动态库就是一个ISAPI扩展程序,负责处理ASP.NET应用程序的请求。
  3 ASP.NET的后台辅助进程aspnet_wp.exe
  实际上客户发起的请求最终要由aspnet_isapi传递给它背后的aspnet_wp.exe去处理,.Net平台将其称为ASP.NET Worker Process(下文简称WP),该文件位于.NET framework安装目录下,与aspnet_isapi.dll所在位置相同。
  当aspnet_isapi接收到IIS转发的ASP.NET请求后,会将请求放入队列,并根据实际情况分配请求处理任务给WP进程,一旦请求被转送给WP进程,WP进程便会通知aspnet_isapi,请求正在被处理。这个通知的过程是通过同步I/0完成的,这么实现目的是为了保证处理过程的完整性,因为只有当请求在aspnet_isapi内部被标记为“executing”后,WP才会真正开始处理该请求。此后请求便在WP的上下文环境中执行,当执行结束后,处理结果会通过一个异步的开放管道回送给aspnet_isapi,这时请求的状态会被更新为“Done”,接着请求就会从队列中清除。如果WP进程崩溃,所有正在处理中的请求,都将维持“executing”状态一段时间,等到aspnet_isapi检测到WP进程死掉后,会自动丢弃所有的请求,并释放已经分配的资源[5]。其过程如图1所示。
  WP会分析每一个请求的信息,解析出其中的虚拟目录信息,并检查该虚拟目录对应的AppDomain是否已经存在,如果不存在则创建一个新的AppDomain,然后使用它,否则直接重用已经建立的AppDomain对象。这里的AppDomain指的是.NET中引入的应用程序域的概念,它可以理解为一个进程或一个边界,或一个容器,它是应用程序的执行环境,.NET下所有的应用程序都运行在AppDomain中,每一个ASP.NET应用程序(IIS中的站点或者虚拟目录)都会有一个AppDomain与之对应[6],它保存了Applcation对象、Cache等全局变量。
  4 请求在ASP.NET运行时中的处理,步骤一:ISAPIRuntime->HttpRuntime
  WP接收到aspnet_isapi转发的请求后,就将请求转送给指定虚拟目录对应的AppDomain中的ISAPIRuntime对象,由它完成对aspnet_isapi封装后的请求包的解析工作,笔者使用Lutz Roeder’s .NET Reflector工具查看System.Web.Dll,通过分析ISAPIRuntime的源码发现,客户的请求首先会被该类的ProcessRequest方法处理,该方法的部分代码如下:
  ISAPIWorkerRequest wr = null;
  try{
  bool useOOP = iWRType == 1;
  wr = ISAPIWorkerRequest.CreateWorkerRequest(ecb, useOOP);
  wr.Initialize();
  ……
  if (……){
  HttpRuntime.ProcessRequestNoDemand(wr);
  return 0;
  }
  ……
  }
  可以看出在ProcessRequest方法中,主要通过调用一些非托管代码生成HttpWorkerRequest对象,在上述代码中,对应于wr对象(ISAPIWorkerRequest类型继承自HttpWorkerRequest类),该对象包含当前请求的所有信息,然后ISAPIRuntime调用HttpRuntime的ProcessRequestNoDemand方法传递创建好的HttpWorkerRequest对象,这个方法的代码如下:
  internal static void ProcessRequestNoDemand(HttpWorkerRequest wr){
  RequestQueue queue = _theRuntime._requestQueue;
  if (queue != null){
  wr = queue.GetRequestToExecute(wr);
  }
  if (wr != null){
  CalculateWaitTimeAndUpdatePerfCounter(wr);
  wr.ResetStartTime();
  ProcessRequestNow(wr);
  }
  }
  该方法先从请求队列中取出一个请求,然后更新请求的引用计数器等信息,接着就让ProcessRequestNow方法处理请求,这个方法的代码如下:
  internal static void ProcessRequestNow(HttpWorkerRequest wr){
  _theRuntime.ProcessRequestInternal(wr);
  }
  追踪分析源码可以发现_theRuntime对象是在HttpRuntime内部定义的,其类型就是HttpRuntime自身,它在HttpRuntime的静态构造函数中被初始化。
  5 请求在ASP.NET运行时中的处理,步骤二:HttpRuntime.ProcessRequestInternal()
  接下来我们重点分析HttpRuntime类ProcessRequestInternal方法的运作细节!使用Reflector工具追踪至ProcessRequestInternal方法的内部:
  HttpContext context;
  context = new HttpContext(wr, false);
  ……
  this.EnsureFirstRequestInit(context);
  context.Response.InitResponseWriter();
  ……
  IHttpHandler applicationInstance = HttpApplicationFactory.GetApplicationInstance(context);
  ……
  IHttpAsyncHandler handler2 = (IHttpAsyncHandler)applicationInstance;
  context.AsyncAppHandler = handler2;
  handler2.BeginProcessRequest(context,this._handlerCompletionCallback, context);
  ……
  通过分析该方法的源码,发现它主要完成如下处理:
  1) 根据HttpWorkerRequest对象初始化HttpContext对象,它包含了request、response等属性,在编程中经常会用到这些重要的属性来完成特定的任务。
  2) 调用EnsureFirstRequestInit方法完成第一次请求的初始化工作,该方法锁定全局变量_beforeFirstRequest,然后调用FirstRequestInit(context)完成应用程序配置文件的加载、初始化请求队列、装载Bin目录下的所有程序集等工作,然后更新_beforeFirstRequest为false。
  3) 执行InitResponseWriter创建HttpWriter对象,用于写入处理结果返回信息。
  4) 调用HttpApplicationFactory类的GetApplicationInstance方法来生成IHttpHandler(这里生成的是一个默认的HttpApplication对象,HttpApplication实现了IHttpHandler接口)。
  5) 调用HttpApplication对象(它同时实现了IHttpAsyncHandler接口)的BeginProcessRequest方法执行客户请求。
  需要注意的是,笔者在跟踪至HttpApplicationFactory类的GetApplicationInstance方法内部时发现它最终通过调用该类的GetNormalApplicationInstance方法获取HttpApplication实例:
  return _theApplicationFactory.GetNormalApplicationInstance(context);
  再深入一步,进入GetNormalApplicationInstance方法内部,我们终于看到HttpApplication对象是如何被创建和初始化的:
  HttpApplication application = null;
  ……
  application = (HttpApplication)HttpRuntime.CreateNonPublicInstance(this._theApplicationType);
  using (new ApplicationImpersonationContext()){
  application.InitInternal(context, this._state, this._eventHandlerMethods);
  }
  我们发现HttpApplication类提供了一个名为InitInternal的方法,调用方通过它来完成HttpApplication实例的初始化工作,在这个方法的内部,有如下代码:
  ……
  this.InitModules();
  ……
  this.HookupEventHandlersForApplicationAndModules(handlers);
  ……
  this._stepManager = new ApplicationStepManager(this);
  this._stepManager.BuildSteps(this._resumeStepsWaitCallback);
  ……
  可以看到在HttpApplication对象初始化时,首先会自动调用自身的InitModules方法来加载在web.config文件中配置的所有HttpModule模块。接着HookupEventHandlersForApplicationAndModules方法被调用,这个方法完成global.asax文件中配置的HttpApplication或HttpModule事件的绑定。最后ApplicationStepManager对象的BuildSteps方法被调用,完成HttpApplication事件的绑定,这个方法很重要,它将创建各种HttpApplication.IExecutionStep对象并保存到一个数组列表中,以便在BeginProcessRequest方法内部调用ResumeSteps方法依次执行这些对象的Execute()方法,完成各种处理。
  图2是以上分析的一个总结。
  
  图2请求在ASP.NET运行时内部处理过程图
  
  在取得HttpApplication对象实例之后,HttpRuntime对象开始调用它的BeginProcessRequest方法(实现IHttpAsyncHandler接口中定义的方法)处理请求:
  IAsyncResult IHttpAsyncHandler.BeginProcessRequest(HttpContext context, AsyncCallback cb, object extraData){
  ……
  this._stepManager.InitRequest();
  this._context.Root();
  HttpAsyncResult result = new HttpAsyncResult(cb, extraData);
  this.AsyncResult = result;
  ……
  this.ResumeSteps(null);
  return result;
  }
  该方法首先调用ApplicationStepManager对象的InitRequest方法完成一些初始化工作,例如将记录当前执行步骤的变量清0、置请求处理完成标志为false等。然后根据上下文创建HttpAsyncResult对象记录执行结果,最后ResumeSteps方法被调用!这个方法会依次取出在数组列表中的HttpApplication.IExecutionStep对象,传递给HttpApplication的ExecuteStep方法,由它调用执行IExecutionStep对象的Execute()方法。当执行到MapHandlerExecutionStep时,会执行如下代码获取最终执行请求的HttpHandler:
  context.Handler = this._application.MapHttpHandler(context, request.RequestType, request.FilePathObject, request.PhysicalPathInternal, false);
  HttpApplication对象的MapHttpHandler方法将根据配置文件结合请求类型和URL,以调用相应的IHttpHandlerFactory来获取HttpHandler对象,例如与.aspx页面对应的Page类就是一种HttpHandler。此后请求处理的执行权被转交至对应的HttpHandler对象上。至此,本文通过源代码分析技术,详细解析了ASP.NET应用程序在底层的运作细节,限于篇幅,无法继续深入讨论ASP.NET页面的编译及执行过程。
  
  6 结语
  ASP.NET运行时是整个ASP.NET技术框架中最为复杂、最难以理解,但却十分重要的部分,对ASP.NET 2.0运行时源代码的研究有助于我们加深对ASP.NET 技术的理解,将为我们开发ASP.NET 2.0应用程序带来很多帮助。
  
  参考文献:
  [1] 谭振林.道不远人—深入解析ASP.NET 2.0 控件开发[M].北京:电子工业出版社,2007:15-18.
  [2] Dr Khosravi S.Professional IIS 7 and ASP.NET Integrated Programming[M].北京:JOHN WILEY
其他文献
摘要:《伤心咖啡馆之歌》以细腻的笔触,流畅的故事构思以及怪诞的主题情节吸引了一代又一代青少年为之疯狂。小说叙述了美国南部小镇两男一女纠葛的爱情三角故事,在压抑的氛围当中表达了对现实世界的不满以及对男女性别不平等的呐喊。本文从二次元下两性的角度来对其进一步解读。  关键词:《伤心咖啡馆之歌》麦卡勒斯艾米利亚 李蒙  一、麦卡勒斯及其作品特点  卡森·麦卡勒斯于1917年出生于乔治亚洲府哥伦布。19岁
摘要:该文主要介绍I2C总线彩电的判断方法、I2C总线彩电故障自检、I2C总线彩电的特殊故障现象、重要引脚对系统的影响、最后谈谈I2C总线系统的检测方法。I2C总线彩电越来越普及,对于各类机型I2C总线故障诊断方法有所差异,该文从故障自检、特殊故障现象、特殊功能引脚作用、检测方法等作了一些归纳。希望能对维修人员提供一些方便。  关键词:I2C总线;故障;诊断  中图分类号:TP368文献标识码:A
2019年11月,中共中央、国务院印发了《新时代爱国主义教育实施纲要》(以下简称《纲要》),并发出通知,要求各地区各部门结合实际认真贯彻落实。《纲要》明确要求,把爱国主义教育贯穿于从幼儿园直至大学的学校教育全过程,充分发挥学校教学主渠道的作用;同時指出,传承和弘扬中华优秀传统文化,对祖国悠久历史、深厚文化的理解和接受,是爱国主义情感培育和发展的重要条件。众所周知,我国是一个诗的国度,在中华民族文化
【关键词】概念义,生活义,表达义,象征义  准确地理解词语是文本学习的基础,也是阅读教学的重要目标之一。说是基础,是因为文本所要表达的意旨得依赖词语的组合而形成形象与意象;说是目标,是因为词语融入文本之后,承载着作者所要表达的文本意义和文化意蕴。对于创作者来说,文本意义和文化意蕴是其运用词语的目的;对于读者来说,从词语中感知、获取文本意义和文化意蕴是其阅读的目的;对于教育者来说,如何打破词语理解的
摘要:与研究型、教学研究型大学不同,新建本科高校多属教学型大学,主要任务是培养各种应用型高级专门人才。新建本科高校多由专科升本而来,专科教学方式影响较大。就汉语言文学专业而言,古代文学教学存在不同程度的观念落后与教学内容、教学方法与手段亟待更新等问题。就该课程的教学改革方面,笔者在教学实践中做了一些有益的探索与研究。  关键词:新建本科高校 中国古代文学 教学改革  当前我国高等学校承担的任务主要
朗读以书面语为依据,但由于书面语和口语传播方式不同,传播技巧、方法、效果有着很大差别。因此,朗读不是简单的“见字出声”,需要掌握一定技巧,其中一项重要技巧是以作者心态把握形象性和逻辑性。这种技巧在散文、记叙文等含有大量描写手法的文体的朗读中,显得尤为重要。本文试以统编教材六年级上册《月光曲》为例予以说明。  一、朗读的形象性  形象性是指朗读应透过文字感受到其所代表的客观事物,引起内心的反应,并通
泥塑 42cm×82cm×35cm 2019年  钦斋泥塑创作泥料为四川本土就地取材,許多泥土都是本色呈现,后期不着色或少着色,泥土材料接地气的本性使作品具有平易近人的质朴之美。钦斋泥塑强调作品的在场感,喜好用连环画式的叙事性场景来构图创作。作品大致分为两类:一类作品颇具书卷气。因为历代传承人的文人、诗人身份,他们创作上提倡“艺文相融”“器以载道”;另一类作品散发着浓郁的民俗味道,蜀中川西的地域风
统编教材四年级下册第三单元第一次集中呈现现代诗的教学,同时也是一个综合性学习的特殊单元。统编教材以人文主题和语文要素双线组织单元结构,将语文要素进行了系统编排,加强了阅读、习作、口语交际等板块之间的联系,表达了“重视语文素养,重建语文知识体系,阅读与表达并重”的追求,在单元设计上有了很大的突破。本单元在教材呈现上,采用了“双线并进”的编排策略,一边是以普通单元的形式编排了几篇独立的课文,分别是精读
中韩语言对比研究是中韩文化对比研究的重要内容。进入二十一世纪,我国在此领域的研究取得了长足的进步和发展。中韩语言对比、第二语言习得、偏误分析、中介语等理论的提出,进一步推动了中韩语言对比研究的进程。随着经济全球化的深化,我国与韩国在各方面的交流越来越密切,进一步推动中韩语言对比研究是实现语言应用性研究、促进两国相互理解、推动文化融合的重要内容。  由崔健、孟柱亿主编的《汉韩语言对比研究(3)》是第
摘要:本文介绍了893智能数据采集网络的结构、性能特点以及在电力企业计算机监控网络系统中的应用,讨论了电力企业计算机监控网络系统的基本内容。  关键词:智能前端;数据采集网络;监控管理系统  中图分类号:TP393文献标识码:A 文章编号:1009-3044(2008)33-1303-02  Intelligent Data Collector Network and Apply on Super