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

View Code

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 = "111";this.TextBox1.Text = "222";}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);}}
}

View Code

查看页面源:

<!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>

View Code

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

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>

View Code

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 + "已存在";elseresult = eventArgument + "可用";}}
}

View Code

这里让当前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)

转载于:https://www.cnblogs.com/jellochen/p/3816184.html

Asp.net中Postback及Callback相关推荐

  1. ASP.NET中PostBack和ViewState

    ASP.NET中PostBack和ViewState 关于PostBack,我曾经也写过一篇博客<深入理解doPostBack>.在这篇文章里有对PostBack进行了一些研究,现在看来研 ...

  2. ASP.NET中的回调技术(CallBack)

    在asp.net中客户端与服务器端的交互默认都是整页面提交,此时客户端将当前页面表单中的数据(包括一些自动生成的隐藏域)都提交到服务器端,服务器重新实例化一个当前页面类的实例响应这个请求,然后将整个页 ...

  3. 【转】ASP.NET中页面传值

    http://www.cnblogs.com/wenly/archive/2008/06/10/1216678.html 一.目前在ASP.NET中页面传值共有这么几种方式: 1.表单提交,    & ...

  4. 技巧/诀窍:在ASP.NET中重写URL(转)

    [原文地址]Tip/Trick: Url Rewriting with ASP.NET [原文发表日期] Monday, February 26, 2007 9:27 PM 经常有人请我指导应该如何动 ...

  5. AjaxPro2在Asp.net中的基本用法

    AjaxPro2在Asp.net中的基本用法 1.      引用ajaxPro2.dll到你的工程中. 2.      在Web.config中添加配置 <httpHandlers>   ...

  6. 浅谈ASP.NET的Postback

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

  7. 技巧/诀窍:在ASP.NET中重写URL

    [原文地址]Tip/Trick: Url Rewriting with ASP.NET [原文发表日期] Monday, February 26, 2007 9:27 PM 经常有人请我指导应该如何动 ...

  8. ASP.NET中实现页面间的参数传递 QueryString\Application\Session\Cookie

    一.使用QueryString 使用QueryString在页面间传递值是一种非常常见的方法,我们在ASP中就常常用到. (1)优点和缺点     优点:     1.使用简单,对于安全性要求不高时传 ...

  9. Asp.net中服务端控件事件是如何触发的(笔记)

    Asp.Net 中在客 户端触发服务器端事件分为两种情况: 一.   WebControls中的Button 和HtmlControls中的Type为submit的HtmlInputButton 这两 ...

最新文章

  1. Java RTTI运行时类型识别
  2. 每日一皮:不允许穿格子衫之后...
  3. NSPredicate 谓词
  4. OpenCV学习:仿射变换+投射变换+单应性矩阵
  5. 2016级算法期末上机-H.难题·AlvinZH's Fight with DDLs III
  6. C程序范例(3)——结构体
  7. C语言中写一个函数返回参数二进制中 1 的个数
  8. 版本控制工具比较-CVS,SVN,GIT
  9. 万字干货:阿里巴巴是怎么做大数据算法应用测试的? | 凌云时刻
  10. Echarts教程_1-2 简介
  11. 【1】国产USB转接芯片CH347-初体验
  12. RK339中安卓系统7和9升级最新webView内核步骤
  13. stm32cube 和 RTX v5一起用的方法
  14. 为了革命 保护眼睛 !—— 眼科专家配置的色调
  15. 是时候让AI辅助你追剧了,以《猎场》为例
  16. 新一年级家长快查收,小学入学必备物品超强清单!
  17. linux+synaptics+驱动程序,Linux下Synaptics笔记本触摸板的配置
  18. greedy策略求解活动选择问题 ActivitySelectProblem
  19. 如何看linux系统中有没有安装cuda,Linux系统CUDA10.2+CUDNN安装教程
  20. 上海滩上,共创行业新价值的大时代要来了

热门文章

  1. ) php中_如何在webmin中配置多个PHP版本
  2. java 对象的属性_java-更新对象属性
  3. matlab imcrop 对应python函数_MATLAB车牌识别之7个字符切割浅谈【抽丝剥茧】
  4. 我崩溃了!月薪30K必须掌握的开源项目Java中SPI机制
  5. 【深度学习】逆卷积(Deconvolution)概述
  6. 【Java Web前端开发】HTML表单和CSS部分
  7. python【Opencv计算机视觉库】opencv模块cv2常用函数用法(全)
  8. Python-time标准库知识小结
  9. php 数组与数组之间去重,PHP开发中一维数组与二维数组去重功能实现教程
  10. 高版本转低版本_Tekla高版本模型转低版本模型插件