我们知道,在默认的情况下,当我们点击Asp.net Page中的一个服务器Button时(默认其实是Submit Form),会导致Page被Recreated,这个过程我们称之为Postback,它是Page生命周期的一个阶段。我们将从以下几个方面来简单谈谈Asp.net中的Postback:

  1. 为什么使用Postback
  2. Postback工作过程
  3. 为什么使用Callback
  4. Callback工作过程
  5. Postback与Callback的区别
  6. 参考资料

1.为什么使用Postback

当我们每次通过浏览器在向服务器请求一个Page时,由于http是无状态协议,对于服务器来说,都是一个新的请求。然而,在有的时候,我们希望在新请求中能够保存上一次请求页面状态,这正是Postback的由来。那页面状态是如何保持的呢,这里引入了ViewState机制,工作原理大致如下:一个请求到达服务器后,最终,服务器在Render Html时,会将页面所有EnableViewState属性为true的服务器Control状态序列化,然后通过默认的SHA1算法(可在Config中配置)加密输出,输出内容是在中,当点击页面按钮时,会调用生成的会将表单和__VIEWSTATE隐藏域提交给Form,服务器端Page在Load的时候通过IsPostBack属性判断出来是PostBack请求,就会将__VIEWSTATE的值反序列化来设置控件状态,最后将当前页面状态Render到Html,这是一个流程。

2.Postback工作过程

首先,我们来举个简单的例子: 创建一个如下的Aspx页面:

<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="WebForm4.aspx.cs" Inherits="_2PostBack.WebForm4" %>

<!DOCTYPE html>

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title></title>
</head>
<body>
<form id="form1" runat="server">
<asp:Label ID="Label1" runat="server" Text="Label"></asp:Label>
<asp:TextBox ID="TextBox1" runat="server"></asp:TextBox>
<asp:DropDownList ID="DropDownList1" runat="server" OnSelectedIndexChanged="DropDownList1_SelectedIndexChanged" AutoPostBack="true">
<asp:ListItem Text="郑州" Value="1"></asp:ListItem>
<asp:ListItem Text="洛阳" Value="2"></asp:ListItem>
</asp:DropDownList>
<asp:Button ID="Button1" runat="server" Text="Button1" OnClick="Button1_Click" OnCommand="Button1_Command" CommandArgument="button1"/>
<asp:Button ID="Button2" runat="server" Text="Button2" OnClick="Button2_Click" OnCommand="Button1_Command" CommandArgument="button2" UseSubmitBehavior="false"/>
</form>
</body>
</html>

Code behind代码:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls; namespace _2PostBack
{
public partial class WebForm4 : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{ } protected void Button1_Click(object sender, EventArgs e)
{
this.Label1.Text = "";
this.TextBox1.Text = "";
} protected void DropDownList1_SelectedIndexChanged(object sender, EventArgs e)
{
this.Label1.Text = this.DropDownList1.SelectedItem.Text + "被选中";
} protected void Button2_Click(object sender, EventArgs e)
{
//this.ClientScript.RegisterClientScriptBlock(this.GetType(), "", "alert('button2 is clicked');", true);
} protected void Button1_Command(object sender, CommandEventArgs e)
{
this.ClientScript.RegisterClientScriptBlock(this.GetType(), "", "alert('Command event is fired by "+e.CommandArgument+"');", true);
}
}
}

查看页面源:

<!DOCTYPE html>

<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="Content-Type" content="text/html; charset=utf-8" /><title> </title></head>
<body>
<form method="post" action="WebForm4.aspx" id="form1">
<div class="aspNetHidden">
<input type="hidden" name="__EVENTTARGET" id="__EVENTTARGET" value="" />
<input type="hidden" name="__EVENTARGUMENT" id="__EVENTARGUMENT" value="" />
<input type="hidden" name="__LASTFOCUS" id="__LASTFOCUS" value="" />
<input type="hidden" name="__VIEWSTATE" id="__VIEWSTATE" value="Vqv+KjPUckg+144xpf/QLmbVZMyUllu8bC/2XIXx6m9nl9zU1fvBY2vEvG3+yItJZ0KxnR2bBZArLGD6aZmvDpyNsXkmR0lOhuBb9IhlRm8VeVo1Sf3K8ZE7bCTXrM8C" />
</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 class="aspNetHidden"> <input type="hidden" name="__VIEWSTATEGENERATOR" id="__VIEWSTATEGENERATOR" value="46C3663D" />
<input type="hidden" name="__EVENTVALIDATION" id="__EVENTVALIDATION" value="sIYZq5CKr84HI9Xl83lk+dbfP8dmxk8DsHHFopi45JLSqIGDkhpRjkagLQ64HpyIxKgJvaWNcKeczV3RwU7GSqQ4YCljmXzlle4LuISbIketSy8wozEbj27ERYlEe2aOmcZMsY59JL2OmfM9UyJ2MvLDJZTXP9nZZn1c/iL+tnMYR3PA9U0aGwXUUIS3vfcsDPXcyr2qvn9ncjj2wIyV3GkytI9DqsErncURMoKdVKs=" />
</div>
<span id="Label1">Label</span>
<input name="TextBox1" type="text" id="TextBox1" />
<select name="DropDownList1" onchange="javascript:setTimeout('__doPostBack(\'DropDownList1\',\'\')', 0)" id="DropDownList1">
<option selected="selected" value="1">郑州</option>
<option value="2">洛阳</option> </select>
<input type="submit" name="Button1" value="Button1" id="Button1" />
<input type="button" name="Button2" value="Button2" onclick="javascript:__doPostBack('Button2','')" id="Button2" />
</form>
</body>
</html>

会发现生成部分有这样几种比较特别的东西:

1.Hidden Input

__EVENTTARGET:触发Event的Control的Unique name;

__EVENTARGUMENT:Event Handler定义的参数;

__LASTFOCUS:这个一般是Changed事件定义;

__VIEWSTATE:ViewState;

2.Script

定义了一个__doPostBack function来提交表单,以eventTarget和eventArgument为参数。

3.Control

Button默认被Render成Submit Button,当UseSubmitBehavior设为false时,是通过Script来提交的,内容是一致的。 看了页面源,大概也能明白Postback是如何工作的:在Client端通过提交一些参数__EVENTTARGET、__EVENTARGUMENT等,不管是直接提交还是通过脚本,在Server端通过提交的__EVENTTARGET值反射出该Control,然后判断该Control是否实现了IPostBackEventHandler接口,如果实现了该接口,当前Page就会调用RaisePostBackEvent方法。

[EditorBrowsable(EditorBrowsableState.Advanced)] 
protected virtual void RaisePostBackEvent(IPostBackEventHandler sourceControl, string eventArgument) { sourceControl.RaisePostBackEvent(eventArgument); }  

第一个参数就是Postback的Source control,第二个参数其实就是__EVENTARGUMENT值。 我们这里具体指的是Button,先来看下Button定义:

[DefaultEvent("Click"), DefaultProperty("Text"), Designer("System.Web.UI.Design.WebControls.ButtonDesigner, System.Design, Version=4.0.0.0, Culture=neutral, 
PublicKeyToken=b03f5f7f11d50a3a"), DataBindingHandler("System.Web.UI.Design.TextDataBindingHandler, System.Design, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"),
SupportsEventValidation, ToolboxData("<{0}:Button runat=\"server\" Text=\"Button\">")]
public class Button : WebControl, IButtonControl, IPostBackEventHandler{}

IPostBackEventHandler接口定义如下:

public interface IPostBackEventHandler { void RaisePostBackEvent(string eventArgument); } 

RaisePostBackEvent方法在Button的实现如下:

protected virtual void RaisePostBackEvent(string eventArgument) 
{
  base.ValidateEvent(this.UniqueID, eventArgument);
  if (this.CausesValidation)
  {
    this.Page.Validate(this.ValidationGroup);
  }
  this.OnClick(EventArgs.Empty);
  this.OnCommand(new CommandEventArgs(this.CommandName, this.CommandArgument));
}

这样调用页面的RaisePostBackEvent方法其实还是调用了Button的RaisePostBackEvent方法,在Button的RaisePostBackEvent方法具体实现中,先进行验证,然后触发Click,接着触发Command,执行相应的事件处理,然后Render Html,工作过程大致这样。另外,需要注意的是:当将Label和TextBox的EnableViewState设为false(默认为true)后,依次点击button1、button2,发现Label值最终变为初始值,而TextBox值不变,原因是在提交表单时,不管是否启用ViewState,TextBox都会提交,而Label不会;DropDownList的AutoPostBack属性默认为false,此时SelectedItem改变时不会触发Changed事件,而设为true后,SelectedItem改变会回发,最终触发Changed事件,原因是DropDownList实现了IPostBackDataHandler接口。

3.为什么使用Callback

在Asp.net中客户端与服务端的交互默认是整页面提交(包括自动生成的Hidden Input),这无疑加重了数据传输负担,加大的服务端的工作压力,而且用户还需要等待最终处理结果。在开发过程中,一个很常见的功能是:在用户注册时,当用户输完用户名,文本框失去焦点就应该提示用户名是否可用。该功能的实现目前主要是通过两种手段,一是纯javascript,二是通过.net类库。在.net类库中常用的有微软的Asp.net Ajax技术以及第三方的AjaxPro类库。然而,在这些.net类库没有出现之前,使用的是什么方法呢?就是我们所要说的Callback,它减轻了数据传输负担,缓解了服务端的工作压力,并且具有异步性。

4.Callback工作过程

客户端回调本质上就是指通过前端的客户端脚本向服务器端传递相应的数据参数,服务器端再以接受到的参数进行查询和处理,最后将结果回传到客户端进行显示。 asp.net 2.0提供了实现无刷新回调的接口ICallbackEventHandler.为了实现客户端回调,你必须实现一个 ICallbackEventHandler接口,该接口定义了两个方法法RaiseCallbackEvent和GetCallbackResult. RaiseCallbackEvent()从浏览器接受一个字符串作为事件参数,即该方法接受客户端JavaScript传递的参数,注意它是首先触发 的。接下来触发的就是GetCallbackResult()方法,它将所得到的结果传回给客户端的JavaScript,JavaScript再将结果 更新到页面。我们来使用Callback实现上面提到的用户注册失去焦点判断用户是否已存在。

Aspx代码:

<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="WebForm1.aspx.cs" Inherits="_3Callback.WebForm1" %>

<!DOCTYPE html>

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<title></title>
<script type="text/javascript">
function Success(args, context){
spanUsername.innerText = args;
}
function Error(args, context) {
spanUsername.innerText = "发生异常";
}
</script>
</head>
<body>
<form id="form1" runat="server">
<div>
<table>
<tr>
<td>用户名:</td>
<td>
<input type="text" id="tbUsername" onblur="CallServerMethod(tbUsername.value,null);"/>
</td>
<td>
<span style="color:red;">*</span>
<span id="spanUsername"></span>
</td>
</tr>
<tr>
<td>密码:</td>
<td>
<input type="text" id="tbPassword" />
</td>
<td>
<span style="color:red;">*</span>
<span id="spanPassword"></span>
</td>
</tr>
</table>
</div>
</form>
</body>
</html>

Code Behind代码:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls; namespace _3Callback
{
public partial class WebForm1 : System.Web.UI.Page,ICallbackEventHandler
{
private ClientScriptManager csm;
private string result;
protected void Page_Load(object sender, EventArgs e)
{
csm = this.Page.ClientScript;//获取当前页的ClientScriptManager
//获取回调引用。会在客户端生成DoCallback脚本方法,调用它来实现异步调用
//
string reference = csm.GetCallbackEventReference(this, "args", "Success", "", "Error", false);
string callbackScript = "function CallServerMethod(args,context){\n" + reference + ";\n}";
csm.RegisterClientScriptBlock(this.GetType(), "CallServerMethod", callbackScript, true);
} public string GetCallbackResult()
{
return result;
} public void RaiseCallbackEvent(string eventArgument)
{
if (eventArgument == "jello")
result = eventArgument + "已存在";
else
result = eventArgument + "可用";
}
}
}

这里让当前Page实现了ICallbackEventHandler接口,由它来处理客户端回调。

工作流程大致如下:在页面Load的时候,获取回调引用,会在客户端生成DoCallback脚本方法,调用它来实现异步调用,然后注册需要在客户端直接调用的脚本并在客户端调用,在页面加载完后,首先会调用WebForm_InitCallback()对页面一些标签做不同处理,当操作导致客户端事件触发时将调用WebForm_DoCallback脚本方法,这俩个方法是在生成的axd文件中,查看该文件发现,其实WebForm_DoCallback方法也是通过javascript ajax处理的,当回调成功时,将GetCallbackResult()返回值作为第一个参数,将context作为第二个参数并调用该成功回调方法。

5.Postback与Callback的区别

1.Postback本质是一次Submit Form的过程,而Callback本质是一次javascript ajax的过程

2.Postback通过ClientScriptManager.GetPostBackEventReference(Control control, string argument)获取引用从而生成__doPostback客户端方法,而Callback通过ClientScriptManager.GetCallbackEventReference(Control control, string argument, string clientCallback, string context, bool useAsync)获取引用从而生成Webform_DoCallback客户端方法

3.其它待总结

6.参考资料

1.TRULY Understanding ViewState

2.asp.net viewstate详解

3.asp.net 中AJAX回调模式(ICallbackEventHandler)

Asp.net中Postback及Callback的更多相关文章

  1. (转)客户端触发Asp.net中服务端控件事件

    第一章. Asp.net中服务端控件事件是如何触发的 Asp.net 中在客户端触发服务端事件分为两种情况: 一. WebControls中的Button 和HtmlControls中的Type为su ...

  2. asp.net中如何防止用户重复点击提交按钮

    asp.net中如何防止用户重复点击提交按钮   asp.net 中防止因为网速慢等影响交互的问题导致用户可能点击多次提交按钮,从而导致数据库中出现多条重复的记录,经过亲自验证在网上找的方法,找到两个 ...

  3. asp.net中的窗口弹出实现,包括分支窗口 . ASP.NET返回上一页面实现方法总结 .

    返回上一页的这个东东在我们做项目的时候一般是用于填写完表单后确认的时候,有对原来输入的数据进行修改或者更新时用的,或者是因为网站为了方便浏览者而有心添加的一个东东,一般这种功能的实现在ASP.NET中 ...

  4. ASP.NET中实现页面间的参数传递

    ASP.NET中实现页面间的参数传递   编写人:CC阿爸 2013-10-27 l  近来在做泛微OA与公司自行开发的系统集成登录的问题.在研究泛微页面间传递参为参数,综合得了解了一下现行页面间传参 ...

  5. ASP.NET 中的返回按钮的实现【转】

      返回上一页的这个东东在我们做项目的时候一般是用于填写完表单后确认的时候,有对原来输入的数据进行修改时用的,或者是因为网站为了方便浏览者而有心添加 的一个东东,一般这种功能的实现在ASP.net中都 ...

  6. jqueryUI中datepicker的使用,解决与asp.net中的UpdatePanel联合使用时的失效问题

    1.jqueryUI的datepicker的使用 -->首先在jqueryUI官网上根据你的需要下载适合你系统主题的样式,jqueryUI主题下载地址: -->下载后的文件 jquery- ...

  7. 转:asp.net 中的viewstate

    概述 ViewState是一个被误解很深的动物了.我希望通过此文章来澄清人们对ViewState的一些错误认识.为了达到这个目的,我决定从头到尾详细的描述一下整个ViewState的工作机制,其中我会 ...

  8. 浅谈ASP.NET的Postback

    说道ASP.NET的Postback,就得说Web Page的生命周期,但是Web Page的生命周期却不是三言两语就能够说得清楚的,所以在这里单纯站的编程的角度,撇开Web Page 的生命周期浅谈 ...

  9. ASP.NET 中 POST 数据并跳转页面(译自 Redirect and POST in ASP.NET)

    本文翻译自 Samer Abu Rabie 的 <Redirect and POST in ASP.NET> 简介        在实际项目中,我们会遇到这样一种应用场景:我们需要与第三方 ...

随机推荐

  1. JAVA insert() 插入字符串 reverse() 颠倒 delete()和deleteCharAt() 删除字符 replace() 替换 substring() 截取子串

    insert() 插入字符串 StringBuffer insert(int index,String str) StringBuffer insert(int index,char ch) Stri ...

  2. 【前端攻略】:玩转图片Base64编码(转)

    引言 图片处理在前端工作中可谓占据了很重要的一壁江山.而图片的Base64编码可能相对一些人而言比较陌生,本文不是从纯技术的角度去讨论图片的base64编码.标题略大,不过只是希望通过一些浅显的论述, ...

  3. Android在Context详细解释 ---- 你不知道Context

                                                                                                         ...

  4. html网页特殊符号代码

    HTML特殊字符编码大全:往网页中输入特殊字符,需在html代码中加入以&开头的字母组合或以&#开头的数字.下面就是以字母或数字表示的特殊符号大全.                   ...

  5. Linux命令之文本处理(二)

    cut命令 cut命令用来操作文件的列,能够视为列编辑器:与之相应是大多数的行"编辑器".如sed.grep.sort等,它们操作文本时,以行为单位. cut的主要功能就是输出文本 ...

  6. 2-07. 素因子分解(20) (ZJUPAT 数学)

    题目链接:http://pat.zju.edu.cn/contests/ds/2-07 给定某个正整数N,求其素因子分解结果,即给出其因式分解表达式 N = p1^k1 * p2^k2 *-*pm ^ ...

  7. 点集配对问题(状态dp)

    给定n个点(n是偶数)使得两个点两两配对,最后总的距离和最小. 用是表示集合,那么dp[s]表示集合s配对后的最小距离和  , 状态转换方程为  表示集合中任意拿两个元素配对,然后转移为更小的两个集合 ...

  8. HDU 3036 Escape 网格图多人逃生 网络流||二分匹配 建图技巧

    题意: 每一个' . '有一个姑娘, E是出口,'.'是空地 , 'X' 是墙. 每秒钟每一个姑娘能够走一步(上下左右) 每秒钟每一个出口仅仅能出去一个人 给定n*m的地图, 时限T 问全部姑娘是否能 ...

  9. dedecms 织梦显示时间格式

    field:pubdate function=GetDateMK(@me)/] 2009-11-10 [field:pubdate function=GetDateTimeMK(@me)/] 2009 ...

  10. c++程序代写(qq:928900200)

     1. Both main memory and secondary storage are types of memory. Describe the difference between the  ...