zoukankan      html  css  js  c++  java
  • ASP.NET Web Form 的“连续”和“有状态”假象 (转)

    原文 http://www.cnblogs.com/sgsoft/articles/62691.html

    从根本上说,ASP.NET 并没有改变 Web 页的本质:每次请求 ASP.NET 页时,服务器就会加载一个 ASP.NET 页,并在请求完成时卸载该页。页及其包含的服务器控件负责执行请求并将 HTML 呈现给客户端。

    ASP.NET 的设计者们,从实际访问者的角度重新考虑了这一过程:访问者打开一个页面,点击一个按钮,看到新的画面……这一切似乎都是连续的。

    这种连续性假象是由 ASP.NET 页框架、页及其控件实现的。回发后,控件的行为必须看起来是从上次 Web 请求结束的地方开始的。另一方面,对于 Web Form 中的 TextBox,ASP.NET 也让它们具有了状态,可以知道上一个 loop 和这一个 loop 之间的 TextBox 值的变化;如果变化,可能会触发 TextBox 的 TextChanged 事件。这同样是 ASP.NET 特意实现的一个假象。

    ASP.NET 服务器控件的生命周期一般如下:

    1. 初始化  - Init 事件 (OnInit 方法)

    2. 加载视图状态 - LoadViewState 方法

    3. 处理回发数据 - LoadPostData 方法
        对实现 IPostBackDataHandler 接口的控件,即可以自动加载回发数据的控件,如 TextBox, DropDownList 等。

    4. 加载 - Load 事件 (OnLoad 方法)

    5. 发送回发更改通知 - RaisePostDataChangedEvent 方法
        对实现 IPostBackDataHandler 接口的控件,即可以自动加载回发数据的控件。
        在第 3 步中加载回发数据,如果回发前后数据发生更改,则在这一步触发相应的服务端事件。

    6. 处理回发事件 - RaisePostBackEvent 方法
        对实现 IPostBackEventHandler 接口的控件,即能引起回发的控件,如 Button, LinkButton, Calendar 等

    7. 预呈现 - PreRender 事件 (OnPreRender 方法)

    8. 保存视图状态 - SaveViewState 方法

    9. 呈现 - Render 方法

    10. 处置 - Dispose 方法

    11. 卸载 - UnLoad 事件 (OnUnLoad 方法)

    Web Form 的基类 System.Web.UI.Page 从 System.Web.UI.Control 继承,它也是一种特殊的 Control。

    ASP.NET 是怎样实现状态的?

    ASP.NET 使用了 ViewState 视图状态,如果你查看 Web Form 产生的 HTML 代码,可以看到一个名为 __ViewState 的隐藏字段,ASP.NET 将状态信息以 Hash 的方式存储在这里。通过它,可以在下一次回发时知道回发前各控件的状态。

    比如:一个 TextBox,回发前 Text 属性有值“hello”,访问者填写了新的值“world”,当这个页面回发到服务器端,服务端代码就可以得知 TextBox 的 Text 属性值发生了改变,TextChanged 事件就被触发了。从生命周期来看,LoadViewState 这一步加载了 TextBox 的原状态,LoadPostData 这一步从 Request.Form 集合中取得了 TextBox 的当前值,过了 Load,在 RaisePostDataChangedEvent 这一步触发 TextBox 的 TextChanged 事件,SaveViewState 将当前值存入 ViewState 作为下一次回发的原状态。

    ASP.NET 是怎样实现连续性假象的?

    对开发者而言,以往对于一个提交按钮的点击回发,或者说 HTML form 提交的处理往往是在另一个页面中处理,将 form 的 target 指向该页面。(当然在一个页面中也是可以完成的,但大部分人习惯于两个页面)

    在 ASP.NET 中,这一过程被处理成和 Windows 程序类似的过程,Button 的点击、form 被提交这个事件被 ASP.NET “包装”成一个服务器事件,也就是 Button 的 Click 事件。从生命周期来看,Button 控件被加载的流程如下:LoadPostData 这一步可以从 Request.Form 集合中找到 Button 的 name 值(只有被点击的 Button 会在 Request.Form 集合中生成一个 name-value 对);过了 Load,在 RaisePostBackEvent 这一步,将触发 Button 的 Click 事件。

    我们再分析特别的情况:Button 在 HTML 中是可以引起 form 的提交的,也就是可以引起页面回发;但其他的,如 LinkButton (对应于 HTML 的 A 元素),DropDownList (对应于 HTML 的 SELECT)等,则并不会自动引起回发。这种情况下,ASP.NET 使用了又一个技巧来保证这一假象继续成立:打开含有 LinkButton 的一个 ASP.NET 生成的 HTML 页面代码,可以找到两个隐藏字段,一个叫 __EVENTTARGET,一个叫 __EVENTARGUMENT,再往下找到一段脚本:

     function __doPostBack(eventTarget, eventArgument) {
      var theform;
      if (window.navigator.appName.toLowerCase().indexOf("netscape") > -1) {
       theform = document.forms["Form1"];
      }
      else {
       theform = document.Form1;
      }
      theform.__EVENTTARGET.value = eventTarget.split("$").join(":");
      theform.__EVENTARGUMENT.value = eventArgument;
      theform.submit();
     }
    
    

    再看看 LinkButton 生成的代码:

    <A id=LinkButton1 href="javascript:__doPostBack('LinkButton1','')">LinkButton</A>
    

    如果你做过网页中的客户端脚本的话,应该知道,当点击这个“LinkButton”时,实际上是通过客户端脚本将它的名字和若干参数(比如 Calendar 需要传递一些参数,LinkButton 没有传参数的必要)设置到两个隐藏字段中,并在脚本中提交了表单。

    继续看服务段的流程:LoadPostData 会看到这两个隐藏字段中的值,但并不马上解析;依然是过了 Load,在 RaisePostBackEvent 这一步解析这两个字段中的值,触发相应控件的事件。

    我们最后分析一下 CheckBox 或者 DropDownList 之类的 AutoPostBack 属性:如果 AutoPostBack 为 true,则在向客户端输出时,加入上面的 __doPostBack 式的回发;如为 false,则不加入这样的立即回发脚本,而是等待有其他可以引起回发的控件(比如 Button, LinkButton 等)回发后,在 RaisePostDataChanged 中触发 CheckBox 的 CheckedChanged 事件,DropDownList 的 SelectedIndexChanged 事件;在 RaisePostBackEvent 时继续分析其他引起回发的事件。

     

    微软把复杂的 Web 模型简化成一个传统 Windows 程序员易于接受的模型,大大降低了 Web 开发的门槛。但尽管如此,微软无法改变 Web 的“无状态”、“断续”的实质,所以不要将所有 Windows 程序开发的经验都一古脑运用到 Web 开发当中。了解了其内在机理,有助于 Windows 程序员避免这些“武断”的错误。

  • 相关阅读:
    跨域
    redis安装
    iframe操作
    element-ui 合并相邻的相同行 span-method
    函数实现 a?.b?.c?.d
    git 使用流程 命令
    svg用作背景图
    js中的位运算符 ,按位操作符
    二十三种设计模式[23]
    二十三种设计模式[22]
  • 原文地址:https://www.cnblogs.com/moses/p/1820792.html
Copyright © 2011-2022 走看看