http://book.51cto.com/art/201201/312514.htm
ASP.NET如何将一个HTML按钮的单击转化为服务器的Click()事件呢?为了找到答案,必须检查一个包含有合适控件的ASP.NET页面。
程序清单2-4显示一个简单的Web页面,页面中有3个Label控件,分别是用来说明请求的类型(GET或POST)、用来判断此页面是否是PostBack的true或false标识(随后给出PostBack的解释)、一条消息(如果单击页面中的链接按钮时就出现此消息)。页面也会显示所发送的表单参数(如果有的话)。
程序清单2-4 含有按钮事件的ASP.NET页面
- <%@ Page Language="C#" %>
- <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
- "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
- <script runat="server">
- protected void Page_Load(object sender, EventArgs e)
- {
- requestType.Text = Request.HttpMethod;
- cameFromPostBack.Text = Page.IsPostBack.ToString();
- }
- protected void button_Clicked(object sender, EventArgs e)
- {
- message.Text = "You clicked the button";
- }
- </script>
- <html xmlns="http://www.w3.org/1999/xhtml">
- <head runat="server">
- <title>Postback Demo</title>
- </head>
- <body>
- <form id="form1" runat="server">
- <div>
- Request Type: <asp:Label ID="requestType" runat="server"/><br />
- IsPostback: <asp:Label ID="cameFromPostBack" runat="server"/><br />
- <asp:Label ID="message" runat="server" /><br />
- <asp:LinkButton ID="button" runat="server"
- OnClick="button_Clicked" Text="Click me!" />
- </div>
- </form>
- <h3>Post Parameters</h3>
- <% foreach (string key in Request.Form.Keys)
- Response.Write(key + " = " + Request.Form[key] + "<br />");
- %>
- </body>
- </html>
如果创建此页面并运行它,就可以在浏览器中查看页面源码(在页面中右击,如果是IE,就选择View Source命令;如果是Firefox浏览器,就选择View Page Source命令)。您会注意到,页面代码可能与您期望的不同。程序清单 2-5显示了此页面的HTML源码。
程序清单2-5 程序清单2-4中演示的页面的HTML源码
- <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
- "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
- <html xmlns="http://www.w3.org/1999/xhtml">
- <head><title>
- Postback Demo
- </title></head>
- <body>
- <form name="form1" method="post" action="PostbackDemo.aspx" id="form1">
- <div>
- <input type="hidden" name="__EVENTTARGET" id="__EVENTTARGET" value="" />
- <input type="hidden" name="__EVENTARGUMENT" id="__EVENTARGUMENT" value="" />
- <input type="hidden" name="__VIEWSTATE" id="__VIEWSTATE"
- value="/wEPDwUJMzYxMzIzNzk3D2QWAgIBD2QWBAIBDw8WAh4EVGV4d
- AUDR0VUZGQCAw8PFgIfAAUFRmFsc2VkZGTofcMG0NrB6D7A9nQm6it+z6YhSA==" />
- </div>
- <script type="text/javascript">
- //<![CDATA[
- var theForm = document.forms['form1'];
- if (!theForm) {
- theForm = document.form1;
- }
- function __doPostBack(eventTarget, eventArgument) {
- if (!theForm.onsubmit || (theForm.onsubmit() != false)) {
- theForm.__EVENTTARGET.value = eventTarget;
- theForm.__EVENTARGUMENT.value = eventArgument;
- theForm.submit();
- }
- }
- //]]>
- </script>
- <div>
- <input type="hidden" name="__EVENTVALIDATION" id="__EVENTVALIDATION"
- value="/wEWAgKwgoeZCwLz9r7ABKfiEt1R2MFVeeJ0uDoFqNVcv8pj" />
- </div>
- <div>
- Request Type: <span id="requestType">GET</span><br />
- IsPostback: <span id="cameFromPostBack">False</span><br />
- <span id="message"></span><br />
- <a id="button"
- href="javascript:__doPostBack('button','')">Click me!</a>
- </div>
- </form>
- <h3>Post Parameters</h3>
- </body>
- </html>
此HTML源码包含几个感兴趣的地方。写本章内容时,在程序清单2-4中演示的页面被命名为PostbackDemo.aspx,本页面的HTML表单的action参数指回本页面。本页面中还有4个隐藏的表单域:_EVENTTARGET、_EVENTARGUMENT、_EVENTVALIDATION和_VIEWSTATE,还插入了一个用JavaScript编写的函数:_doPostBack()。最后,链接按钮已经作为<a>元素来呈现,并且具有一个客户端事件,用来调用插入的_doPostBack()函数。
当您仔细检查_doPostBack()函数时,会发现在此方法中,在调用表单的JavaScript submit()方法之前(submit()方法会导致浏览器提交包含这两个隐藏域的表单),首先设置两个隐藏域:_EVENTTARGET和_EVENTARGUMENT。
通过结合使用页面回发到自身(PostBack)和使用JavaScript设置事件源(和任意参数)这两种方式,允许ASP.NET实现事件模型。PostBack的生命周期如下:
(1) 第一次加载页面(通常是通过一个GET请求),ASP.NET创建Page对象和页面中所包含的所有控件。Page事件被触发,HTML被提交和返回到客户端。此时,释放Page对象(包括页面中所有的对象),最后,当.NET垃圾回收器运行时,所用的内存也被释放。
(2) 在客户端浏览器中,用户将执行一个创建PostBack的行为,如单击一个链接或按钮,或改变一个列表框选择项等。这些行为者中与客户端的JavaScript事件相联系,此事件将调用_doPostBack()方法,然后将本页面和表单数据提交到服务器。
(3) ASP.NET创建一个新的page对象,并重新创建控件,当页面最后一次发送到客户端时,使用_VIEWSTATE域来设置对象的返回状态,并且运行页面初始化事件。
(4) 在_EVENTTARGET和_EVENTARGUMENT域设置结束后,ASP.NET使用EVENTVALIDATION域检查事件的有效性(例如,如果黑客通过隐藏的或不能使用的控件伪造了事件,就会发生异常)。然后ASP.NET使用_EVENTTARGET和_EVENTARGUMENT域决定触发哪一个服务器端的事件,然后引发该事件。在服务器端的事件代码中,页面通常以某种方式被修改(例如,计算一个新的价格或从数据库中检索信息)。
(5) 最后,将经过修改的页面呈现给HTML,并发送到客户端。Page对象(和那些页面元素成员)从内存中释放,如果此时有另外的PostBack发生,那么处理将从第(2)步重新开始。
如果对_EVENTVALIDATION和_VIEWSTATE域感兴趣,在第4章和第5章将有更详细的介绍。在整个生命周期中,触发很多事件用来构建页面,从ViewState重新创建控件内容,触发事件,最后呈现页面。如果您想看看页面生命周期中那些主要的事件,那么可以通过在页面声明中添加Trace="true"来启动跟踪,例如:
- <%@ Page Language="C#" Trace="true" %
当启动跟踪时,调试信息也被添加到每一个页面中,如图2-8所示,显示了来自一个跟踪的事件信息示例。可以看到当加载完成页面后,处理回发事件。所以,在一个已经是产品的Web站点中从来也不要启用跟踪,否则,攻击者将很容易从跟踪数据中获取有关信息。
(点击查看大图)图2-8 事件跟踪数据 |