开发者社区> xland> 正文

四:理解Page类的运行机制(例:基于PageStatePersister的页面状态存取)

简介: 有人说类似gridview datalist这样的控件最好不要用在高并发,IO大的网站中企业应用中为了快速开发到可以用一用因为这是一类"沉重"的组件我们姑且不谈这种看法的正确性(我个人觉得有道理)只谈它为什么笨重:因为这些控件给页面带来了大量的viewstateusing System;using System.
+关注继续查看

 有人说类似gridview datalist这样的控件最好不要用在高并发,IO大的网站中
企业应用中为了快速开发到可以用一用
因为这是一类"沉重"的组件
我们姑且不谈这种看法的正确性(我个人觉得有道理)
只谈它为什么笨重:

因为这些控件给页面带来了大量的
viewstate
<input type="hidden" name="____VIEWSTATE" id="____VIEWSTATE" value=
这就是页面状态
一个页面里可能存在两种状态
控件状态,视图状态

page类是在
LoadPageStateFromPersistenceMedium()
SavePageStateToPersistenceMedium()
存取页面状态的
这两个方法都是可以重写的
他们也可以把状态信息存储在别的媒介中
我们这里通过重写PageStatePersister属性
来实现自己的状态存取逻辑

我们为了压缩viewstate里的数据,必须先实现一个工具类:如下

Code
using System;
using System.IO;
using System.IO.Compression;
using System.Web.UI;

/// <summary>
///GZipCompress 的摘要说明
/// </summary>
public class GZipCompress
{
    
//LosFormatter序列化web窗体页的视图状态
    private static LosFormatter _formater = new LosFormatter();
    
public GZipCompress()
    {}
    
//带压缩功能的序列化
    public static string Compress(object state)
    {
        StringWriter writer 
= new StringWriter();
        
//序列化状态
        _formater.Serialize(writer, state);
        
//取得序列化结果
        string stateString = writer.ToString();
        writer.Close();
        
//将字符串转换成八位无符号整数数组
        byte[] buffer = Convert.FromBase64String(stateString);
        MemoryStream ms 
= new MemoryStream();
        
//搞一个压缩流出来,将流保持为打开的状态
        GZipStream zipStream = new GZipStream(ms, CompressionMode.Compress, true);
        zipStream.Write(buffer, 
0, buffer.Length);
        zipStream.Close();
        buffer 
= new byte[ms.Length];
        
//获取或设置流中的当前位置
        ms.Position = 0;
        ms.Read(buffer, 
0, buffer.Length);
        ms.Close();
        
//将压缩结果转成字符串,便于保存在页面中
        stateString = Convert.ToBase64String(buffer);
        
return stateString;
    }
    
public static object Decompress(string stateString)
    {
        
byte[] buffer = Convert.FromBase64String(stateString);
        MemoryStream ms 
= new MemoryStream(buffer);
        GZipStream zipStream 
= new GZipStream(ms, CompressionMode.Decompress);
        MemoryStream msReader 
= new MemoryStream();
        buffer 
= new byte[0x1000];//开辟0x1000个字节空间16*16*16=4K
        while (true)
        {
            
int read = zipStream.Read(buffer, 0, buffer.Length);
            
if (read <= 0)
            { 
break; }
            msReader.Write(buffer, 
0, read);
        }
        zipStream.Close();
        ms.Close();
        msReader.Position 
= 0;
        buffer 
= msReader.ToArray();
        stateString 
= Convert.ToBase64String(buffer);
        
return _formater.Deserialize(stateString);
    }
}

 

 下面重写PageStatePersister来实现自定义的页面状态存取

Code
using System;
using System.Data;
using System.Configuration;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.HtmlControls;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.IO;
using System.IO.Compression;

/// <summary>
///PageStatePersister 的摘要说明
/// </summary>
public class CompressPageStatePersister:PageStatePersister
{
    
private const string STATEKEY = "____VIEWSTATE";
    
//调用基类构造函数
    public CompressPageStatePersister(Page page) : base(page) { }
    
    
//加载页面状态
    public override void Load()
    {
        
//取得保存在客户端的状态内容
        string postbackstate = Page.Request.Form[STATEKEY];
        
if (!string.IsNullOrEmpty(postbackstate))
        {
            
//解压,反序列化
            
//asp.net的viewstate包括控件状态和视图状态
            
//存储两个相关对象
            Pair statePair = (Pair)GZipCompress.Decompress(postbackstate);
            
if (Page.EnableViewState)
            {
                ViewState 
= null;
            }
            
else
            {
                ViewState 
= statePair.First;
            }
            ControlState 
= statePair.Second;
        }       
    }
    
//保存页面状态
    public override void Save()
    {
        
if (!Page.EnableViewState)
        {
            ViewState 
= null;
        }
        
if (ViewState != null || ControlState != null)
        {
            
string stateString;
            Pair statePair 
= new Pair(ViewState, ControlState);
            
//序列化,压缩
            stateString = GZipCompress.Compress(statePair);
            
//把页面状态注册到页面上
            Page.ClientScript.RegisterHiddenField(STATEKEY, stateString);
        }
    }
}

 项目的webconfig文件

Code
<?xml version="1.0"?>
<configuration>
  
<appSettings/>
  
<connectionStrings>
    
<add name="AntMallConnectionString" connectionString="Data Source=192.168.1.186;Initial Catalog=AntMall;Integrated Security=True"
      providerName
="System.Data.SqlClient" />
  
</connectionStrings>
  
<system.web>
    
<compilation debug="true"></compilation>
    
<authentication mode="Forms"/>
  
</system.web>
</configuration>

用来测试的一个页面

Code
<%@ Page Language="C#" AutoEventWireup="true"  CodeFile="Default.aspx.cs" Inherits="_Default" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    
<title>无标题页</title>
</head>
<body>
    
<form id="form1" runat="server">
    
<div>    
        
<asp:GridView ID="GridView1" runat="server" AllowPaging="True" 
            DataSourceID
="SqlDataSource1" AutoGenerateColumns="False">
            
<Columns>
                
<asp:BoundField DataField="title" HeaderText="title" SortExpression="title" />
                
<asp:BoundField DataField="memo" HeaderText="memo" SortExpression="memo" />
                
<asp:BoundField DataField="fullPrice" HeaderText="fullPrice" 
                    SortExpression
="fullPrice" />
                
<asp:BoundField DataField="defaultPic" HeaderText="defaultPic" 
                    SortExpression
="defaultPic" />
                
<asp:BoundField DataField="inputTime" HeaderText="inputTime" 
                    SortExpression
="inputTime" />
            
</Columns>
        
</asp:GridView>
        
<asp:SqlDataSource ID="SqlDataSource1" runat="server" 
            ConnectionString
="<%$ ConnectionStrings:AntMallConnectionString %>" 
            SelectCommand
="SELECT [fullPrice], [inputTime], [memo], [title], [defaultPic] FROM [Product]">
        
</asp:SqlDataSource>    
    
</div>
    
</form>
</body>
</html>

用来测试的页面的cs文件
注意里面重写了PageStatePersister

Code
using System;
using System.Configuration;
using System.Data;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.HtmlControls;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;

public partial class _Default : System.Web.UI.Page
{
    
#region 重写PageStatePersister定制页面状态持久化行为
    CompressPageStatePersister _pageStatePersister 
= null;
    
protected override PageStatePersister PageStatePersister
    {
        
get
        {
            
if (_pageStatePersister == null)
            {
                _pageStatePersister 
= new CompressPageStatePersister(this);
            }
            
return _pageStatePersister;
        }
    }
    
#endregion
    
protected void Page_Load(object sender, EventArgs e)
    {

    }
}

 

实验做完
大家运行一下就知道
定制出来的viewstate比自动生成的要小很多

最后评价一句
传输给客户的东西是少了许多
但是服务器的CPU要做的事情也多了
用与不用还要自己权衡

版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

相关文章
定义一个事件需要单独新建一个文件吗?底层原理是什么?
定义一个事件需要单独新建一个文件吗?底层原理是什么?
12 0
JAVA中对Color对象共用缓存,如何处理?
JAVA中对Color对象共用缓存,如何处理?
20 0
第三十章 使用系统监视器 - 编写用户定义的应用程序监视器类
第三十章 使用系统监视器 - 编写用户定义的应用程序监视器类
26 0
读源码长知识 | 动态扩展类并绑定生命周期的新方式
在阅读viewModelScope源码时,发现了一种新的方式。 协程需隶属于某 CoroutineScope ,以实现structured-concurrency,而 CoroutineScope 应
59 0
如何在 Spartacus 使用 UserAccountFacade 在语言设置更改后重新读取用户数据
如何在 Spartacus 使用 UserAccountFacade 在语言设置更改后重新读取用户数据
42 0
聊聊ViewPager2中的缓存和复用机制
聊聊ViewPager2中的缓存和复用机制
1053 0
JSP中静态包含与动态包含的关系
JSP中静态包含与动态包含的关系
53 0
SAP Spartacus Unit List树形数据的加载触发时机
SAP Spartacus Unit List树形数据的加载触发时机
45 0
将函数放在对象的Value上,然后传给组件执行,实现组件抽象
代码总是可以解决很多问题,在Coding 时,应该及时重构,将代码中的坏味道及时剔除,为以后业务功能开发解决技术债。
612 0
pyppeteer最为核心类Page的接口方法
重要:因为同步公号的文章格式很难保证,所以后面文章选择性在其他平台同步,欢迎移步公众号(Python之战),每日更新原汁原味! 重要:因为同步公号的文章格式很难保证,所以后面文章选择性在其他平台同步,欢迎移步公众号(Python之战),每日更新原汁原味! Page类是pyppeteer的核心,...
1793 0
pyppeteer最为核心类Page的接口方法(下)
重要:因为同步公号的文章格式很难保证,所以后面文章选择性在其他平台同步,欢迎移步公众号(Python之战),每日更新原汁原味! 在上一篇《pyppeteer最为核心类Page的接口方法》讲了大部分pyppeteer的Page类的接口,与selenium相比增强了与页面js的交互功能,同时增加了设备的伪装和模拟能力,一方是因为pyppeteer库是源于puppeteer,而puppeteer是Google提供了一个js库,本身和js的交互性强,所以在页面交互上更深入。
1689 0
《一切皆是映射:代码的本质》Java 动态读取源代码,并编译 & 加载执行
动态的执行一段简单代码,采用生成java文件,调用javac编译,反射执行的方式。 使用输入输出流(或者你说的可能是要用反射得到程序结果来解析)解析做出*.Java文件。
1122 0
【PageLayout】非常简单的一键切换加载-空数据-错误页,支持自定义
版权声明:本文为博主原创文章,转载请标明出处。 https://blog.csdn.net/lyhhj/article/details/82594706 项目中我们经常会用到的加载数据,加载完数据后显示内容,如果没有数据显示一个空白页,这是如果网络错误了显示一个网络错误页,自定义一个PageLayout。
1068 0
阐述Session加载实体对象的过程
Session加载实体对象的步骤是: ① Session在调用数据库查询功能之前,首先会在一级缓存中通过实体类型和主键进行查找,如果一级缓存查找命中且数据状态合法,则直接返回; ② 如果一级缓存没有命中,接下来Session会在当前NonExists记...
1096 0
+关注
xland
上市公司研发部门经理 管理着40个人以上的技术团队; 服务过诸多大型客户; 为很多知名开源项目提交过代码; 开发过几十万用户的APP; 技能:C++/.NET/JS/架构
文章
问答
视频
相关电子书
更多
对象的生命期管理
立即下载
低代码开发师(初级)实战教程
立即下载
阿里巴巴DevOps 最佳实践手册
立即下载