理解ASP.NET页面生命周期和asp.net运行时

ASP.NET 页生命周期概述 :http://msdn.microsoft.com/zh-cn/library/ms178472%28VS.80%29.aspx

ASP.NET 运行时学习

dudu的asp.net运行时简要分析
EagleFish的从.net类库看.net运行时
Artech的ASP.NET Process Model之二:ASP.NET Http RunTime Pipeline-PartI
Artech的ASP.NET Process Model之二:ASP.NET Http RunTime Pipeline-PartII
文野的一点一点学ASP.NET之基础概念——HTTP运行期与页面执行模型
头中中,不大的ASP.NET的(HttpModule,HttpHandler)

介绍

对于ASP.NET开发者,理解ASP.NET的页面生命周期是非常重要的。主要是为了搞明白在哪里放置特定的方法和在何时设置各种页面属性。但是记忆和 理解页面生命周期里提供的事件处理方法(method)非常困难。互联网上有很多关于页面生命周期内部机制的文章,所以本文只准备简单覆盖技术的基础部 分,更主要的目的是给大家提供一个简单得记忆页面生命周期的方法。

准确的记忆ASP.NET页面生命周期每一个阶段发生了什么事情是比较困难的,一种便于记忆的方法是根据各个阶段的名字组合出一个缩写。微软的文档给出的ASP.NET生命周期如下:

  1. Page Request
  2. Start
  3. Page Initialization
  4. Load
  5. Validation
  6. Postback event handling
  7. Rendering
  8. Unload

根据这个组合出一个缩写非常容易。既然Page Request技术上并不是页面生命周期的一部分(这个阶段仅仅标示我们是否开始一个页面周期或者从缓存加载一个页面),我们为了方便,就不包括这一阶段。

  • S – Start
  • I – Initialize
  • L – Load
  • V – Validate
  • E – Event Handling
  • R – Render

这样就组合出一个缩写“SILVER',这个英文单词非常好记。当然,一定要记住页面生命周期的最后一个环节unload没有包括在里面。如果你觉 得有必要,你可以记忆为“SILVER-U”或者“SILVER-YOU",尽管有点破坏这个记忆法的完美性。现在,我们非常容易就记住了页面生命周期, 接着我们总结一下每一步都发生了什么,都有什么事件伴随着发生。

1. Start

在这个阶段,页面属性,比如Request , Response , IsPostBackUICulture 被创建。最为一个开发人员,大部分时候在这个阶段你不需要做任何事。 如果你需要调用或者重写(override)这一阶段的行为,可以使用PreInit方法创建或者重新创建动态控件,设置master page或者theme或者读取和设置profile property的值。要注意的一点是,如果是回传(postback)的页面请求,所有控件的值还没有从view state里还原,如果你在这个阶段设置一个控件的值,这个值有可能在下面的阶段被重写并覆盖。

2. Initialize

这个阶段对于开发人员是很重要。在这个阶段,theme被应用,所有的控件都被设置了唯一的ID。开发人员在这个阶段可以调用Init , InitCompletePreLoad 方法。微软关于这些方法使用的建议如下:

  • Init – 这个事件发生在所有控件被初始化并且皮肤设置也被应用后。使用这个事件来读取控件的初始化值。
  • InitComplete –这个事件被Page对象触发,使用这个事件处理那些要求所有初始化工作都完成后才能做的事情。
  • PreLoad - 如果在页面或者控件进入Load事件前你有什么要处理的,使用这个事件。Page在触发这个事件后,Page就会为自己和所有的控件加载view state并且处理所有Request中的postback数据。
3. Load

这个阶段可能是开发者使用得最多的一个阶段。在这个阶段,所有的控件被viewstate中信息填充并被加载,OnLoad事件被触发。在这个阶段你可以为页面上所有的服务端控件设置属性,得到query strings,建立数据库连接。

4. Validation

如果你的控件要求验证,验证会在这个阶段发生,这个时候你可以检查控件的IsValid属性。跟这个阶段关联的事件是Validate,它有一个可以接受验证字符串群的重载方法(overload method),这个重载方法执行特定控件群的验证。

5. Event Handling

所有服务器端控件的事件处理发生在这个阶段。也就是说Click , SelectedIndexChanged 等等这些事件会应用到你的服务器端控件,如果是页面请求是回传(postback)的话,这些事件的处理函数就会被控件触发。这个阶段可以使用的事件如下:

  • LoadComplete – 在这个阶段,页面上所有的控件加载完毕。
  • PreRender – 这里有几个重点,第一:页面对象(page object)会调用每一个控件的EnsureChildControls函数,并最终调用自己的。其次:所有具有DataSourceID的数据绑定控 件都会调用自己的DataBind函数。要注意的一点是,PreRender事件会发生在一个页面的每一个控件上。在这个事件的最后,页面和所有控件的 ViewState被存储。
  • SaveStateComplete – 到这里,ViewState已经存储完毕,如果你有什么操作不需要修改控件但需要修改ViewState的,可以放在SaveStateComplete里面。
6. Render

渲染(Render)实际上不是一个事件,页面对象调用每一个控件的Render方法从而按顺序的输出控件的HTML代码。编写用户自定义控件的开 发者对这个阶段最感兴趣了,因为输出用户自定义HTML代码的标准做法就是重写Render方法。如果你的控件是从ASP.NET服务器端控件继承来的, 你也许不需要重写Render方法,除非你想呈现一个与用户控件默认行为不同的行为。这些都超出这个文档要讨论的范围了,如果想了解更多,请参考 Microsoft's Developing Custom ASP.NET Server Controls. (http://msdn2.microsoft./zt27com/en-us/librarytfhy.aspx )

7. Unload

最后这个事件首先是被各个控件逐一触发,最后被页面触发。在这个时刻,所有的控件已经被渲染为输出流(output stream)并且无法被修改。这个阶段中,任何试图对response stream的操作都会引发异常。这个事件主要用于做一些清理工作,比如关闭数据库连接和打开的文件或者登记事件记录等等其它任务。

页面周期中都有哪些方法

下面列出ASP.NET页面生命周期中所有的方法,这些方法都可以被重写(override),要注意的是这些方法有的会递归调用,有个会被页面中的内容重复调用,这个列表是按照页面加载时最通用的顺序排列的。

  1. Construct
  2. ProcessRequest
  3. FrameworkInitialize
  4. InitializeCulture
  5. If child controls are present:
    1. AddParsedSubObject
    2. CreateControlCollection
    3. AddedControl
    4. ResolveAdapter
  6. DeterminePostBackMode
  7. OnPreInit
  8. OnInit
  9. TrackViewState
  10. OnInitComplete
  11. OnPreLoad
  12. OnLoad
  13. OnLoadComplete
  14. EnsureChildControls
    1. CreateChildControls
  15. OnPreRender
  16. OnPreRenderComplete
  17. SaveViewState
  18. OnSaveStateComplete
  19. CreateHtmlTextWriter
  20. RenderControl
  21. Render
    1. RenderChildren
    2. VerifyRenderingInServerForm
  22. OnUnload
  23. Dispose

结论

在开发ASP.NET程序时,了解什么时候发生什么事情是非常重要的。理解页面中事件是如何层层展开节省大量挠头和查错的时间。当这些页面周期中的事件难以记住时,我希望这个使用的法子能帮助你梳理出在程序里哪个地方需要做什么处理。

我写这篇文章是为了帮助大家,也方便了自己。即使是熟练的开发人员有时也会忘记那些先那些后。这篇文章不是面面俱到,而是希望给初学者和中级水平的开发者提供一些“小技巧”,从而帮助他们避免一些基本的错误。

祝使用ASP.NET一路愉快!

原文地址:http://69.10.233.10/KB/aspnet/ASPNET_Page_Lifecycle.aspx

--------------------------------------------------------------------------------------------------------------------------------------------

原文摘自:http://www.cnblogs.com/justdi/archive/2008/02/26/1073204.html

ASP.NET 运行时学习

      ASP.NET2.0运行时在我看来一直是一项高深莫测的的知识,每每看到它时总是将其跳过去,因为我觉得其中的奥妙或许不是现阶段的我能够理解的.但在 学习控件开发的过程中越来越多的疑问不能顺利地解决,回过头来看正是它卡住了我前行的步伐,是有必要去深入地了解下它了,花了几天的时间整理了下关于 asp.net2.0运行时的相关内容,结合他人的想法和自己的一些理解对其做了一些总结,但感觉asp.net2.0运行时还是很复杂,自己的理解或许 只是停留在表面上的,由于能力的限制,文中难免有错误的地方,欢迎批评指正.
      一、概念入手,什么是ASP.NET2.0运行时?
      ASP.NET运行时指从asp.net框架接收到客户端请求,到合适的HttpHandle接管求求之间,以及从HttpHandlers生成处理结果后到发送请求处理结果到客户端之间,ASP.NET框架所完成的一系列工作和逻辑.
      从概念上来看似乎看不出什么端倪,也看不出关于asp.net2.0运行时的任何内部机理.所以我们从ASP.NET应用程序的宿主IIS说起,一般我们 发布一个asp.net应用程序时,我们都会在IIS中选择一个应用池,一般默认的是DefaultAppPool,当然我们可以建立多个应用池,但建立 这么多的应用池有什么用呢?一般来说一个应用池可以也只能设置一个版本的asp.net Framework,还可以设置它的最大内存数量、CPU使用率、回收工作进程的时间间隔等参数,因此设置多个应用池可以对应地发布不同的asp.net 应用程序,默认情况下,每个应用程序池由一个w3wp.exe进程来维护(这也是为什么每次我们本地IIS部署并开启一个asp.net网站时会有一个 w3wp.exe进程在那运行着).
      IIS中不仅仅可以发布asp.net应用程序还可以发布asp,php应用程序,如何区别这些不同应用程序发过来的请求呢?其实,IIS处理这些不同的 请求是通过各种ISAPI的扩展来执行的,IIS根据不同的请求,将请求指定到不同的ISAPI扩展,如果说客户端发送请求的是一个aspx页面,IIS 就会将这个请求发给asp.net特有的扩展aspnet_isapi处理,如果我们未安装这个扩展,就会提示"HTTP 错误 404,您正在搜索的页面可能已经删除、更名或暂时不可用 ".至于aspnet_isapi如何处理这个请求,我们可以先从ISAPIRunTime这个类入手.
      二、ISAPIRunTime
       这个类位于System.Web.Hosting命名空间下,是一个密封类,aspnet_isapi对于IIS交给它的请求它第一时间以COM方式调用 了IISAPIRunTime对象的ProcessRequest方法,这也是从托管环境至非托管环境的一个交界点.aspnet_isapi.dll存 在于非托管环境中,它通过加载CLR创建了一个托管的环境,而这个过程是异步的,aspnet_isapi一调用ISAPIRunTime对象的 ProcessRequest方法后就立即返回,只将自己对应的 ECB的指针传给它, ISAPIRutime不但可以将最终生成的 Response返回给 ISAPI,还能通过 ECB调用ISAPI获得一些所需的数据。

public   int  ProcessRequest(IntPtr ecb,  int  iWRType)
{
    
try
    
{
          //ecb是aspnet_isapi异步调用 ISAPIRunTime对象的ProcessRequest方法后传递的指针,这也是从托管环境进入非托管环境的一个交界点.

        HttpWorkerRequest wr  =  ISAPIWorkerRequest.CreateWorkerRequest(ecb, iWRType);
        
string  appPathTranslated  =  wr.GetAppPathTranslated();
        
string  appDomainAppPathInternal  =  HttpRuntime.AppDomainAppPathInternal;
        
if  ((appDomainAppPathInternal  ==   null ||  StringUtil.EqualsIgnoreCase
                  (appPathTranslated, appDomainAppPathInternal))
        
{
            HttpRuntime.ProcessRequestNoDemand(wr);
            
return   0 ;
        }

        HttpRuntime.ShutdownAppDomain(ApplicationShutdownReason.PhysicalApplicationPathChanged,
SR.GetString(
" Hosting_Phys_Path_Changed " new   object []  { appDomainAppPathInternal, appPathTranslated } ));
    }

    
catch  (Exception exception)
    
{
        Misc.ReportUnhandledException(exception, 
new   string []
          
{ SR.GetString( " Failed_to_process_request " ) } );
        
throw ;
    }

    
return   1 ;
}


这段代码的其余部分可以不用去深入地理解它,但我们需要知道的是从HttpRuntime.ProcessRequestNoDemand(wr)这里,我们就进入 了HttpRunTime对象,这也是本篇文章所重点论述的.
    三、HttpRunTime
      HttpRunTime这个类位于System.Web命名空间下,是System.Web组件中最为复杂的几个类之一.这是一个密封类,因此我们不能去继承修改它.这个类在asp.net2.0运行时起着一个主导的作用.从HttpRunTime这个对象的ProcessRequestInternal方法我们来看 看它到底做了什么.

private   void  ProcessRequestInternal(HttpWorkerRequest wr)
{
      //创建一个HttpContext实例,每一个请求都会对应一个HttpContext对象,而每一个对象都管理着一个HttpSession对象,这也保证了每次请求均有一个Session对象可以使用.
    HttpContext extraData 
=   new  HttpContext(wr,  false );
    wr.SetEndOfSendNotification(
this ._asyncEndOfSendCallback, extraData);
    Interlocked.Increment(
ref   this ._activeRequestCount);
    HostingEnvironment.IncrementBusyCount();
    
try
    
{
        
try
        
{
               //对第一次请求初始化,在这个过程中 过调用System.Web.HttpRuntime.FirstRequestInit进行一些初始化工作,比如:将Web.Config配置读到到RuntimeConfig中,从bin目录中装载所有dll文件

            
this .EnsureFirstRequestInit(extraData);
        }

        
catch
        
{
            
if  ( ! extraData.Request.IsDebuggingRequest)
            
{
                
throw ;
            }

        }

        extraData.Response.InitResponseWriter();
   IHttpHandler applicationInstance  =  HttpApplicationFactory.GetApplicationInstance(extraData);
         //HttpApplication是在这里创建的,这里引用dudu对这个方法的分析.
          
通过调用HttpApplicationFactory.GetApplicationInstance创建HttpApplication实例。
            在HttpApplicationFactory.GetApplicationInstance中有三个关键方法:
                  HttpApplicationFactory._theApplicationFactory.EnsureInited();
                  HttpApplicationFactory._theApplicationFactory.EnsureAppStartCalled(context);
                  HttpApplicationFactory._theApplicationFactory.GetNormalApplicationInstance(context);

             下面我们对这三个方法逐个进行分析:
1) HttpApplicationFactory._theApplicationFactory.EnsureInited();
     该方法检查HttpApplicationFactory是否被初始化,如果没有,就通过HttpApplicationFactory.Init()进 行初始化。在Init()中,先获取global.asax文件的完整路径,然后调用CompileApplication()对global.asax 进行编译。
       那编译是如何进行的呢?
     编译的工作由BuildManager完成的。BuildManager先得到GlobalAsaxType(也就是HttpApplication), 然后调用BuildManager.GetGlobalAsaxBuildResult()=》 GetGlobalAsaxBuildResultInternal()=》EnsureTopLevelFilesCompiled()进行编译。
     在EnsureTopLevelFilesCompiled中,先进行CompilationStage.TopLevelFiles编译,对下面三个目录中的文件进行编译:
     a. CompileResourcesDirectory();
         编译App_GlobalResources目录。
     b. CompileWebRefDirectory();
         编译App_WebReferences目录。
     c. CompileCodeDirectories();
         编译App_Code目录。

     接着进行CompilationStage.GlobalAsax 编译,对global.asax进行编译,方法调用情况:CompileGlobalAsax()=》 ApplicationBuildProvider.GetGlobalAsaxBuildResult(BuildManager.IsPrecompiledApp)。
     在GetGlobalAsaxBuildResult中具体的编译是由ApplicationBuildProvider与BuildProvidersCompiler共同完成的。
     BuildProvidersCompiler.PerformBuild();进行编译工作。
     ApplicationBuildProvider.GetBuildResult得到编译的结果。
     编译成功后,会在C:/WINDOWS/Microsoft.NET/Framework/v2.0.50727/Temporary ASP.NET Files/相应的目录中生成类似App_global.asax.mlgx7n2v.dll的dll文件。
     编译生成的类名为ASP.global_asax,继承自HttpApplication。
注:如果Web目录中没有Global.asax文件,就不会编译生成App_global.asax.mlgx7n2v.dll这样的文件。

2) HttpApplicationFactory._theApplicationFactory.EnsureAppStartCalled(context);
     创建特定的HttpApplication实例,触发ApplicationOnStart事件,执行ASP.global_asax中的 Application_Start(object sender, EventArgs e)方法。这里创建的HttpApplication实例在处理完事件后,就被回收。

3) HttpApplicationFactory._theApplicationFactory.GetNormalApplicationInstance(context);
     该 方法创建HttpApplication实例并进行初始化(调用System.Web.HttpApplication. InitInternal()方法)。
创 建HttpApplication实例是根据实际的_theApplicationType进行创建。如果Web目录中没有global.asax文件,也 就是说没有动态编译生成ASP.global_asax类型,那就直接实例化HttpApplication。如果创建了ASP.global_asax 类型,那就对ASP.global_asa进行实例化。

        
if  (applicationInstance  ==   null )
        
{
            
throw   new  HttpException(SR.GetString( " Unable_create_app_object " ));
        }

        
if  (EtwTrace.IsTraceEnabled( 5 1 ))
        
{
            EtwTrace.Trace(EtwTraceType.ETW_TYPE_START_HANDLER, extraData.WorkerRequest,
               applicationInstance.GetType().FullName, 
" Start " );
        }

        
if  (applicationInstance  is  IHttpAsyncHandler)
        
{
            IHttpAsyncHandler handler2 
=  (IHttpAsyncHandler) applicationInstance;
            extraData.AsyncAppHandler 
=  handler2;
            handler2.BeginProcessRequest(extraData, 
this ._handlerCompletionCallback, extraData);
        }

        
else
        
{
            applicationInstance.ProcessRequest(extraData);
            
this .FinishRequest(extraData.WorkerRequest, extraData,  null );
        }

    }

    
catch  (Exception exception)
    
{
        extraData.Response.InitResponseWriter();
        
this .FinishRequest(wr, extraData, exception);
    }

}

从代码上看asp.net运行时总显得很枯燥,笔者通过自己的理解画了一幅流程图,撇开了大部分代码

理解ASP.NET页面生命周期和asp.net运行时_第1张图片
asp.net2.0运行时牵涉到的内容很多,本人对.net运行时的理解或许只是停留在表面上的,如果朋友对.net运行时感兴趣的话,可以学习如下几位大牛的文章,本文的很大一部分也是参考如下文章,希望本篇文章能对你学习asp.net2.0运行时带来一点帮助.

 dudu的asp.net运行时简要分析
EagleFish的从.net类库看.net运行时
Artech的ASP.NET Process Model之二:ASP.NET Http RunTime Pipeline-PartI
Artech的ASP.NET Process Model之二:ASP.NET Http RunTime Pipeline-PartII
文野的一点一点学ASP.NET之基础概念——HTTP运行期与页面执行模型
头中中,不大的ASP.NET的(HttpModule,HttpHandler)

你可能感兴趣的:(asp.net,asp.net,postback,httpmodule,validation,iis,exception)