我们知道,在默认的情况下,当我们点击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. Android Fragment使用

                     通常地 fragment做为宿主activity UI的一部分, 被作为activity整个view hierarchy的一部分被嵌入. 有2种方法你能够加入一个fr ...

  2. android学习---SeekBar和RatingBar

    SeekBar 拖动条:拖动条和滚动栏类似,当是拖动条能够拖动滑块改变进度 RatingBar 星级评分条:星级评分条与拖动条相似 SeekBar特有的xml属性 android:thumb    指 ...

  3. ubuntu下ssh使用 与 SCP 使用

    1 ssh远程登录服务器 ssh username@remote_ip #将username换成自己的用户名,将remote_ip换成远程服务器的ip地址 2 将文件/文件夹从远程服务器拷至本地(sc ...

  4. Linux php/php-fpm 安装,配置

    1> 下载php源代码   #wget  http://cn2.php.net/get/php-5.4.30.tar.gz/from/this/mirror   官网5.2的版本号貌似没提供   ...

  5. ecshop加广告出现广告位的宽度值必须在1到1024之间的解决方法

    ecshop加广告出现广告位的宽度值必须在1到1024之间,这点是非常郁闷的,因为现在宽屏网站逐渐成为主流,越来越多的宽屏网站进入了我们的视线,比如京东啊,一号店啊. 但是ecshop的广告位却不能超 ...

  6. HOJ2275 Number sequence

    Number sequence My Tags tag=&type=or" style="margin:0px; padding:0px; color:rgb(27,87, ...

  7. 我的学习笔记_Windows_HOOK计划 2009-12-03 11:19

    一.什么是HOOK? "hook"这个单词的意思是"钩子","Windows Hook"是Windows消息处理机制的一个重要扩展,程序猿能 ...

  8. POJ 3450 Corporate Identity KMP解决问题的方法

    这个问题,需要一组字符串求最长公共子,其实灵活运用KMP高速寻求最长前缀. 请注意,意大利愿父亲:按照输出词典的顺序的规定. 另外要提醒的是:它也被用来KMP为了解决这个问题,但是很多人认为KMP使用 ...

  9. [Windows Phone] 实作不同的地图显示模式

    原文:[Windows Phone] 实作不同的地图显示模式 前言 本文章主要示范如何让地图有不同的模式产生,例如平面图.地形图.鸟瞰图.鸟瞰图含街道等. 这部分主要是调整 Map.Cartograp ...

  10. 【牛刀小试2】password保

    ]password保 主要知识: 1.        while循环 2.        do-while循环 3.        if-else 4.        strcmp()函数 [充电一下 ...