• 对ASP.Net的认识(三)


    较为详细的整个请求处理流程

    Application: BeginRequest
    Application: PreAuthenticateRequest
    Application: AuthenticateRequest
    Application: PostAuthenticateRequest
    Application: PreAuthorizeRequest
    Application: AuthorizeRequest
    Application: PostAuthorizeRequest
    Application: PreResolveRequestCache
    Application: ResolveRequestCache
    Application: PostResolveRequestCache
    Application: PreMapRequestHandler
    Page: Construct
    Application: PostMapRequestHandler
    Application: PreAcquireRequestState
    Application: AcquireRequestState
    Application: PostAcquireRequestState
    Application: PreRequestHandlerExecute
    Page: AddParsedSubObject
    Page: CreateControlCollection
    Page: AddedControl
    Page: AddParsedSubObject
    Page: AddedControl
    Page: ResolveAdapter
    Page: DeterminePostBackMode

    Page: PreInit
    Control: ResolveAdapter
    Control: Init
    Control: TrackViewState
    Page: Init
    Page: TrackViewState
    Page: InitComplete
    Page: LoadPageStateFromPersistenceMedium
    Control: LoadViewState
    Page: EnsureChildControls
    Page: CreateChildControls
    Page: PreLoad
    Page: Load
    Control: DataBind
    Control: Load
    Page: EnsureChildControls
    Page: LoadComplete
    Page: EnsureChildControls
    Page: PreRender
    Control: EnsureChildControls
    Control: PreRender
    Page: PreRenderComplete
    Page: SaveViewState
    Control: SaveViewState
    Page: SaveViewState
    Control: SaveViewState
    Page: SavePageStateToPersistenceMedium
    Page: SaveStateComplete
    Page: CreateHtmlTextWriter
    Page: RenderControl
    Page: Render
    Page: RenderChildren
    Control: RenderControl
    Page: VerifyRenderingInServerForm
    Page: CreateHtmlTextWriter
    Control: Unload
    Control: Dispose
    Page: Unload
    Page: Dispose
    Application: PostRequestHandlerExecute
    Application: PreReleaseRequestState
    Application: ReleaseRequestState
    Application: PostReleaseRequestState
    Application: PreUpdateRequestCache
    Application: UpdateRequestCache
    Application: PostUpdateRequestCache
    Application: EndRequest
    Application: PreSendRequestHeaders
    Application: PreSendRequestContent

    Master Page的加载顺序

    1、Master page中的用户控件的page_init

    2、aspx页面中的用户控件的page_init

    3、Master page的page_init

    4、aspx页面的page_init

    5、aspx页面的page_load

    6、Master page的page_load

    7、Master page中的用户控件的page_load

    8、aspx页面中的用户控件的page_load

    其实Master Page可以看成是一个控件。

    何时使用DataGrid/DataList/Repeater

    实现了IEnumerable接口的类的对象可以成为这三种数据控件的数据源。

    DataGrid最终会生成一个table,所以DataGridItem类继承自TableRow类。而Repeater最终生成的控件是用户自定义的,所以RepeaterItem类与TableRow类没有任何关系。DataGrid和DataList继承自WebControl类,而Repeater继承自Control类,WebControl类包含一些设置样式的属性,如BackColor,ForeColor,CssStyle,BorderStyle等,而Repeater样式的设置必须在它的Template里完成。

    DataGrid有很多功能但欠缺灵活性,使用DataGrid很便捷,因为很多功能都已经封装好,只需要设置下相应的属性即可,但也正因为这个好处,使得DataGrid比较呆板,只能使用已经做好的功能,修改现有功能会比较麻烦,而且DataGrid最终生成的是一个table,如果想生成多个table或者div,DataGrid就无能为力了。DataGrid的性能是最差的因为DataGrid会把几乎所有内容都放入它的ViewState中,如果要使用DataGrid的Sort,Paging和Edit功能就不能禁掉ViewState,这会使ViewState大到足以严重影响性能的程度。

    DataList比起DataGrid更加灵活,它可以使一行有多条记录,既可以使用table也可以使用span,不过有许多功能DataList并没有实现,需要开发人员自己实现,这样虽然会让开发人员花费更多时间但增强了灵活性,DataList的性能比起DataGrid要好。

    Repeater是最灵活的,但对开发人员的要求也是最高的,它会花费最多的开发时间,但可以实现很多DataGrid和DataList无法实现的效果和功能,而且性能是最好的。

    Page继承自TemplateControl并且实现了IHttpHandler接口,TemplateControl继承自Control,Page本身就是个HttpHandler。

    Page处理Request的流程大致如下代码所述,也就是页面处理的流程。

    private void ProcessRequestMain(bool includeStagesBeforeAsyncPoint, bool includeStagesAfterAsyncPoint)
    {
            
    // 1. PreInit
            this.PerformPreInit();
            
    // 2. Init
            this.InitRecursive(null);
            
    this.OnInitComplete(EventArgs.Empty);

            
    // 对于Postback,插入下面处理
            if (this.IsPostBack)
            
    {
                
    // 加载ViewState和ControlState,进行场景恢复
                this.LoadAllState();
                
    // 第一次处理PostData
                this.ProcessPostData(this._requestValueCollection, true);
            }


            
    // 3. PreLoad
            this.OnPreLoad(EventArgs.Empty);
            
    // 4. Load
            this.LoadRecursive();

            
    // 对于Postback,插入下面处理
            if (this.IsPostBack)
            
    {
                
    // 第二次处理PostData
                this.ProcessPostData(this._leftoverPostData, false);
                
    // 如果PostData表面某个Control数据发生变化,那么RaisePostDataChanged事件
                this.RaiseChangedEvents();
                
    // RaisePostBackEvent
                this.RaisePostBackEvent(this._requestValueCollection);
            }


            
    this.OnLoadComplete(EventArgs.Empty);

            
    // 对于CallBack,RaiseCallBackEvent
            if (this.IsPostBack && this.IsCallback)
            
    {
                
    this.PrepareCallback(callbackControlID);
            }

            
    else if (!this.IsCrossPagePostBack)
            
    {
                
    // 5. PreRender
                this.PreRenderRecursiveInternal();
            }

       
            
    // 对于CallBack, Render出CallBack的结果
            if (this.IsCallback)
            
    {
                
    this.RenderCallback();
            }

            
    else if (!this.IsCrossPagePostBack)
            
    {
                
    this.PerformPreRenderComplete();
                
                
    // 6. SaveViewStae和ControlState
                this.SaveAllState();
                
    this.OnSaveStateComplete(EventArgs.Empty);

                
    // 7. Render 整个Control
                this.RenderControl(this.CreateHtmlTextWriter(this.Response.Output));
            }

    }

    其中,PerformPreInit方法代码如下,可以发现PreInit时主要初始化Themes,加载MasterPage。

    private void PerformPreInit()
    {
        
    this.OnPreInit(EventArgs.Empty);
        
    this.InitializeThemes();
        
    this.ApplyMasterPage();
        
    this._preInitWorkComplete = true;
    }

    Page以及每个Control都有个ControlState属性,该属性用于记录Page处理到哪个阶段了,例如Init阶段结束时,这个属性会被赋值ControlState.Initialized,从而表明Init阶段的结束。这个属性会被用于很多地方,例如当添加一个动态控件时,父控件的AddedControl方法就会检查这个属性,如果已经过了Init阶段,则直接初始化添加的控件。ControlState和ViewState最大的区别是ControlState是无法被禁止的,并且ControlState里有个ArrayList,这个ArrayList保存了需要处理PostBackData的Control的ID,当处理PostBackData时就会从这个ArrayList里获取需要处理的Control的ID。

    下面是Control.AddedControl方法的代码,

    protected internal virtual void AddedControl(Control control, int index)
    {
        
    // 1. 初始化Page,Parent,NameContainer,ID
        control._parent = this;
        control._page 
    = this.Page;
        control.flags.Clear(
    0x20000);
        Control namingContainer 
    = this.flags[0x80? this : this._namingContainer;
        
    if (namingContainer != null)
        
    {
            control.UpdateNamingContainer(namingContainer);
            
    if ((control._id == null&& !control.flags[0x40])
            
    {
                control.GenerateAutomaticID();
            }

            
    else if ((control._id != null|| ((control._occasionalFields != null&& (control._occasionalFields.Controls != null)))
            
    {
                namingContainer.DirtyNameTable();
            }

        }


        
    // 2. 判断当前Control所在的页面生命周期阶段,然后对于新加入的Control进行补充调用
        if (this._controlState >= ControlState.ChildrenInitialized)
        
    {
            control.InitRecursive(namingContainer);
            
    if (((control._controlState >= ControlState.Initialized) && (control.RareFields != null)) && control.RareFields.RequiredControlState)
            
    {
                
    this.Page.RegisterRequiresControlState(control);
            }

            
    if (this._controlState >= ControlState.ViewStateLoaded)
            
    {
                
    object savedState = null;
                
    if ((this._occasionalFields != null&& (this._occasionalFields.ControlsViewState != null))
                
    {
                    savedState 
    = this._occasionalFields.ControlsViewState[index];
                    
    if (this.LoadViewStateByID)
                    
    {
                        control.EnsureID();
                        savedState 
    = this._occasionalFields.ControlsViewState[control.ID];
                        
    this._occasionalFields.ControlsViewState.Remove(control.ID);
                    }

                    
    else
                    
    {
                        savedState 
    = this._occasionalFields.ControlsViewState[index];
                        
    this._occasionalFields.ControlsViewState.Remove(index);
                    }

                }

                control.LoadViewStateRecursive(savedState);
                
    if (this._controlState >= ControlState.Loaded)
                
    {
                    control.LoadRecursive();
                    
    if (this._controlState >= ControlState.PreRendered)
                    
    {
                        control.PreRenderRecursiveInternal();
                    }

                }

            }

        }

    }

    Control的卸载也是递归调用的。

    对于需要用ASP.Net进行身份验证的页面,即使所有内容是静态的,也需要将后缀名改成aspx而不能用html,这是因为html将不会被ASP.Net的ISAPI所处理,也就无法进行身份验证。

    aspx页面一般有ASP.Net自带的页处理程序来处理,它是Http处理程序中的一种,另外还有处理asmx的Web服务处理程序,如果需要针对特别的后缀名进行特别处理,需要创建一个自定义的Http处理程序,然后在IIS中将扩展名映射到ASP.Net的ISAPI中,并且在Web.config中注册这个处理程序。在Web.config中的注册如下代码所示

    <configuration>
        <system.web>
            <httpHandlers>  <add verb="*" path="*.sample" type="MyHandler"/></httpHandlers>
        </system.web>
    </configuration>

    创建一个自定义的Http处理程序,有两种方式,

    1、实现IHttpHandler接口创建同步处理程序

    2、实现IHttpAsyncHandler接口创建异步处理程序

    这个两个接口都需要实现IsReusable属性和ProcessRequest方法。IsReusable属性用于确定HttpHandlerFacotry对象(接收请求并调用相应的处理程序的对象)是否可以把该处理程序放入池中以便重复使用来提高性能,如果不可以的话,那么每次都要创建一个该处理程序的实例。ProcessRequest方法用于处理单个Http请求。如果Http处理程序的扩展名为ashx,那么这个处理程序会自动注册到IIS和ASP.Net中。异步处理程序可以启动一个外部进程,ASP.Net会将用于外部进程的线程放回线程池中以提高性能,直至外部进程处理结束进行回调为止。异步处理程序还必须实现BeginProcessRequest和EndProcessRequest方法。

    另外可以通过实现IHttpHandlerFactory接口来自定义HttpHandlerFactory,这样做更具有灵活性,可以根据Http请求的具体命令(HttpContext.Request.RequestType,如PUT,GET,POST等)做一些处理,例如对于不同的命令调用不同的处理程序。在创建了自定义的HttpHandlerFactory以后需要在Web.config和IIS中进行注册。在Web.config中添加如下代码

    <configuration>
      <system.web>
        <httpHandlers>      <add verb="GET,POST" path="*.sample" type="MyHandlerFactory" />    </httpHandlers>
      </system.web>
    </configuration>
    在IIS中需要对文件后缀名与ASP.Net的ISAPI进行映射。

    ApplicationManager类在asp.net 2.0及之后版本用于创建并管理AppDomain。

  • 相关阅读:
    这样设计是否更好些~仓储接口是否应该设计成基础操作接口和扩展操作接口
    爱上MVC3~MVC+ZTree实现对树的CURD及拖拽操作
    Android自定义图形,图形的拼接、叠加、相容
    CSDN问答频道“华章杯”7月排行榜活动开始,丰厚奖品等你拿
    修改MyEclipse内存-------OutOfMemoryError错误
    MySQL中MySQL X.X Command Line Client一闪而过的问题
    C++组合问题
    Android编程之仿微信显示更多文字的View
    理解MapReduce哲学
    mysql 备份
  • 原文地址:https://www.cnblogs.com/loofywang/p/MyUnderstandingOfASPNET3.html
Copyright © 2020-2023  润新知