在大型网站中,页面数量众多,用户量大,因此减少客户端和服务器之间来回传输的视图状态是提高性能的关键。本文将介绍一种将视图状态存储在数据库中的策略,以及如何通过.NET代码来实现这一策略。
首先,需要创建一个用于存储视图状态的数据库表。这个表将包含一个唯一标识视图状态的键(View_State_Key),一个存储视图状态字符串的列(View_State_Value),以及一个记录插入时间的列(Insert_Time)。
CREATE TABLE [dbo].[View_State] (
View_State_Key NVARCHAR(250) NOT NULL,
View_State_Value NVARCHAR(MAX) NULL,
Insert_Time DATETIME NOT NULL CONSTRAINT DF_View_State_Insert_Time DEFAULT (GETDATE()),
CONSTRAINT PK_View_State PRIMARY KEY CLUSTERED (
View_State_Key ASC
) ON [PRIMARY]
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
这个表的设计允许将视图状态的键注入到网页中,而不是实际的视图状态。这样可以减少数据传输量。
接下来,需要创建一些存储过程来获取和设置视图状态。这些存储过程非常简单,但非常有效。
CREATE PROCEDURE [dbo].[sp_get_view_state]
@View_State_Key NVARCHAR(250)
AS
BEGIN
SET NOCOUNT ON;
SELECT TOP 1 View_State_Value FROM View_State WITH (NOLOCK) WHERE View_State_Key = @View_State_Key
END
CREATE PROCEDURE [dbo].[sp_set_view_state]
@View_State_Key NVARCHAR(250),
@View_State_Value NVARCHAR(MAX)
AS
BEGIN
SET XACT_ABORT ON;
BEGIN TRY
BEGIN TRANSACTION
INSERT INTO View_State(View_State_Key, View_State_Value) VALUES (@View_State_Key, @View_State_Value)
COMMIT TRANSACTION
RETURN 0
END TRY
BEGIN CATCH
IF @@TRANCOUNT > 0 ROLLBACK TRANSACTION
RETURN -1
END CATCH
END
这些存储过程将用于从数据库中检索和存储视图状态。
还需要一个存储过程来删除过期的视图状态。这个存储过程将删除所有至少2小时没有被访问的视图状态。
CREATE PROCEDURE [dbo].[sp_delete_view_state]
AS
BEGIN
SET NOCOUNT ON;
DECLARE @hours INT = 2
DELETE FROM View_State WHERE DATEDIFF(hour, Insert_Time, GETDATE()) > @hours
END
这个存储过程将由SQL Server作业定期执行,而不是直接从.NET代码中执行。
ViewStateManagement类负责读取和写入视图状态。它在网页和数据库之间进行协调。SetViewState方法存储视图状态。首先,该方法使用专用的.NET类LosFormatter将视图状态对象序列化为字符串。然后,它构建一个唯一标识视图状态的键。
public static class ViewStateManagement
{
public static bool SetViewState(
Page page,
HttpContext context,
string connectionString,
object viewState,
string uniqueKey = null)
{
StringBuilder sb = new StringBuilder();
using (StringWriter swr = new StringWriter(sb))
new System.Web.UI.LosFormatter().Serialize(swr, viewState);
string viewStateKey = string.Format("VIEWSTATE_{0}_{1}_{2}", uniqueKey, GetIP(context), DateTime.Now.Ticks);
bool succeeded = SetViewState(connectionString, viewStateKey, sb.ToString());
if (succeeded)
page.ClientScript.RegisterHiddenField("__VIEWSTATE_KEY", viewStateKey);
return succeeded;
}
}
Get方法从HTTP请求中提取__VIEWSTATE_KEY。有了这个键,它将查询数据库,从数据库中获取视图状态字符串,并使用LosFormatter将其反序列化为对象。
public static class ViewStateManagement
{
public static object GetViewState(HttpContext context, string connectionString)
{
if (context == null || context.Request == null)
return null;
string viewStateKey = context.Request.Form["__VIEWSTATE_KEY"];
if (!string.IsNullOrEmpty(viewStateKey) && viewStateKey.StartsWith("VIEWSTATE_"))
{
string viewState = GetViewState(connectionString, viewStateKey);
if (!string.IsNullOrEmpty(viewState))
return new System.Web.UI.LosFormatter().Deserialize(viewState);
}
return null;
}
}
public abstract class BasePage : System.Web.UI.Page
{
protected override void SavePageStateToPersistenceMedium(object viewState)
{
string uniqueKey = null;
string connectionString = HttpContext.Current.Session["ConnectionString"] as string;
bool succeeded = ViewStateManagement.SetViewState(this, HttpContext.Current, connectionString, viewState, uniqueKey);
if (!succeeded)
base.SavePageStateToPersistenceMedium(viewState);
}
protected override object LoadPageStateFromPersistenceMedium()
{
string connectionString = HttpContext.Current.Session["ConnectionString"] as string;
object viewState = ViewStateManagement.GetViewState(HttpContext.Current, connectionString);
if (viewState != null)
return viewState;
else
return base.LoadPageStateFromPersistenceMedium();
}
}