一切为客户着想

一切的一切还得从和一位台湾客户的沟通说起:

客户提到将ViewState保存在服务器端以减少上行数据量,从而加快页面的回发速度。

但是在FineUI中,控件状态都保存在FState中,并且为了减少下行数据量,FState的数据不仅用来保存状态,而且用于JavaScript的数据源。

所以FState必须写入HTTP响应,才能被JavaScript使用。我在之前的一篇文章中曾详细阐述:http://www.cnblogs.com/sanshi/archive/2013/01/08/2850459.html

但这的确是个问题,FState虽然能够减少下行数据量,但是页面回发时上行数据量依然很大,特别是页面中有多个下拉列表和表格时,上行的数据量可达到500K或者更多,对网速受限的环境的确是个挑战。

FineUI(专业版)v3.5.0将提供一种简单的方法,将FState保存在服务器端,从而大幅减少页面回发时的上行数据量。

注:FState仍然需要返回到页面上(以便JavaScript使用,比如作为表格和下拉列表的数据源),只不过不需要回发到服务器而已。

减少 90% 的上行数据

作为对比,我们以下面的表格页面为例:http://fineui.com/demo_pro/iframe/grid_iframe.aspx

首先选中一项,然后点击工具栏上的[删除选中行]按钮,此时会触发按钮点击事件,我们分别看下v3.3.0和v3.5.0中上传数据量。

FineUI(专业版)v3.3.0:

FineUI(专业版)v3.5.0:

FineUI(专业版)v3.3.0上行数据量:32616bytes =  31.9K

FineUI(专业版)v3.5.0上行数据量:2137bytes =  2.1K

从上面数据来看,FineUI(专业版)v3.5.0上行数据量减少了 90% 左右。在一个包含多个表格和下拉列表的页面,这个效果会更加明显。

自定义编码实现

虽然FineUI(专业版)v3.5.0提供了将FState保存到服务器端的方法,但不是默认就支持的,需要自己写点代码。因为保存到服务器有多种方法,可以保存到服务器文件中,HttpRuntime.Cache,SqlServer或者NoSQL数据库(比如Memcached,Redis)。

官网示例的PageBase.cs中提供了两种保存方式:文件、HttpRuntime.Cache,你可以直接拷贝代码到自己的项目中去。

现在来看下保存到服务器缓存中(HttpRuntime.Cache)的方法:

1. 启用PageManager的EnableFStatePersistence,并定义代理函数LoadFStateFromPersistenceMedium和SaveFStateToPersistenceMedium。

protected override void OnInit(EventArgs e)
{
var pm = PageManager.Instance;
if (pm != null)
{
// FState保存到服务器缓存
pm.EnableFStatePersistence = true;
pm.LoadFStateFromPersistenceMedium = LoadFStateFromPersistenceMedium_Cache;
pm.SaveFStateToPersistenceMedium = SaveFStateToPersistenceMedium_Cache; }
}

页面级别的支持,方便我们控制哪些页面启用,哪些页面可以不启用。

2. 获取和保存FState的代理函数

private static readonly string FSTATE_CACHE_KEY = "__FSTATE_KEY";

private JObject LoadFStateFromPersistenceMedium_Cache()
{
string cacheKey = Page.Request.Form[FSTATE_CACHE_KEY]; var fstate = HttpRuntime.Cache[cacheKey] as JObject; if (fstate != null)
{
// 缓存使用过一次后,5s后过期(用不到了)
HttpRuntime.Cache.Insert(cacheKey, fstate, null,
DateTime.Now.AddSeconds(),
System.Web.Caching.Cache.NoSlidingExpiration,
System.Web.Caching.CacheItemPriority.Default, null);
} return fstate;
} private void SaveFStateToPersistenceMedium_Cache(JObject fstate)
{
   // 1. 生成缓存Key = 用户会话ID+当前时间
string cacheKey = String.Format("{0}_{1}",
HttpContext.Current.Session.SessionID,
DateTime.Now.Ticks.ToString());

   // 2. 将页面的FState保存到缓存中,指定过期时间为当前用户会话过期时间(Session.Timeout)
// 指定时间后过期(Session.Timeout)
HttpRuntime.Cache.Insert(cacheKey, fstate, null,
DateTime.Now.AddMinutes(HttpContext.Current.Session.Timeout),
System.Web.Caching.Cache.NoSlidingExpiration,
System.Web.Caching.CacheItemPriority.Default, null);

// 3. 将缓存Key保存到页面的一个隐藏字段中,通过PageContext.RegisterStartupScript来注册一段脚本
PageContext.RegisterStartupScript(String.Format("F.setHidden('{0}','{1}');", FSTATE_CACHE_KEY, cacheKey));
}

这里面的实现方式和在服务器端保存ViewState的方式类似。

官网示例中也有保存到服务器端文件的实现,可以参考:

private static readonly string FSTATE_FILE_KEY = "__FSTATE_KEY";
private static readonly string FSTATE_FILE_BASE_PATH = "~/App_Data/FState/"; private JObject LoadFStateFromPersistenceMedium()
{
string filePath = GetFStateFilePath();
string fileContent;
using (StreamReader sr = new StreamReader(filePath, System.Text.Encoding.UTF8))
{
fileContent = sr.ReadToEnd();
}
return JObject.Parse(fileContent);
} private void SaveFStateToPersistenceMedium(JObject fstate)
{
string filePath = GenerateFStateFilePath();
using (StreamWriter streamW = new StreamWriter(filePath, false, System.Text.Encoding.UTF8))
{
streamW.Write(fstate.ToString(Formatting.None));
}
} private string GenerateFStateFilePath()
{
DateTime now = DateTime.Now;
string folderName = now.ToString("yyyyMMddHH");
string fileName = String.Format("{0}_{1}",
HttpContext.Current.Session.SessionID,
now.Ticks.ToString());
//Page.Request.Url.AbsolutePath.Replace(".", "_").Replace("/", "_")); string folderPath = Page.Server.MapPath(Path.Combine(FSTATE_FILE_BASE_PATH, folderName));
if (!Directory.Exists(folderPath))
{
Directory.CreateDirectory(folderPath);
} PageContext.RegisterStartupScript(String.Format("F.setHidden('{0}','{1}');", FSTATE_FILE_KEY, fileName)); return folderPath + "/" + fileName + ".config";
} private string GetFStateFilePath()
{
string fileName = Request.Form[FSTATE_FILE_KEY];
string[] fileNames = fileName.Split('_');
string folderName = new DateTime(Convert.ToInt64(fileNames[])).ToString("yyyyMMddHH"); return Page.Server.MapPath(Path.Combine(FSTATE_FILE_BASE_PATH, folderName)) + "/" + fileName + ".config";
}

当然你也可以方便的扩展到外部数据库(SqlServer,MySql)以及NoSQL数据库(Memcached,Redis)。

使用建议

虽然EnableFStatePersistence可以极大的减少上行数据量,但并不适合于所有的场合。因为每个用户访问的每个页面都可能会产生大量的FState,所以在服务端保存意味着对服务器资源的极大消耗(内存、文件或者数据库)!

有一个简单的使用原则:

仅在上行带宽有限(也即是服务器成本低于网络传输成本)时使用,否则适得其反。

在 stackoverflow 上有一个帖子,描述了将 ViewState 保存到服务器端可能存在的问题。

启用 FineUI 的 EnableFStatePersistence 适用于同样的原则(引文中的VS指的是ViewState):

  1. If the application recycles, the VS for all anyone using the application is lost.

  2. It increases the memory consumption of the application. This isn't an issue if there are only a few apps hosted on a server; but there are cases when there could be many websites hosted on one box.

  3. Scalability; the more active the application, the more VS needs to be stored. And you can't assume 1-1 (1 user - 1 VS). A user can have multiple tabs open, can go back, leave tabs inactive, etc... which leads to:

  4. How long do you store VS? Keeping the data encoded on the page ensures that it'll still be there if the user leaves the site open for a while.

  5. What happens if you're hosted on a web farm. We can't guarantee that the user will hit the same machine on each request.

官网示例:http://fineui.com/demo_pro/

FineUIPro v3.5.0发布了,减少 90% 的上行数据量,15行代码全搞定!的更多相关文章

  1. FineUIPro v3.6.0 发布了(3 年助力 200 家企业的信息化建设)!

    FineUI(专业版)自从 2014-07-30 发布第一个版本以来,3 年来已经持续更新了 25 个版本,我们的坚持有目共睹,同时也受到了 200 家企业的青睐和信任,感谢一路有你. FineUI( ...

  2. FineUIPro v5.1.0 发布了!

    FineUIPro v5.1.0 已发布,这已经是自 2014 年以来的第 31 个版本,4 年来精雕细琢,只为你来! 上个大版本新增了响应式布局,而这个版本主要是BUG修正,此外还增加了树控件的级联 ...

  3. FineUI(专业版)v3.2.0 发布(ASP.NET UI控件库)!

    +2016-08-20 v3.2.0 +表格增强. +表格列RenderField增加属性ClientHtmlEncode,用于在客户端进行HTML编码. -增加示例:单元格编辑->杂项-> ...

  4. AEAI DP V3.7.0 发布,开源综合应用开发平台

    1  升级说明 AEAI DP 3.7版本是AEAI DP一个里程碑版本,基于JDK1.7开发,在本版本中新增支持Rest服务开发机制(默认支持WebService服务开发机制),且支持WS服务.RS ...

  5. 一个共通的viewModel搞定所有的分页查询一览及数据导出(easyui + knockoutjs + mvc4.0)

    前言 大家看标题就明白了我想写什么了,在做企业信息化系统中可能大家写的最多的一种页面就是查询页面了.其实每个查询页面,除了条件不太一样,数据不太一样,其它的其实都差不多.所以我就想提取一些共通的东西出 ...

  6. FineUI v4.0.3 (beta) 和 FineUI v3.3.3 发布了!

    关于FineUI基于 ExtJS 的开源 ASP.NET 控件库 FineUI的使命创建 No JavaScript,No CSS,No UpdatePanel,No ViewState,No Web ...

  7. 开源敏捷测试管理& 开源BUG跟踪管理软件itest(爱测试) V3.3.0隆重发布

    v3.3.0 下载地址 :itest下载 码云源码地址 https://gitee.com/itestwork/itest 开源中国  itest项目地址   https://www.oschina. ...

  8. 痞子衡嵌入式:MCUBootUtility v3.0发布,开始支持LPC, Kinetis啦

    -- 痞子衡维护的NXP-MCUBootUtility工具距离上一个版本(v2.4.0)发布过去2个半月了,这一次痞子衡为大家带来了全新版本v3.0.0,从这个版本开始,NXP-MCUBootUtil ...

  9. 痞子衡嵌入式:MCUBootFlasher v3.0发布,为真实的产线操作场景而生

    -- 痞子衡维护的NXP-MCUBootFlasher工具(以前叫RT-Flash)距离上一个版本(v2.0.0)发布过去一年半以上了,这一次痞子衡为大家带来了全新版本v3.0.0,从这个版本开始,N ...

随机推荐

  1. GitHub Flow & Git Flow 基于Git 的两种协作开发模式

    介绍基于Git 两种协作开发模式,GitHub Flow & Git Flow 对于Github 一些好用的特殊操作技巧 ,可以见GitHub 特殊操作技巧 和Git的基本操作 一 GitHu ...

  2. [20180808]exists and not exists.txt

    [20180808]exists and not exists.txt --//生产系统遇到的一个性能问题,通过例子来说明: 1.环境:SCOTT@test01p> @ ver1 PORT_ST ...

  3. windows下,下载pip安装

    windows下,下载pip安装 https://pypi.python.org/pypi/pip#downloads 找到source那个压缩文件,下载下来解压. 参考: windows下面安装Py ...

  4. python第一百零九天---Django 4

    session :1. Session 基于Cookie做用户验证时:敏感信息不适合放在cookie中 a. Session原理 Cookie是保存在用户浏览器端的键值对 Session是保存在服务器 ...

  5. 【PAT】B1012 数字分类

    注意逻辑的描述,只要认真看题,就能做对,如果自己结果一直不正确,请仔细推一下样例结果 #include<stdio.h> int arr[1005]; int main(){ int N, ...

  6. Docker 从入门到实践(二)Docker 三个基本概念

    一.Docker 的三个进本概念? 了解 Docker 的三个基本概念,就可以大致了解 Docker 的生命周期. 镜像(Image) 容器(Container) 仓库(Repository) 二.镜 ...

  7. puppet 横向扩展(二)

    Table of Contents 1. 概述 2. 实验环境 3. 实验步骤 3.1. 机器B 的环境 3.1.1. 安装puppetmaster 以及 apache passenger 3.1.2 ...

  8. 【PS技巧】如何校正倾斜的图片

    1.打开PS,直接拖拽图片. 2.点击[滤镜==>扭曲==>镜头校正],出现校正对话框. 3.点击拉直工具,从右向左滑一条直线. 参考文档: 在Photoshop中如何校正倾斜的图片?

  9. 获取当前页面的URL信息

    以前在做网站的时候,经常会遇到当前页的分类高亮显示,以便让用户了解当前处于哪个页面.之前一直是在每个不同页面写方法.工程量大,也不便于修改.一直在想有什么简便的方法实现.后来在网上查到可以用获取当前U ...

  10. ES5-ES6-ES7_对象的扩展

    简化的对象写法 省略同名的属性值,省略方法的function let x = 1; let y = 2; let point = { x, y, setX (x) { this.x = x } }; ...