对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。

posted @ 2013-07-24 21:09  loofywang  阅读(640)  评论(1编辑  收藏  举报