唐山网站建设

设为主页 加入收藏 繁體中文

ASP.NET Web Page利用深进探讨

核心提示:ASP.NETWebPage利用深进探讨,浏览ASP.NETWebPage利用深进探讨,1、服务器脚本基础先容首先,我们先复习1下Web服务器页面的基本履行方式:1、客户端通过在浏览器的地址栏敲进地址来发送要求到服务器端2、服务器接收到要求以后,发给相应的服务器端页面(也就是脚本)来

1、服务器脚本基础先容

首先,我们先复习1下Web服务器页面的基本履行方式:

1、客户端通过在浏览器的地址栏敲进地址来发送要求到服务器端

2、服务器接收到要求以后,发给相应的服务器端页面(也就是脚本)来履行,脚本产生客户真个响应,发送回客户端

3、客户端浏览器接收到服务器传回的响应,对Html进行解析,将图形化的网页显现在用户眼前

对服务器和客户真个交互,通常通过下面几种主要方式:

1、Form:这是最主要的方式,标准化的控件来获得用户的输进,Form的提交将数据发送给服务器端处理

2、QueryString:通过在Url后面带参数到达将参数传送给服务器,这类方式实在跟Get方式的Form是1样的

3、Cookies:这是1种比较特殊的方式,通常常使用于用户身份的确认

2、ASP.Net简介

传统的服务器脚本语言,如ASP、JSP等,编写服务器脚本的方式大同小异,都是在Html中嵌进解释或编译履行的代码,由服务器平台履行这些代码来天生Html;对这类似的脚本,页面的生存周期实际上很简单,就是从开头至末尾,履行完所有的代码,固然用Java编写的Servlet可以编写更复杂的代码,但是从结构上看,和JSP没甚么辨别。

ASP.Net的出现,打破了这类传统;ASP.Net采取了CodeBehind技术和服务器端控件,加进了服务器真个事件的概念,改变了脚本语言编写的模式,更加贴近Window编程,使Web编程更加简单、直观;但是我们要看到,ASP.Net本身并没有改变Web编程的基本模式,只是封装了1些细节、提供了1些易用的功能,使代码更轻易编写和保护;从某种程度上来讲,将服务器端履行的方式复杂化了,这就是我们今天要讨论的主体:ASP.NetWebPage的生存周期。

1 2 3 4 下1页

核心提示:ASP.NETWebPage利用深进探讨,浏览ASP.NETWebPage利用深进探讨,1、服务器脚本基础先容首先,我们先复习1下Web服务器页面的基本履行方式:1、客户端通过在浏览器的地址栏敲进地址来发送要求到服务器端2、服务器接收到要求以后,发给相应的服务器端页面(也就是脚本)来

3、ASP.Net要求处理模式

我们说,ASP.Net的WebPage并没有脱离Web编程的模式,所以它依然是以要求->接收要求->处理要求->发送响应这样的模式在工作,每1次与客户真个交互都会引发1次新的要求,所以1个WebPage的生命周期是以1次要求为基础的。

当IIS收到客户真个要求的时候,会将要求交给aspnet_wp这个进程来处理,这个进程会查看要求的利用程序域是否是存在,假设不存在则会创建1个,然后会创建1个Http运行时(HttpRuntime)来处理要求,这个运行时“为当前利用程序提供1组ASP.NET运行时服务”(摘自MSDN)。

HttpRuntime在处理要求的时候,会保护1系列的利用程序实例,也就是利用程序的Global类(global.asax)的实例,这些实例在没有要求的时候,会寄存在1个利用程序池中(实际上利用程序池由另1个类来保护,HttpRuntime只是简单的调用),每接收到1个要求,HttpRuntime都会获得1个闲置的实例来处理要求,这个实例在要求结束前不会处理其他的要求,处理终了以后,它又会回到池中,“1个实例在其生存期内被用于处理多个要求,但它1次只能处理1个要求。”(摘自MSDN)

当利用程序实例处理要求的时候,它会创建要求页面类的实例,履行它的ProcessRequest方法来处理要求,这个方法也就是WebPage生命周期的开始。

4、Aspx页面与CodeBehind

在深进了解页面的生命周期之前,我们先来探讨1些Aspx与CodeBehind之间的关系。

<%@Pagelanguage="c#"Codebehind="WebForm.aspx.cs"Inherits="MyNamespace.WebForm"%>

相信使用过CodeBehind技术的朋友,对ASPX顶部的这句话应当是非常熟习了,我们来1项1项的分析它:

Pagelanguage="c#"这个就不用多说了吧

Codebehind="WebForm.aspx.cs"这1句表示绑定的代码文件

Inherits="MyNamespace.WebForm"这句非常重要,它表示页面继续的类名称,也就是CodeBehind的代码文件中的类,这个类必须从System.Web.WebControls.Page派生

从上面我们可以分析出,实际上CodeBehind中的类就是页面(ASPX)的基类,到这里,可能有些朋友要问了,在编写ASPX的时候,完全是依照ASP的方式,在Html中嵌进代码或嵌进服务器控件,没有看到所谓“类”的影子啊?

这个题目实际上其实不复杂,各位使用ASP.Net编程的朋友可以到你们的系统盘:\WINDOWS\Microsoft.NET\Framework\<版本号>\TemporaryASP.NETFiles这个目录下,这个下面就放了所有本机上存在的ASP.Net利用程序的临时文件,子目录的名称就是利用程序的名称,然后再下往两层(为了保证唯1,ASP.Net自动产生了两层子目录,并且子目录名称是随机的),然后我们会发现有很多类似:“yfy1gjhc.dll”、“xeunj5u3.dll”这样的链接库和“komee-bp.0.cs”、“9falckav.0.cs”这样的源文件,实际上这就是ASPX被ASP.Net动态编译后的结果,打开这些源文件我们可以发现:

publicclassWebForm_aspx:MyNamespace.WebForm,System.Web.SessionState.IRequiresSessionState

这就印证了我们前面的说法,ASPX是代码绑定类的子类,它的名称是ASPX文件名加上“_aspx”后缀,通过研究这些代码我们可以发现,实际上所有aspx中定义的服务器控件都是在这些代码中天生的,然后动态产生这些代码的时候,把原来在ASPX中嵌进的代码写在了相应的位置。

当某个页面第1次被访问的时候,Http运行时就会使用1个代码天生器往解析ASPX文件并天生源代码并编译,然后以后的访问就直接调用编译后的dll,这也是为甚么ASPX第1次访问的时候非常慢的缘由。

解释了这个题目,我们再来看另1个题目。我们在使用代码绑定的时候,在设计页面拖1个控件,然后切换到代码视图,便可以够直接在Page_Load中使用这个控件了,既然控件是在子类中产生的,那为甚么在父类中可以直接使用呢?

实际上我们可以发现,每当用VS.Net拖1个控件到页面上,代码绑定文件中总是会类似这样的添加1个声明:

protectedSystem.Web.WebControls.ButtonButton1;

我们可以发现这个字段被声明成protected,而且名字与ASPX中控件的ID1致,仔细想1想,这个题目就迎刃而解了。我们前面提到ASPX的源代码是被天生器动态天生和编译的,天生器会产生动态天生每1个服务器控件的代码,在天生的时候,它会检查父类有无声明这个控件,假设声明了,它会添加类似下面的1句代码:

this.DataGrid1=__ctrl;

这个__ctrl就是天生该控件的变量,这时候候它就把控件的援用赋给了父类中相应的变量,这也是为甚么父类中的声明必须为protected(实际上也能够为public),由于要保证子类能够调用。

然后在履行Page_Load的时候,由于这时候候父类的声明已被子类中的初始化代码赋了值,所以我们便可以够使用这个字段来访问对应的控件,了解了这些,我们就不会犯在代码绑定文件中的构造器里使用控件,造成空援用的异常的毛病了,由于构造器是最早履行的,这时候候子类的初始化还没有开始,所以父类中的字段是空值,至于子类是甚么时候初始化我们放到后面讨论。

上1页 1 2 3 4 下1页

核心提示:ASP.NETWebPage利用深进探讨,浏览ASP.NETWebPage利用深进探讨,1、服务器脚本基础先容首先,我们先复习1下Web服务器页面的基本履行方式:1、客户端通过在浏览器的地址栏敲进地址来发送要求到服务器端2、服务器接收到要求以后,发给相应的服务器端页面(也就是脚本)来

5、页面生存周期

现在回到第3个标题中讲到的内容,我们讲到了HttpApplication的实例接收要求,并创建页面类的实例,实际上这个实例也就是动态编译的ASPX的类的1个实例,上1个标题中我们了解到ASPX实际上是代码绑定中类的子类,所以它继续了所有的protected方法。

现在我们来看看VS.Net自动天生的CodeBehind类的代码,以此来开始我们对页面生命周期的探讨:

#regionWebFormDesignergeneratedcode

overrideprotectedvoidOnInit(EventArgse)
{
 //
 //CODEGEN:该调用是ASP.NETWeb窗体设计器所必须的。
 //
 InitializeComponent();
 base.OnInit(e);
}

///


///设计器支持所需的方法-不要使用代码编辑器修改
///此方法的内容。
///

privatevoidInitializeComponent()
{
 this.DataGrid1.ItemDataBound+=newSystem.Web.UI.WebControls.DataGridItemEventHandler(this.DataGrid1_ItemDataBound);

 this.Load+=newSystem.EventHandler(this.Page_Load);
}

#endregion

这个就是使用VS.Net产生的Page的代码,我们来看,这里面有两个方法,1个是OnInit,1个是InitializeComponent,后者被前者调用,实际上这就是页面初始化的开始,在InitializeComponent中我们看到了控件的事件声明和Page的Load声明。

下面是从MSDN中摘录的1段描写和1个页面生命周期方法和事件触发的顺序表:

“每次要求ASP.NET页时,服务器就会加载1个ASP.NET页,并在要求完成时卸载该页。页及其包括的服务器控件负责履行要求并将HTML显现给客户端。固然客户端和服务器之间的通讯是无状态的和断续的,但是必须使客户感觉到这是1个连续履行的进程。”

“这类连续性假象是由ASP.NET页框架、页及其控件实现的。回发后,控件的行动必须看起来是从上次Web要求结束的地方开始的。固然ASP.NET页框架可使履行状态治理相对轻易1些,但是为了取得连续性效果,控件开发职员必须知道控件的履行顺序。控件开发职员需要了解:在控件生命周期的各个阶段,控件可使用哪些信息、保持哪些数据、控件显现时处于哪种状态。例如,在填充页上的控件树之前控件不能调用其父级。”“下表提供了控件生命周期中各阶段的高级概述。有关具体信息,请点击表中的链接。”

阶段控件需要履行的操纵要重写的方法或事件 初始化初始化在传进Web要求生命周期内所需的设置。请参阅处理继续的事件。Init事件(OnInit方法) 加载视图状态在此阶段结束时,就会自动填充控件的ViewState属性,详见保护控件中的状态中的先容。控件可以重写LoadViewState方法的默许实现,以自定义状态还原。LoadViewState方法 处理回发数据处理传进窗体数据,并相应地更新属性。请参阅处理回发数据。
留意只有处理回发数据的控件参与此阶段。LoadPostData方法(假设已实现IPostBackDataHandler) 加载履行所有要求共有的操纵,如设置数据库查询。此时,树中的服务器控件已创建并初始化、状态已还原并且窗体控件反应了客户真个数据。请参阅处理继续的事件。Load事件
(OnLoad方法) 发送回发更改通知引发更改事件以响应当前和之前回发之间的状态更改。请参阅处理回发数据。

留意只有引发回发更改事件的控件参与此阶段。RaisePostDataChangedEvent方法
(假设已实现IPostBackDataHandler) 处理回发事件处理引发回发的客户端事件,并在服务器上引发相应的事件。请参阅捕捉回发事件。

留意只有处理回发事件的控件参与此阶段。RaisePostBackEvent方法
(假设已实现IPostBackEventHandler) 预显现在显现输出之前履行任何更新。可以保存在预显现阶段对控件状态所做的更改,而在显现阶段所对的更改则会丢失。请参阅处理继续的事件。PreRender事件
(OnPreRender方法) 保存状态在此阶段后,自动将控件的ViewState属性保持到字符串对象中。此字符串对象被发送到客户端并作为隐躲变量发送回来。为了进步效率,控件可以重写SaveViewState方法以修改ViewState属性。请参阅保护控件中的状态。SaveViewState方法 显现天生显现给客户真个输出。请参阅显现ASP.NET服务器控件。Render方法 处置履行烧毁控件前的所有终极清算操纵。在此阶段必须开释对昂贵资源的援用,如数据库链接。请参阅ASP.NET服务器控件中的方法。
Dispose方法 卸载履行烧毁控件前的所有终极清算操纵。控件作者通常在Dispose中履行清除,而不处理此事件。UnLoad事件(OnUnLoad方法)

从这个表里面我们可以清楚的看到1个Page从装载到卸载之间调用的方法和触发的时间,接下来我们就深进的对其进行1些分析。

看了上面的表,仔细的朋友可能要问了,既然OnInit是页面生命周期的开始,而我们在上1讲中谈到控件在子类中被创建,那末在这里实际上在InitializeComponent方法中我们已可使用父类中申明的字段了,那末就意味着子类的初始化更在这之前?

在第3个标题中我们讲到了页面类的ProcessRequest才是真正意义上的页面声明周期的开始,这个方法是由HttpApplication调用的(其中调用的方式比较复杂,有机会单独撰文来讲授),1个Page对要求的处理就是从这个方法开始,通过反编译.Net类库来查看源代码,我们发现在System.Web.WebControls.Page的基类:System.Web.WebControls.TemplateControl(它是页面和用户控件的基类)中定义了1个“FrameworkInitialize”虚拟方法,然后在Page的ProcessRequest中最早调用了这个方法,在天生器天生的ASPX的源代码中我们发现了这个方法的踪影,所有的控件都在这个方法中被初始化,页面的控件树就在这个时候产生。

上1页 1 2 3 4 下1页

核心提示:ASP.NETWebPage利用深进探讨,浏览ASP.NETWebPage利用深进探讨,1、服务器脚本基础先容首先,我们先复习1下Web服务器页面的基本履行方式:1、客户端通过在浏览器的地址栏敲进地址来发送要求到服务器端2、服务器接收到要求以后,发给相应的服务器端页面(也就是脚本)来

接下来的事情就简单了,我们来逐渐分析页面生命周期的每1项:

1、初始化

初始化对应Page的Init事件和OnInit方法。

假设要重写,MSDN推荐的方式是重载OnInti方法,而不是增加1个Init事件的代理,这二者是有差别的,前者可以控制调用父类OnInit方法的顺序,而后者只能在父类的OnInit后履行(实际上是在OnInit里面被调用的)。

2、加载视图状态

这是个比较重要的方法,我们知道,对每次要求,实际上是由不同的页面类实例来处理的,为了保证blicvirtualboolostDataKey是标识控件的关键字(也就是postCollection中的Key),postCollection是包括回发数据的集合,我们可以重写这个方法,然后检查回发的数据是否是产生了变化,假设是则返回1个True,“假设控件状态因回发而更改,则LoadPostData返回true;否则返回false。页框架跟踪所有返回true的控件并在这些控件上调用RaisePostDataCh个方法是System.Web.WebControls.Control中定义的,也是所有需要处理事件的自定义控件需要处理的方法,对我们今天讨论的Page来讲,可以不用管它。

3、处理回发数据

这个方法是用来检查客户端发回的控件数据的状态是否是产生了改变。方法的原型:

publicvirtualboolLoadPostData(stringpostDataKey,NameValueCollectionpostCollection)

postDataKey是标识控件的关键字(也就是postCollection中的Key),postCollection是包括回发数据的集合,我们可以重写这个方法,然后检查回发的数据是否是产生了变化,假设是则返回1个True,“假设控件状态因回发而更改,则LoadPostData返回true;否则返回false。页框架跟踪所有返回true的控件并在这些控件上调用RaisePostDataChangedEvent。”(摘自MSDN)

这个方法是System.Web.WebControls.Control中定义的,也是所有需要处理事件的自定义控件需要处理的方法,对我们今天讨论的Page来讲,可以不用管它。

4、加载

加载对应Load事件和OnLoad方法,对这个事件,相信大多数朋友都会比较熟习,用VS.Net天生的页面中的Page_Load方法就是响应Load事件的方法,对每1次要求,Load事件都会触发,Page_Load方法也就会履行,相信这也是大多数人了解ASP.Net的第1步

Page_Load方法响应了Load事件,这个事件是在System.Web.WebControl.Control类中定义的(这个类是Page和所有服务器控件的祖宗),并且在OnLoad方法中被触发。

很多人可能碰到过这样的事情,写了1个PageBase类,然后在Page_Load中来验证用户信息,结果发现不管验证是否是成功,子类页面的Page_Load总是会先履行,这个时候很可能留下1些安全性的隐患,用户可能在没有得到验证的情况下就履行了子类中的Page_Load方法。

出现这个题目的缘由很简单,由于Page_Load方法是在OnInit中被添加到Load事件中的,而子类的OnInit方法中是先添加了Load事件,然后再调用base.OnInit,这样就造成了子类的Page_Load被先添加,那末先履行了。

解决这个题目也很简单,有两种方法:

1)在PageBase中重载OnLoad方法,然后在OnLoad中验证用户,然后调用base.OnLoad,由于Load事件是在OnLoad中触发,这样我们便可以够保证在触发Load事件之前验证用户。

 2)在子类的OnInit方法中先调用base.OnInit,这样来保证父类先履行Page_Load

 5、发送回发更改通知

 这个方法对应第3步的处理回发数据,假设处理回发数据返回True,页面框架就会调用此方法来触发数据更改的事件,所以自定义控件的回发数据更改事件需要在此方法中触发。

 一样这个方法对Page来讲,没有太大的用处,固然你也能够在Page的基础上自己定义数据更改的事件,这固然也是可以的。

 6、处理回发事件

 这个方法是大多数服务器控件事件引发的地方,当要求中包括控件事件触发的信息时(服务器控件的事件是另1个论题,我会在不久将来另外撰文讨论),页面控件会调用相应控件的RaisePostBackEvent方法来引发服务器真个事件。

 这里又引出1个常见的题目:

常常有网友问,为甚么修改提交后的数据并没有更改

多数的情况都是他们没有理解服务器事件的触发流程,我们可以看出,触发服务器事件是在Page的Load以后,也就是说页面会先履行Page_Load,然后才会履行按钮(这里以按钮为例)的点击事件,很多朋友都是在Page_Load中绑定数据,然后在按钮事件中处理更改,这样做有1个毛病,Page_Load永久都是在按钮事件之前履行,那末意味着数据还没来得及更改,Page_Load中的数据绑定的代码就先履行了,原本的数据又赋给了控件,那末履行按钮事件的时候,实际上取得的是原本的数据,那末更新固然就没有效果了。

更改这个题目也非常简单,比较公道的做法是把数据绑定的代码写成1个方法,我们假定为BindData:

privatevoidBindData()
{
 //绑定数据
}

然后修改PageLoad:

privatevoidPage_Load(objectsender,EventArgse)
{
 if(!IsPostBack)
 {
BindData();//在页面第1次访问的时候绑定数据
 }
}

最后在按钮事件中:

privateButton1_Click(objectsender,EventArgse)
{
 //更新数据
 BindData();//重新绑定数据
}

7、预显现

终极要求的处理都会转变成发回服务器的响应,预显现这个阶段就是履行在终极显现之前所作的状态的更改,由于在显现1个控件之前,我们必须根据它的属性来产生Html,比如Style属性,这是最典型的例子,在预显现之前,我们可以更改1个控件的Style,当履行预显现的时候,我们便可以够把Style保存下来,作为显现阶段显示Html的样式信息。

8、保存状态

这个阶段是针对加载状态的,我们屡次提到,要求之间是不同的实例在处理,所以我们需要把本次的页面和控件的状态保存起来,这个阶段就是把状态写进ViewState的阶段。

9、显现

到这里,实际上页面对要求的处理基本就告1段落了,在Render方法中,会递回全部页面的控件树,顺次调用Render方法,把对应的Html代码写进终极响应的流中。

10、处置

实际上就是Dispose方法,在这个阶段会开释占用的资源,例如数据库连接。

11、卸载

最后,页面会履行OnUnLoad方法触发UnLoad事件,处理在页面对象被烧毁之前的最后处理,实际上ASP.Net提供这个事件只是设计上的考虑,通常资源的开释都会在Dispose方法中完成,所以这个方法也变成鸡肋了。

我们简单的先容了页面的生存周期,对服务器端事件的处理做了不太深进的讲授,今天主要是想大家了解页面履行的周期,对服务器控件的事件和生存期我会在后续在写1些文章来探讨。

这些内容是我在学习ASP.Net的时候对Page研究的1些心得,具体的细节没有很具体的探讨,更多的内容请大家参考MSDN,但是我举了1些初学者常犯的毛病和出现毛病的缘由,希看可以给大家带来启发。 上1页 1 2 3 4 唐山网站建设www.fw8.net
TAG:方法,事件,服务器,控件,页面
评论加载中...
内容:
评论者: 验证码: