四:理解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要做的事情也多了
用与不用还要自己权衡

目录
相关文章
|
8月前
|
Java 测试技术 API
Java RESTful中的PATCH请求:局部更新与资源修改
在RESTful架构中,PATCH请求是一种用于局部更新已有资源的操作。PATCH请求允许客户端将部分数据发送到服务器,以便对资源进行局部修改,而不必替换整个资源。本文将引导您深入了解Java中使用PATCH请求构建RESTful API,探讨其特点、实现方式、用例以及在实际应用中的优势。
|
1月前
|
传感器 安全
3500/42 GE / 本特利内华达 带内部屏障和内部终端的I/O模块
3500/42 GE / 本特利内华达 带内部屏障和内部终端的I/O模块
|
8月前
|
存储 Java
|
测试技术
软件测试面试题:page object设置模式中,是否需要在page里定位的方法中加上断言?
软件测试面试题:page object设置模式中,是否需要在page里定位的方法中加上断言?
98 0
|
缓存
读源码长知识 | 动态扩展类并绑定生命周期的新方式
在阅读viewModelScope源码时,发现了一种新的方式。 协程需隶属于某 CoroutineScope ,以实现structured-concurrency,而 CoroutineScope 应
136 0
|
存储 缓存 Android开发
聊聊ViewPager2中的缓存和复用机制
聊聊ViewPager2中的缓存和复用机制
聊聊ViewPager2中的缓存和复用机制
|
前端开发 数据格式
【Taro工作记录一】如何判断对象为空得方式
【Taro工作记录一】如何判断对象为空得方式
119 0
SAP Spartacus Unit List树形数据的加载触发时机
SAP Spartacus Unit List树形数据的加载触发时机
SAP Spartacus Unit List树形数据的加载触发时机
|
数据采集 前端开发 JavaScript
pyppeteer最为核心类Page的接口方法(下)
重要:因为同步公号的文章格式很难保证,所以后面文章选择性在其他平台同步,欢迎移步公众号(Python之战),每日更新原汁原味! 在上一篇《pyppeteer最为核心类Page的接口方法》讲了大部分pyppeteer的Page类的接口,与selenium相比增强了与页面js的交互功能,同时增加了设备的伪装和模拟能力,一方是因为pyppeteer库是源于puppeteer,而puppeteer是Google提供了一个js库,本身和js的交互性强,所以在页面交互上更深入。
1847 0
|
Web App开发 JavaScript 前端开发
pyppeteer最为核心类Page的接口方法
重要:因为同步公号的文章格式很难保证,所以后面文章选择性在其他平台同步,欢迎移步公众号(Python之战),每日更新原汁原味! 重要:因为同步公号的文章格式很难保证,所以后面文章选择性在其他平台同步,欢迎移步公众号(Python之战),每日更新原汁原味! Page类是pyppeteer的核心,...
1927 0