ASP.Net之运行机制的原理
面试题-------------------------------------------------- 1.页面生命周期是什么? 1.1.全局:是页面在服务器端被创建完毕后,按照Page类预先定义的代码的执行过程. 1.2.为什么要有生命周期: 为程序员提供修改控件树属性的通道.(程序员在cs后台页面的方法都注册在生命周期的事件上--通过页面对象的自动事件注册机制) 1.3.aspx页面就是控件(asp.net中有个概念 页面即控件)
画图 从HttpContext-HttpApplication中的PR--请求管道--11至12事件之间执行请求页面的PR()--里面构造控件树--生命周期--render()遍历控件中的HTML代码
2.如果要在Page_Load之前做一些处理怎么办? 需要再Page_Load方法之前,加一个Page_PreLoad()方法,在里面可以进行 预加载处理.
<<<10.ASP.NET运行机制运行原理:>>> 1.浏览器向服务器发送请求报文-- 2.IIS服务器对请求报文进行处理- 3.查询脚本映射扩展表,把请求映射到aspnet_isAPI.dll扩展程序 (到IIS映射表中查找后缀名,若查找到了,转到4, 如果找不到,则IIS服务器自己对其进行处理,比如静态页面, IIS服务器自己进行读取,将响应报文返回给浏览器)-- 4.通过IIS提供的公共接口与FW搭建桥梁并将请求报文交给FrameWork-(,net运行时被加载) 5.FW将请求报文交给ISAPIRuntime类,调用ISAPIRuntime.ProcessRequest()方法-- 6.再直接调用HttpRuntime类的ProcessRequest()方法 7.创建ISAPIWorkerRequest对象(将请求报文信息进行简单的封装,返回的响应报文请求也将包括在内)-- 8.通过HttpWorkerRequest对象创建HttpContext对象 : 上下文对象包括1.HttpRequest对象 2.HttpResponse对象 (需要使用HttpWorkerRequest对象) 3.Application 4.Server 5.Cache 在请求的生命周期里,这个上下文对象一直有效的,并且可以通过静态的HttpContext.Current属性访问. 注意: HttpContext对象还包含一个非常有用的列表集合,可以使用它存储有关特定的请求需要的数据 上下文context对象创建于一个请求生命周期的开始,在请求结束时被释放. 因此,保存在列表集合里的数据仅仅对当前的请求有效. 一个很好的例子就是记录请求的日志机制: 通过使用Global.asax里的Application_BeginRequest和 Application_EndRequest方法,可以在请求的开始到结束时间段内,对请求进行跟踪 9.每一个ASP.NET程序都拥有各自的虚拟目录(Web根目录),并且他们都是独立处理请求的 Web程序的主要部分:HttpApplication 每一个请求都将被路由到一个HttpApplication对象. HttpApplicationFactory类会为你的ASP.NET程序 创建一个HttpApplication对象池,它负责加载程序 和 给每一个发来的请求分发HttpApplication对象的引用 这个对象池可以通过machine.config里的ProcessModel节点中的MaxWorkerThreads选项配置,默认是20; HttpApplication对象池尽管以比较少的数目开启,通常是一个,但是当同时有多个请求需要处理时, 池中的对象将会随之增加. HttpApplication对象池也将会被监控,目的是保持池中对象的数目不超过设置的最大值, 当请求数量减少时,池中的数目就会跌回一个较小的值
10.通过上下文对象作为参数传递给HttpApplication.GetApplicationInstance() 调用该方法,从HttpApplication池中获取HttpApplication对象,-负责处理整个请求
11.调用HttpApplication的ProcessRequest()方法--
12.在此同时执行请求管道中所注册的19个委托事件--前五个事件是对用户权限的判断,
13.执行到第八个事件时,通过反射技术创建请求页面的实体类对象, 请求页面的实体类都必须实现FrameWork环境所提供的IHttpHandler公共接口, 该接口中实现了处理请求的ProcessRequest()方法
14.在处理管道的第9个事件是对Session进行处理 1.向服务器Session池添加Session对象,将键值对存入Session对象中 同时以cookie方式向浏览器发送SessionId. 2.在浏览器未关闭的前提下,当再次访问该网站页面时, 浏览器会自动将保存了SessionId的cookie发送到服务器来 3.在调用页面对象的ProcessRequest方法之前,也就是请求管道的第八个事件, 先尝试将请求页面类对象转换成IRequiresSessionState接口对象,如果转换失败,则不加载Session对象 如果转换成功,服务器端会根据请求报文头中的Cookie里的SessionId到Session池中去找 看是否有对应的Session对象,并且将该对象的引用设置给HttpContext里的Session属性 4.页面对象执行PR方法时,就直接通过Page类的Session属性 可以访问到HttpContext里的Session引用. 15.在执行到第11个事件和第12事件 之间,调用了反射创建的请求页面对象的ProcessRequest()处理方法, 在此方法中,调用Page类的FrameWorkInitialize().中间就调用__buildControlTree()方法创建控件树 之后调用ProcessRequestMain()方法,在此方法里面,执行了整个页面的生命周期.
在PR方法中 执行页面类的buildControlTree()方法来构造控件树 buildControlTree()方法中传入当前前台页面类对象,作为根节点, 生成页面控件树,将页面的每个HTML代码及相应的服务端运行的控件标签(runat=server) 都以服务器端控件类对象方式封装起来. 最后当页面执行完毕,生成整个页面对象所对应的HTML页面代码时,只需要循环遍历整个控件树的每个节点 并调用每个节点的Render方法,就可以生成每个控件里所封装的Html代码了,最后组成整个页面的html 返回浏览器. 16.--执行页面生命周期的一系列方法(LoadState(),PageLoad(),SaveState()) 生命周期中有许多事件,程序员可以注册方法,并在方法中修改控件树里某个控件对象的属性 17.--通过生命周期中的方法来改变控件树中对应控件的属性,然后在调用页面的renderControl()方法生成Html代码 遍历整个控件树,调用每个控件的render方法,根据控件属性生成 并 拼成整个页面的html代码, renderControl方法()需要传入Response对象参数,实际上是一个写出器HtmlTextWriter对象. 遍历控件树时,调用每个控件的renderControl()方法,都会传入同一个HtmlTextWriter对象, 所以每个控件生成的html代码,都按照次序存在同一个HtmlTextWriter对象中, 最后只要将这个HtmlTextWriter对象中的字符串输出 就可以形成整个页面
18.将处理后所得到的响应报文信息通过HttpFinishRequest对象包装返回给HttpWorkerRequest对象 19.HttpWorkerRequest对象 通过HttpResponse对象将响应报文返回给IIS服务器 20.最后再将响应报文返回到浏览器页面解析出来
<<<aspx页面执行过程:>>>---------------------------------------------------------------------------------- 1.--首先通过反射创建aspx前台页面(第八个事件), 第九个事件尝试将页面类对象转换成IRequeiresSessionState接口对象, 如果转换不成功,则不加载Session对象, 转换成功则从请求报文头中获得 cookie里的SessionId,然后到服务器的Session池中根据Session找到Session对象 并将其引用赋值给页面对象的Session属性 2.--然后调用反射创建的请求页面的ProcessRequest()方法(第十一与第十二个事件之间)
3.--调用父类的ProcessRequest方法,在此方法中父类调用了父类的FrameworkInitialize() 但因为被页面类重写了,所以执行的是当前页面类的FrameworkInitialize(),在中间就调用了 buildControlTree()方法,然后调用ProcessRequestMain()方法,在此方法中,执行了整个页面的生命周期 (页面生命周期,其实就是调用一系列事件的方法)
在PR方法中 执行页面类的buildControlTree()方法来构造控件树 buildControlTree()方法中传入当前前台页面类对象,作为根节点, 生成页面控件树,将页面的每个HTML代码及相应的服务端运行的控件标签(runat=server) 都以服务器端控件类对象方式封装起来. 最后当页面执行完毕,生成整个页面对象所对应的HTML页面代码时,只需要循环遍历整个控件树的每个节点 并调用每个节点的Render方法,就可以生成每个控件里所封装的Html代码了,最后组成整个页面的html 返回浏览器. 4.--执行页面生命周期的一系列方法(PageLoad(),SaveState(),LoadState()) 生命周期中有许多事件,程序员可以注册方法,并在方法中修改控件树里某个控件对象的属性 5.--通过生命周期中的方法来改变控件树中对应控件的属性,然后在调用页面的renderControl()方法生成Html代码 遍历整个控件树,调用每个控件的render方法,根据控件属性生成 并 拼成整个页面的html代码, renderControl方法()需要传入Response对象参数,实际上是一个写出器HtmlTextWriter对象. 遍历控件树时,调用每个控件的renderControl()方法,都会传入同一个HtmlTextWriter对象, 所以每个控件生成的html代码,都按照次序存在同一个HtmlTextWriter对象中, 最后只要将这个HtmlTextWriter对象中的字符串输出 就可以形成整个页面