【问题标题】:Getting asp.net to store viewstate in the session rather than bulking up the html让 asp.net 在会话中存储视图状态而不是增加 html
【发布时间】:2011-01-07 02:24:18
【问题描述】:

我正在尝试让 asp.net 在会话中存储视图状态,而不是增加 html。

现在我已经读到 asp.net 带有 SessionPageStatePersister 可以用来代替默认的 HiddenFieldPageStatePersister 来执行此操作。我想知道如何将它放入?

这是我到目前为止所得到的: 我想我需要创建一个 PageAdapter,它从它的 GetStatePersister 方法返回一个 SessionPageStatePersister,并以某种方式让页面使用这个 pageadapter。但是 Page.PageAdapter 只有一个 getter,所以我不确定你是如何设置它的。

在此处查看“备注”标题:http://msdn.microsoft.com/en-us/library/system.web.ui.hiddenfieldpagestatepersister.aspx

谢谢!

【问题讨论】:

  • 您是否考虑过将 ViewState 存储在数据库中而不是会话中,这应该更容易并且扩展性更好
  • RPM:视图状态已经序列化,所以没有区别。我服务器上的 RAM 比在澳大利亚网络连接上双向发送 100kb 视图状态要快得多。
  • daveo:Db 会比 ram 慢。扩展不是问题 - 不是那种网站。

标签: c# asp.net session viewstate


【解决方案1】:

您确定要这样做吗?有问题

  1. 如何将各个页面分开?当然,您可以在页面前加上会话状态名称,例如。 Session["/default.aspx-Viewstate"] 但是当用户打开一个页面的多个实例时会发生什么?
  2. 因此,为了解决您在每个页面中放置一个带有 GUID 的隐藏字段,然后将其用作键的问题。因此,您的会话大小会增加。并且成长。并且成长。您如何知道是否/何时可以安全移除物品?

如果您坚持要继续阅读,那么您需要做的就是从页面派生一个类并覆盖 LoadPageStateFromPersistenceMedium() 和 SavePageStateToPersistenceMedium()。但你会恨自己,最终把它撕掉。

只要确保您在服务器上打开了 HTTP 压缩,请您考虑其他事情。

【讨论】:

  • 最后一句话让我笑了,但确实如此。 gzip 将弥补一个 viewstate 的世界。
  • 1:我认为这将由内置的 SessionPageStatePersister 类处理
  • 2:公平通话。我肯定我会想到一些事情的。也许是一个圆形数组或其他东西。
【解决方案2】:

对于它的价值,这是我最终用来解决手头大局问题的代码:将视图状态移出 html。只需将其弹出到您的 mypage.aspx.cs 中:

// Inspired by: http://aspalliance.com/72
const string ViewStateFieldName = "__VIEWSTATEKEY";
const string RecentViewStateQueue = "RecentViewStateQueue";
const int RecentViewStateQueueMaxLength = 5;

protected override object LoadPageStateFromPersistenceMedium()
{
    // The cache key for this viewstate is stored where the viewstate normally is, so grab it
    string viewStateKey = Request.Form[ViewStateFieldName] as string;
    if (viewStateKey == null) return null;

    // Grab the viewstate data from the cache using the key to look it up
    string viewStateData = Cache[viewStateKey] as string;
    if (viewStateData == null) return null;

    // Deserialise it
    return new LosFormatter().Deserialize(viewStateData);
}

protected override void SavePageStateToPersistenceMedium(object viewState)
{
    // Serialise the viewstate information
    StringBuilder _viewState = new StringBuilder();
    StringWriter _writer = new StringWriter(_viewState);
    new LosFormatter().Serialize(_writer, viewState);

    // Give this viewstate a random key
    string viewStateKey = Guid.NewGuid().ToString();

    // Store the viewstate in the cache
    Cache.Add(viewStateKey, _viewState.ToString(), null, Cache.NoAbsoluteExpiration, TimeSpan.FromMinutes(Session.Timeout), CacheItemPriority.Normal, null);

    // Store the viewstate's cache key in the viewstate hidden field, so on postback we can grab it from the cache
    ClientScript.RegisterHiddenField(ViewStateFieldName, viewStateKey);

    // Some tidying up: keep track of the X most recent viewstates for this user, and remove old ones
    var recent = Session[RecentViewStateQueue] as Queue<string>;
    if (recent == null) Session[RecentViewStateQueue] = recent = new Queue<string>();
    recent.Enqueue(viewStateKey); // Add this new one so it'll get removed later
    while (recent.Count > RecentViewStateQueueMaxLength) // If we've got lots in the queue, remove the old ones
    Cache.Remove(recent.Dequeue());
}

对于使用 SessionPageStatePersister 的超级简单方法,再次将其放入 mypage.aspx.cs:

protected override PageStatePersister PageStatePersister
{
    get
    {
        return new SessionPageStatePersister(this);
    }
}

【讨论】:

  • 五年后,这段代码仍然值得复制意大利面。我能够将它放入一个 VB.NET 转换器中,并在经过几次小的编辑后将它直接粘贴到我的页面中。我从不建议将视图状态存储在服务器内存中,但这作为一种临时解决方案非常有效,因为我们重写了 15 年前的 WebForms 应用程序以使用 Angular 和 WebAPI。只需确保在完成后清理缓存的视图状态,而不是等待它过期。
  • @oscilatingcretin 所以就在您在 LoadPageStateFromPersistenceMedium() 中返回视图状态之前,执行 Cache.Remove(viewStateKey)?我认为这样做是安全的,因为为后续回调生成了新的视图状态?在 SavePageStateToPersistenceMedium() 中清除旧的可能仍然是个好主意
  • 忽略我最后的建议。加载后无法删除;如果用户刷新返回相同表单数据的页面怎么办?它会丢失该页面的状态。
  • @Radderz 在完整的邮包后,我没有丢失任何视图状态。该代码在页面上注册了一个隐藏字段,该字段在回发中持续存在,因此保留了 GUID。当新页面被加载(即不是 IsPostback)时,会创建一个新的 GUID。这是我的理解,至少
【解决方案3】:

为了使用您的自定义 PageAdapter 类,您必须使用 .browser 文件注册它。您需要添加(如果您还没有)一个 App_Browsers 目录。然后添加一个带有以下 XML 的 .browser 文件

<browsers>
    <browser refID="Default">
        <controlAdapters>
           <adapter controlType="System.Web.UI.Page" adapterType="{Your adapter type}" />
        </controlAdapters>
    </browser>
</browsers> 

将 {Your adapter type} 替换为您的适配器类型。

更多信息here

希望这会有所帮助。

【讨论】:

  • 谢谢,这对我有用。但最后,使用此方法并使用 SessionPageStatePersister 类,它实际上并没有减少视图状态的大小(并且我 确实 断点它以确保它被调用)。我认为它只是存储页面状态,而不是视图状态,所以并不是很大的节省。那好吧。还是谢谢!
猜你喜欢
  • 2012-02-12
  • 1970-01-01
  • 1970-01-01
  • 2012-12-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-01-02
  • 1970-01-01
相关资源
最近更新 更多