我在<<
DNN性能优化方案系列(1)概述 >>说明DNN对性能优化做的努力,Page State Persistence的保存方法是其中一个措施之一.
下面来看下DNN4.5.5的实现.
先看 DotNetNuke_04.05.05_Source\Library\Components\Framework\PageBase.vb
#Region
"Protected Properties"
'
'' -----------------------------------------------------------------------------
'
'' <summary>
'
'' PageStatePersister returns an instance of the class that will be used to persist the Page State
'
'' </summary>
'
'' <returns>A System.Web.UI.PageStatePersister</returns>
'
'' <history>
'
'' [cnurse] 11/30/2005 Created
'
'' </history>
'
'' -----------------------------------------------------------------------------
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
)
End
Select
End
If
Return
_persister
End
Get
End Property
#End Region
其中
Select
Case
DirectCast
(DotNetNuke.Common.Globals.HostSettings(
"
PageStatePersister
"
),
String
)
Case
"
M
"
'
选择将页面状态持久化保存于内存,M即memery首字母
_persister
=
New
CachePageStatePersister(
Me
)
Case
"
D
"
'
选择将页面状态持久化保存于硬盘,D即Disk首字母,不过在主机设置里面似乎没有这个选项
_persister
=
New
DiskPageStatePersister(
Me
)
End
Select
CachePageStatePersister.vb
Imports
System.Text
Namespace DotNetNuke
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 CachePageStatePersisterClass CachePageStatePersister
Inherits PageStatePersister
''' -----------------------------------------------------------------------------
''' <summary>
''' Creates the CachePageStatePersister
''' </summary>
''' <history>
''' [cnurse] 11/30/2006 Documented
''' </history>
''' -----------------------------------------------------------------------------
Public Sub New()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()Sub Load()
' Get the cache key from the web form data
Dim key As String = TryCast(Page.Request.Params("__VIEWSTATE_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 vaild __VIEWSTATE_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
End Sub
''' -----------------------------------------------------------------------------
''' <summary>
''' Saves the Page State to the Cache
''' </summary>
''' <history>
''' [cnurse] 11/30/2006 Documented
''' </history>
''' -----------------------------------------------------------------------------
Public Overrides Sub Save()Sub Save()
'No processing needed if no states available
If ViewState Is Nothing And ControlState Is Nothing Then
Exit Sub
End If
Dim key As New StringBuilder()
Dim _PortalSettings As PortalSettings = PortalController.GetCurrentPortalSettings()
Dim TabId As Integer = _PortalSettings.ActiveTab.TabID
'Generate a unique cache key
With key
.Append("VS_")
.Append(IIf(Page.Session Is Nothing, Guid.NewGuid().ToString(), Page.Session.SessionID))
.Append("_")
.Append(TabId)
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(15), System.Web.Caching.Cache.NoSlidingExpiration, True)
'Register hidden field to store cache key in
Page.ClientScript.RegisterHiddenField("__VIEWSTATE_CACHEKEY", key.ToString())
End Sub
End Class
End Namespace
继承PageStatePersister必须重载Load与Save
DNN将ViewState保存在内存,它将用于保存的Key保存的页面,用于从内存存取ViewState
Page.ClientScript.RegisterHiddenField("__VIEWSTATE_CACHEKEY", key.ToString())
生成一个隐藏域
<input type="hidden" name="__VIEWSTATE_CACHEKEY" id="__VIEWSTATE_CACHEKEY" value="VS_yjp0hlrgns3sqirbw0hsci45_36" />
此Key生成方法如下
With key
.Append("VS_")
.Append(IIf(Page.Session Is Nothing, Guid.NewGuid().ToString(), Page.Session.SessionID))
.Append("_")
.Append(TabId)
End With
并设置Cache过期时间为15分钟
DataCache.SetCache(key.ToString(), state, Nothing, DateTime.Now.AddMinutes(15), System.Web.Caching.Cache.NoSlidingExpiration, True)
如果15分钟后页面才回传就会
Throw New ApplicationException("Missing vaild __VIEWSTATE_CACHEKEY")
就是这个页面的所有ViewState已经全部丢失.
这个Bug怎么处理,DNN不知有没有触觉的办法.我还没发现,或者目前根本还没解觉.
有好办法的同仁请提示下.
DiskPageStatePersister.vb
Imports
System.IO
Imports
System.Text
Namespace DotNetNuke
Namespace DotNetNuke.Framework
''' -----------------------------------------------------------------------------
''' Namespace: DotNetNuke.Framework
''' Project: DotNetNuke
''' Class: DiskPageStatePersister
''' -----------------------------------------------------------------------------
''' <summary>
''' DiskPageStatePersister provides a disk (stream) based page state peristence mechanism
''' </summary>
''' <history>
''' [cnurse] 11/30/2006 documented
''' </history>
''' -----------------------------------------------------------------------------
Public Class DiskPageStatePersisterClass DiskPageStatePersister
Inherits PageStatePersister
''' -----------------------------------------------------------------------------
''' <summary>
''' Creates the DiskPageStatePersister
''' </summary>
''' <history>
''' [cnurse] 11/30/2006 Documented
''' </history>
''' -----------------------------------------------------------------------------
Public Sub New()Sub New(ByVal page As Page)
MyBase.New(page)
End Sub
''' -----------------------------------------------------------------------------
''' <summary>
''' The CacheDirectory property is used to return the location of the "Cache"
''' Directory for the Portal
''' </summary>
''' <remarks>
''' </remarks>
''' <history>
''' [cnurse] 11/30/2006 Created
''' </history>
''' -----------------------------------------------------------------------------
Public ReadOnly Property CacheDirectory()Property CacheDirectory() As String
Get
Return PortalController.GetCurrentPortalSettings.HomeDirectoryMapPath & "Cache"
End Get
End Property
''' -----------------------------------------------------------------------------
''' <summary>
''' The StateFileName property is used to store the FileName for the State
''' </summary>
''' <remarks>
''' </remarks>
''' <history>
''' [cnurse] 11/30/2006 Created
''' </history>
''' -----------------------------------------------------------------------------
Public ReadOnly Property StateFileName()Property StateFileName() As String
Get
Dim key As New StringBuilder()
With key
.Append("VIEWSTATE_")
.Append(Page.Session.SessionID)
.Append("_")
.Append(Page.Request.RawUrl)
End With
Return CacheDirectory & "\" & CleanFileName(key.ToString) & ".txt"
End Get
End Property
''' -----------------------------------------------------------------------------
''' <summary>
''' Loads the Page State from the Cache
''' </summary>
''' <history>
''' [cnurse] 11/30/2006 Documented
''' </history>
''' -----------------------------------------------------------------------------
Public Overrides Sub Load()Sub Load()
Dim reader As StreamReader = Nothing
' Read the state string, using the StateFormatter.
Try
reader = New StreamReader(StateFileName)
Dim serializedStatePair As String = reader.ReadToEnd
Dim formatter As IStateFormatter = Me.StateFormatter
' Deserialize returns the Pair object that is serialized in
' the Save method.
Dim statePair As Pair = CType(formatter.Deserialize(serializedStatePair), Pair)
ViewState = statePair.First
ControlState = statePair.Second
Finally
If Not reader Is Nothing Then
reader.Close()
End If
End Try
End Sub
''' -----------------------------------------------------------------------------
''' <summary>
''' Saves the Page State to the Cache
''' </summary>
''' <history>
''' [cnurse] 11/30/2006 Documented
''' </history>
''' -----------------------------------------------------------------------------
Public Overrides Sub Save()Sub Save()
'No processing needed if no states available
If ViewState Is Nothing And ControlState Is Nothing Then
Exit Sub
End If
If Not (Page.Session Is Nothing) Then
If Not Directory.Exists(CacheDirectory) Then
Directory.CreateDirectory(CacheDirectory)
End If
' Write a state string, using the StateFormatter.
Dim writer As New StreamWriter(StateFileName, False)
Dim formatter As IStateFormatter = Me.StateFormatter
Dim statePair As New Pair(ViewState, ControlState)
Dim serializedState As String = formatter.Serialize(statePair)
writer.Write(serializedState)
writer.Close()
End If
End Sub
End Class
End Namespace
在源码中看到的保存于盘硬的,没有过期这回事,但总不能让那些没用的文件一直留着,要有个删除的办法.但DNN中似乎还没处理这个.
还有这个Key问题,
'
'' -----------------------------------------------------------------------------
'
'' <summary>
'
'' The StateFileName property is used to store the FileName for the State
'
'' </summary>
'
'' <remarks>
'
'' </remarks>
'
'' <history>
'
'' [cnurse] 11/30/2006 Created
'
'' </history>
'
'' -----------------------------------------------------------------------------
Public
ReadOnly
Property StateFileName()
Property StateFileName() As String
Get
Dim key As New StringBuilder()
With key
.Append("VIEWSTATE_")
.Append(Page.Session.SessionID)
.Append("_")
.Append(Page.Request.RawUrl)
End With
Return CacheDirectory & "\" & CleanFileName(key.ToString) & ".txt"
End Get
End Property
与比CachePageStatePersister.vb不周到的地方是他似乎没考虑Page禁用Session的情况.