开源项目大家谈-网站性能调校-Page State Persistence

简介: 之所以用这个题目是因为很多人常常问我研究开源项目的意义,有一些开源项目在别人眼里看起来完全没有搞头,是一些没有实用价值的项目。其实开源项目往往是新技术的试验田,是全世界优秀程序开发者智慧的汇集,如果你仔细研读这些开源项目,得到的不仅仅是这个项目的功能,而是观摩新的技术,学习比你更聪明人的智慧。

之所以用这个题目是因为很多人常常问我研究开源项目的意义,有一些开源项目在别人眼里看起来完全没有搞头,是一些没有实用价值的项目。其实开源项目往往是新技术的试验田,是全世界优秀程序开发者智慧的汇集,如果你仔细研读这些开源项目,得到的不仅仅是这个项目的功能,而是观摩新的技术,学习比你更聪明人的智慧。

我一直研究的一个开源项目是DotNetNuke(简称DNN),也许你不知道这是一个什么系统,不过你不用关心这是一个什么系统,因为我要讨论的技术在任何一个ASP.NET网站里都有可能用到,只是用这个开源项目做示范罢了,不过你会看到在开源项目里,MSDN里那些死板的技术说明是如何巧妙发挥功能。

开源网站系统提供的性能设置选项

在DNN开源项目里,有一些设置可以调校网站的性能,包括以下这几个:

image

我会花几篇文章逐个讨论一下这几个选项对网站性能的影响,并给出一些技术分析。 在这一篇文章里,我讨论Page State Persistence这个设置。

什么是Page Sate Persistence

我想大家对ViewState一定不陌生,ViewState是ASP.NET相对ASP新增的一个强大的功能,能够保存一个页面的state。简单的说,就是保存你提交页面时,文本框,下拉列表等等在页面提交那一时刻的值,这样万一你填写的内容通不过检验,就可以用这些信息来还原之前的状态(当然,用处不止这些)。知道ViewSate的人,一般都知道ViewSate使用一个hidden input来保存页面的state信息。网上有很多这样的文章,大家可以Google一下。那这个ViewSate跟性能又有什么关系呢?因为这个hidden input是要跟随PostBack信息在客户端和服务器之间来回传递的,如果这个值太大,自然会影响性能。当然,除了大小,还有一个方面就是ViewState存储的位置了,如果我们不来回传递ViewState的值,而是存储在服务器这一端,自然会减少ViewState在网络上传输占用的时间,但同时却加重了服务器的负担。

可能很多人不知道ASP.NET 2.0的一个新特性就是可以通过重载PageStatePersister类从而实现自定义page ViewState的存储位置。在ASP.NET v1.x里,ViewState只能是存储在之前提到的那个隐藏input元素中。在ASP.NET 2.0 中,新增的SessionPageStatePersister类就提供了把ViewState存储在session里的功能。

开源项目DNN构架如何利用这一新特性

这个开源项目重写了页面的基类,在它自己的基类中,有一个PageStatePersister只读属性,这个属性会根据用户的设置,返回一个System.Web.UI.PageStatePersister实体,之后运行的页面就会用这个实体去实现ViewState的存储,从而实现由用户选择在哪里存储ViewState,从而调节性能。

代码如下:

Protected Overrides ReadOnly Property PageStatePersister() As System.Web.UI.PageStatePersister
Get
'Set ViewState Persister to default (as defined in Base Class)
Dim _persister As PageStatePersister = MyBase.PageStatePersister
If Not DotNetNuke.Common.Globals.HostSettings("PageStatePersister") Is Nothing Then
Select Case DirectCast(DotNetNuke.Common.Globals.HostSettings("PageStatePersister"), String)
Case "M"
_persister = New CachePageStatePersister(Me)
Case "D"
_persister = New DiskPageStatePersister(Me)
Case "S"
_persister = New SessionPageStatePersister(Me)
End Select
End If
Return _persister
End Get
End Property 

从代码我们可以看到,如果用户选择“Page”,那就使用默认的hidden input元素在页面上存储viewstate(在代码的处理上,是判断其它非选择“Page”项的情况,所以你找不到 Case "P" 这一句);如果用户选用的是"Memory",那么在Case "M"这一句,就会返回一个CachePageStatePersister,这是这个开源系统自定义的一个viewstate处理类。那么DNN开源系统就会使用Cache在服务器端存储viewstate的信息,也就是存储在服务器的“Memory”中。

如果是"D",那么是存储在服务端的文件里,所以是"Disk",但系统似乎保留了这个设置,没有提供界面。

如果是"S",那么是存储在Session里面。这个实现是ASP.NET 2.0 已经提供了的。

如何实现

其实比较简单,在ASP.NET 2.0 里, 抽象类PageStatePersister 实现了存储page state到其它地方的基本功能,你只要重写这个抽象类提供的Load和Save方法就可以了。

我们看看DNN开源项目实现的一个CachePageStatePersister:

Imports System.Text
 
Namespace DotNetNuke.Framework
 
''' -----------------------------------------------------------------------------
''' Namespace:  DotNetNuke.Framework
''' Project:    DotNetNuke
''' Class:      CachePageStatePersister
''' -----------------------------------------------------------------------------
''' <summary>
''' CachePageStatePersister provides a cache based page state peristence mechanism
''' </summary>
''' <history>
'''        [cnurse]    11/30/2006    documented
''' </history>
''' -----------------------------------------------------------------------------
Public Class CachePageStatePersister
Inherits PageStatePersister
 
Private Const VIEW_STATE_CACHEKEY As String = "__VIEWSTATE_CACHEKEY"
 
''' -----------------------------------------------------------------------------
''' <summary>
''' Creates the CachePageStatePersister
''' </summary>
''' <history>
'''     [cnurse]        11/30/2006    Documented
''' </history>
''' -----------------------------------------------------------------------------
Public Sub New(ByVal page As Page)
MyBase.New(page)
End Sub
''' -----------------------------------------------------------------------------
''' <summary>
''' Loads the Page State from the Cache
''' </summary>
''' <history>
'''     [cnurse]        11/30/2006    Documented
''' </history>
''' -----------------------------------------------------------------------------
Public Overrides Sub Load()
 
' Get the cache key from the web form data
Dim key As String = TryCast(Page.Request.Params(VIEW_STATE_CACHEKEY), String)
 
'Abort if cache key is not available or valid
If String.IsNullOrEmpty(key) Or Not key.StartsWith("VS_") Then
Throw New ApplicationException("Missing valid " + VIEW_STATE_CACHEKEY)
End If
Dim state As Pair = TryCast(DataCache.GetPersistentCacheItem(key, GetType(Pair)), Pair)
 
If Not state Is Nothing Then
'Set view state and control state
ViewState = state.First
ControlState = state.Second
End If
'Remove this ViewState from the cache as it has served its purpose
DataCache.RemovePersistentCacheItem(key)
 
End Sub
''' -----------------------------------------------------------------------------
''' <summary>
''' Saves the Page State to the Cache
''' </summary>
''' <history>
'''     [cnurse]        11/30/2006    Documented
''' </history>
''' -----------------------------------------------------------------------------
Public Overrides Sub Save()
 
'No processing needed if no states available
If ViewState Is Nothing And ControlState Is Nothing Then
Exit Sub
End If
'Generate a unique cache key
Dim key As New StringBuilder()
With key
.Append("VS_")
.Append(IIf(Page.Session Is Nothing, Guid.NewGuid().ToString(), Page.Session.SessionID))
.Append("_")
.Append(DateTime.Now.Ticks.ToString())
End With
'Save view state and control state separately
Dim state As New Pair(ViewState, ControlState)
 
'Add view state and control state to cache
DataCache.SetCache(key.ToString(), state, Nothing, DateTime.Now.AddMinutes(Page.Session.Timeout), System.Web.Caching.Cache.NoSlidingExpiration, True)
 
'Register hidden field to store cache key in
Page.ClientScript.RegisterHiddenField(VIEW_STATE_CACHEKEY, key.ToString())
End Sub
End Class
End Namespace

对性能有什么影响

性能永远是一个博弈的问题,没有绝对,只有如何平衡。把viewstate放在page的hidden input里面自然会增加客户端的处理时间以及网路传输时间。把viewstate放在服务器端自然会消耗服务器的内存(硬盘)和CPU,所以,没有最好的设置,只有最合适的设置。

  • 如果使用专属的服务器,并且配置较高,使用"Memory"模式,这样会提高网站的速度。
  • 对于一般的应用,使用默认的viewstate设置就可以了,也就是使用hidden input,针对这个开源系统,就是选择"Page"。
  • 如果你发现有一些页面的viewstate特别大,消耗了大量的网络传输时间,你可以选用memory模式,把viewstate放在服务端的Cache里。
  • 很明显,如果使用Disk的方式,会比使用Cache的慢,这种方式也许可以用在那些对反映速度要求不高,viewstate又很大的页面上。
  • 对于存储在Session里的实现方式,之前放在hidden INPUT里的信息会通过BASE64编码在Session里面传递,估计性能上比默认直接使用hidden input的要慢,毕竟你还要进行编码的转换,不过可能对安全性上有帮助,只是我的推测。希望有高手指出错误.
 
参考文档:
ScottGu's Blog: PageStatePersister Extensibility with ASP.NET 2.0
PageStatePersister class in 2.0 - To persist state on page or Session or even on Database.
目录
相关文章
|
4月前
|
数据库连接 数据库
Entity Framework Core 中的延迟加载与即时加载大揭秘!性能考量全知道,助你高效开发!
【8月更文挑战第31天】Entity Framework Core (EF Core) 是一款强大的对象关系映射(ORM)框架,支持延迟加载与即时加载两种方式。延迟加载即访问关联实体时再加载,适用于减少初始查询负载,但可能导致多次数据库查询;即时加载则在查询主实体时一并加载关联实体,减少数据库访问次数,但可能增加初始查询复杂度。选择加载方式需综合考虑查询复杂性、数据量及数据库连接管理等因素。
78 0
|
4月前
|
SQL API 数据库
揭开高效数据层构建的秘密武器:Entity Framework Core 分页查询的最佳实践与性能优化技巧全解析
【8月更文挑战第31天】本文以随笔形式详细探讨了如何在Entity Framework Core中实现分页查询的最佳实践。通过创建基于EF Core的项目,配置数据库上下文,并定义领域模型,文章展示了如何使用`Skip()`和`Take()`方法进行分页查询。此外,还介绍了如何使用惰性加载、显式加载和预加载来优化性能,并通过投影技术减少不必要的数据加载。最后,文章强调了分页查询对于提升应用性能和用户体验的重要性。
74 0
|
缓存
webpack优化篇(四十六):充分利用缓存提升二次构建速度
webpack优化篇(四十六):充分利用缓存提升二次构建速度
444 0
webpack优化篇(四十六):充分利用缓存提升二次构建速度
|
前端开发 JavaScript
webpack原理篇(五十三):Tapable插件架构与Hooks设计
webpack原理篇(五十三):Tapable插件架构与Hooks设计
306 0
webpack原理篇(五十三):Tapable插件架构与Hooks设计
|
缓存 异构计算
Silverlig“.NET研究”ht性能优化纪要
  Silverlight作为微软为富网络应用所做的一个全新的架构,其优秀的表现力让开发者和用户感受到了强烈的冲击,无数的开发者为其着迷,同时微软的广大设计者也在不断地为其完善和充实,同时Silverlight团队也积极的构建Silverlight 5,其初步的版本已在 http://channel9.msdn.com/Series/Silverlight-Firestarter做了演示,从中你可以感受到Silverlight未来之路。
1069 0