声明:FineUIMvc(基础版)是免费软件,本系列文章适用于基础版。

用户反馈

有网友在官方论坛抛出了这么一个问题,似乎对 FineUIMvc 中的浏览器端与服务器端的交互方式很有异议。

这里面的关键词就是:回发!

似乎一提到回发(__doPostBack),就让人联想到 WebForms 中的 ViewState 和单表单提交,因为回发时会把页面上所有控件的 ViewState 一股脑的提交到后台,无疑加重了网络的上行数据量。从此 回发 这一名词给人的印象就很晦涩了。

真的是这样吗?我们分别来比较 WebForms、ASP.NET MVC、以及FineUIMvc中的回发,来探索其中的联系和差异。

WebForms中的回发(__doPostBack)

每位经历过 ASP.NET WebForms 的开发人员都不会忘记这个字符串:__doPostBack,因为它出现在你写的每一个 .aspx 页面的浏览器源代码中:

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

在 WebForms 中,整个页面就是一个表单,所以早期的微软工程师大摇大摆的定义了一个全局变量:

var theForm = document.forms['form1'];

__doPostBack 函数则是对页面上这个唯一的表单提交( theForm.submit),传入的 eventTarget 和 eventArgument 分别用来标识本次回发的触发控件以及回发参数。

这些都没啥,关键是页面上永远都有一个 ViewState 隐藏字段:

<input type="hidden" name="__VIEWSTATE" id="__VIEWSTATE" value="/wEPDwUKLTQyNjcyNDU5MWRkpK.....aycxe0NfpWe+PGI0=" />

这里面存放了页面上所有控件的状态信息,比如下拉列表的数据,表格的数据,输入框的数据等等,所有这个字段一般会比较大,导致上传的数据量动辄就有20K~1000K。在网络有限的情况下会非常影响性能,从而给人了臃肿的印象。

比如在 FineUI(开源版)中一个包含表格的页面:

http://fineui.com/demo/iframe/grid_iframe.aspx

页面回发时,请求的数据量就达到 19802 bytes = 19K

ASP.NET MVC中的回发(BegionForm)

在 ASP.NET MVC 中,我们可以定义多个表单,从而自行控制需要提交的表单,以及表单中字段。也就是只提交我们需要的数据,这样不仅灵活而且上传数据量不会很大。

在 MVC 的其他文档中,你可能很少会看到 回发 这个字眼,很多是这样描述的:提交某个表单到控制器的某个操作方法,或者说发起一个 HTTP POST 请求。其实这些都对应于 WebForms 中的回发字眼,只不过操作的表单和表单字段不同而已。本质上还是一样的。

在我之前写MVC系列教程中有一个典型的回发过程:【第四篇】ASP.NET MVC快速入门之完整示例(MVC5+EF6)

@using (Html.BeginForm())
{
@Html.AntiForgeryToken()
<p>
所学专业: @Html.DropDownList("Major", ViewBag.MajorList as IEnumerable<SelectListItem>, "全部")
姓名: @Html.TextBox("Name")
<input type="submit" value="检索" />
</p>
}

通过 Html.BeginForm 辅助方法来生成一个表单,这个表单会提交到当前页面对应的控制器方法,默认使用 POST 请求,生成到页面的HTML结构类似:

<form action="/Students/Create" method="post">

</form>

表格里面,明确定义了两个表单字段,分别是 Major 和 Name,以及一个提交按钮(type=submit)。

对应的后台控制器方法类似:

[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Index(string Major, string Name)
{
// ...
return View(students.ToList());
}

在这个过程中,虽然我们可以控制要提交的表单,以及提交哪些参数,但这个过程还是整个页面提交。

而 FineUIMvc 中,我们不仅不需要定义表单(只需要告诉FineUIMvc需要提交哪些参数即可),而且所有的提交都是AJAX过程。

FineUIMvc中的回发(OnClick、OnPageIndexChanged)

FineUIMvc中将对控制器方法的调用放到每个具体的控件中, 对应于 FineUI(开源版)中控件的事件。

无参数回发

按钮的点击事件:

@(F.Button()
.OnClick(Url.Action("btnHello_Click"))
.ID("btnHello")
.Text("点击弹出对话框")
)

这样就将按钮的客户端点击事件(click)和服务器端控制器的方法(btnHello_Click)关联起来,而且命名也和WebForms中的一模一样,是不是倍感亲切。

仔细观察下这个 HTTP 请求,我们就能知道这个客户端点击事件将去向何方:

从这张图上,我们有如下收获:

  1. Basic是区域名称(Area),Hello是当前控制器名称
  2. btnHello_Click是点击按钮时对应的控制器方法
  3. 请求方法是 POST
  4. X-Requested-Width: XMLHttpRequest,表明当前请求是AJAX

再来看下HTTP请求正文数据:

只要一个防止跨站请求伪造(CSRF)的参数_RequestVerificationToken,再无其他参数。

对应的控制器方法:

[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult btnHello_Click()
{
Alert.Show("你好 FineUIMvc!", MessageBoxIcon.Warning); return UIHelper.Result();
}

因为在这个过程中,后台无需参数,所以前台也没必要传入任何数据。这样一个AJAX回发过程就非常干净,不像之前的WebForms一样,需要传递一堆参数了。

带参数回发

来看下表格的数据库分页事件,在数据库分页时后台C#代码需要知道两个参数:

1. 当前的页码

2. 表格中用到了哪些数据库字段,即使熟练的WebForms开发人员可能也不会意识到这一点,因为在WebForms中后台能够知道控件的所有参数,而MVC中回发时,你对表格的任何参数一无所知,所有你需要的参数都需要通过前台传入

FineUIMvc对于带参数的回发回发进行了深度优化,你根本无需自己通过JavaScript来获取这些参数(当然你也可以这么做,只要你愿意),而是指定表格的ID即可:

@(F.Grid()
.EnableCheckBoxSelect(true)
.Width()
.ShowHeader(true)
.ShowBorder(true)
.EnableCollapse(true)
.Title("表格")
.ID("Grid1")
.DataIDField("Id")
.DataTextField("Name")
.AllowPaging(true)
.PageSize()
.IsDatabasePaging(true)
.OnPageIndexChanged(Url.Action("Grid1_PageIndexChanged"), "Grid1")
.Columns(
F.RowNumberField(),
F.RenderField()
.HeaderText("姓名")
.DataField("Name")
.Width(),
....
)
.RecordCount(ViewBag.Grid1RecordCount)
.DataSource(ViewBag.Grid1DataSource)
)

注意 OnPageIndexChanged 的第二个参数,这样在发起对控制器方法(Grid1_PageIndexChanged)的POST请求时,会自动附加所需的参数:

对应的控制器方法:

[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Grid1_PageIndexChanged(JArray Grid1_fields, int Grid1_pageIndex)
{
var grid1 = UIHelper.Grid("Grid1"); var recordCount = DataSourceUtil.GetTotalCount(); // 1.设置总项数(数据库分页回发时,如果总记录数不变,可以不设置RecordCount)
grid1.RecordCount(recordCount); // 2.获取当前分页数据
var dataSource = DataSourceUtil.GetPagedDataTable(pageIndex: Grid1_pageIndex, pageSize: , recordCount: recordCount);
grid1.DataSource(dataSource, Grid1_fields); return UIHelper.Result();
}

小结

WebForms中的回发由于需要附加上ViewState而略显臃肿;

ASP.NET MVC原生的回发需要借助Html.BeginForm辅助方法来生成单独的表单,并把需要提交的参数放置到表单中,回发过程是整个页面提交;

FineUIMvc对回发过程进行深度优化,无需创建表单,只需要提供需要回发的参数,而且回发过程是AJAX的。对于部分控件比如表单和表格,甚至不需要指定回发参数,只需要设置控件ID即可,非常方便。

如果你还对WebForms中的回发念念不忘,那就无需忘却。

FineUIMvc随笔(3)不能忘却的回发(__doPostBack)的更多相关文章

  1. FineUIMvc随笔(4)自定义回发参数与自定义回发

    声明:FineUIMvc(基础版)是免费软件,本系列文章适用于基础版. 不能忘却的回发 在上一篇文章中,我们对FineUIMvc中的回发进行了详细描述,目的是为了告诉大家: 1. FineUIMvc中 ...

  2. FineUIMvc随笔 - 不能忘却的回发(__doPostBack)

    声明:FineUIMvc(基础版)是免费软件,本系列文章适用于基础版. 用户反馈 有网友在官方论坛抛出了这么一个问题,似乎对 FineUIMvc 中的浏览器端与服务器端的交互方式很有异议. 这里面的关 ...

  3. FineUIMvc随笔 - 动态创建表格列

    声明:FineUIMvc(基础版)是免费软件,本系列文章适用于基础版. 用户需求 用户希望实现动态创建表格列,在 WebForms 中,我们通过在 Page_Init 中创建列来实现: 但是在 MVC ...

  4. FineUIMvc随笔(1)动态创建表格列

    声明:FineUIMvc(基础版)是免费软件,本系列文章适用于基础版. <FineUIMvc随笔>目录 FineUIMvc随笔(1)动态创建表格列 FineUIMvc随笔(2)怎样在控件中 ...

  5. FineUIMvc随笔(5)UIHelper是个什么梗?

    声明:FineUIMvc(基础版)是免费软件,本系列文章适用于基础版. UIHelper.Result 在 FineUIMvc 的每一个 HttpPost 的控制器方法里面,你都会看到 UIHelpe ...

  6. FineUIMvc随笔(6)对比WebForms和MVC中表格的数据库分页

    声明:FineUIMvc(基础版)是免费软件,本系列文章适用于基础版. 通过对比WebForms和MVC中表格数据库分页代码的不同,可以对 MVC 中的数据流转有更加深入的了解. WebForms 中 ...

  7. 回发或回调参数无效。在配置中使用 pages enableEventValidation=true 或在页面中使用 %@ Page EnableEventValidation=true % 启用了事件验证

    WebForm中回发或回调参数无效问题的解决 解决 .NET中回发或回调参数无效问题的解 该错误的详细提示信息为: 回发或回调参数无效.在配置中使用 <pages enableEventVali ...

  8. FineUI小技巧(6)自定义页面回发

    前言 FineUI中的绝大部分回发事件都是由控件触发了,比如按钮的点击事件,下拉列表的改变事件,表格的排序分页事件.但有时我们可能会要自己触发页面回发,这时就要知道怎么使用 JavaScript 来做 ...

  9. asp.net 解决 "回发或回调参数无效" 一些常见解决方案

    一.回发或回调参数无效,出现下图错误, 常见解决方案: 1.在页面的<%@ Page Language="C#"  AutoEventWireup="true&qu ...

随机推荐

  1. Android-TextView 控件常用属性以及基本用法

    github地址:https://github.com/1165863642/TextViewDemo 前言 这是我第一次写博客,第一次的笔记,不足之处多谅解.开门见山,这一篇博客主要讲一下在Andr ...

  2. 章节七、1-ArrayList

    一.集合是一个容器,前面讲的数值也是一个容器, 它们的区别是: 1.数组既可以存储基本数据类型,又可以存储引用数据类型,而集合只能存储引用数据类型,也就是对象. 2.基本数据类型存储的是值,引用数据类 ...

  3. ChakraCore/JSRT使用问题汇总

    QQ交流群:523723780(ChakraCore) ChakraCore是什么? 一个微软开源的,用于Windows IE/Edge内核的高效JS脚本引擎. 前不久微软开源了ChakraCore, ...

  4. Cas 服务器 下载、编译及部署

    一直想把公司运营的项目的各个子项的认证及授权统一到Cas上,从有想法到现在快一年的时间了.现在才正式着手,有兴趣的朋友一起交流学习一下.具体项目的细节不便透露,整合的大体思路为:1.开发部署Cas服务 ...

  5. 自动化测试基础篇--Selenium简单的163邮箱登录实例

    摘自https://www.cnblogs.com/sanzangTst/p/7472556.html 前面几篇内容一直讲解Selenium Python的基本使用方法.学习了什么是selenium: ...

  6. SQL Server 执行计划解析

    前置说明: 本文旨在通过一个简单的执行计划来引申并总结一些SQL Server数据库中的SQL优化的关键点,日常总结,其中的概念介绍中有不足之处有待补充修改,希望大神勘误. SQL语句如下: SELE ...

  7. 简单易懂的程序语言入门小册子(4):基于文本替换的解释器,递归,如何构造递归函数,Y组合子

    递归.哦,递归. 递归在计算机科学中的重要性不言而喻. 递归就像女人,即令人烦恼,又无法抛弃. 先上个例子,这个例子里的函数double输入一个非负整数$n$,输出$2n$. \[ {double} ...

  8. Windows Server 2016-Active Directory域服务端口汇总

    本章为大家简单整理一下有关Windows server Active Directory和Active Directory域服务(AD DS)组件的端口要求.生产环境中我们在做网络调整.防火墙或者开关 ...

  9. shell 函数用法

    近期在学习shell编程方面的知识,写的不怎么好,请大家多多指点,下面给大家分享一下shell函数的用法. 我们为什么要用shell函数? 简单的说,函数的作用就是把程序多次调用相同的代码部分定义成一 ...

  10. 18年10月份最新免费申请微软OneDrive5TB云盘超详细教程!(已亲测!)

    本人已于今天10月23日亲测,成功获取微软OneDrive5T云盘! 第一步:.打开申请链接学生版:https://signup.microsoft.com/signup?sku=student教师版 ...