ASP.NET回发中的数据持久性

时间:2013-02-14 11:33:07

标签: c# asp.net session webforms viewstate

背景:

我经常遇到这样的情况:我们的ASP.NET页面必须在GridView上向用户显示数据,让他随心所欲地更改它(单元格上的文本框)并且只在实际上将它保存到数据库中点击“保存按钮”。这些数据通常是页面上信息的虚拟状态,这意味着用户可以更改所有内容而无需保存,直到他点击“保存按钮”。 在这些情况下,总是需要在ASP.NET回发中保留数据列表。此数据可以是DataTable的实例,也可以是List<Someclass>的实例。

我经常看到人们实现这一点并将数据保存在Session上。在这种情况下,我通常也会看到一些用户导航时打开多个标签的问题,有些时候在同一页面上。两个不同选项卡的数据合并在一起,导致信息被扰乱的问题。

经常使用Session的示例:

private List<SomeClass> DataList
{
    get
    {
        return Session["SomeKey"] as List<SomeClass>;
    }
    set 
    {
        Session["SomeKey"] = value;
    }
}

人们经常试图通过这样做来解决它:

protected void Page_Load(object sender, EventArgs e)
{
    if (!IsPostBack)
    {
        DataList = null
    }
    else
    {
        FillGridView(DataList);
    }
}

但是当两个标签已经加载并且用户正在更改GridView值并且由于一些奇怪的原因他尝试通过点击另一页上的“保存”按钮来保存数据时呢?我个人不喜欢这个选项。

其他方法是将数据放在ViewState上。但是,当涉及到持久存在的大型列表时,它可能会严重影响页面存储在页面上(HiddenField)。

但是,这项工作的最佳方式是什么?有一次,我考虑将SessionViewState一起使用,其中ViewState将包含唯一标识符,该标识符将对Session已保存的数据编制索引。这样可以防止在浏览器上的标签之间共享数据:

private List<SomeClass> DataList
{
    get
    {
        if (ViewState["SomeKey"] == null)
        {
            ViewState["SomeKey"] = Guid.NewGuid().ToString();
        }

        return Session[ViewState["SomeKey"].ToString()] as List<SomeClass>;
    }
    set {

        if (ViewState["SomeKey"] == null)
        {
            ViewState["SomeKey"] = Guid.NewGuid().ToString();
        }

        Session[ViewState["SomeKey"].ToString()] = value;
    }
}

另一方面,每次用户进入页面时,它都会向Session存储一个新的数据列表。哪会影响服务器内存。也许他们可能会以某种方式被删除。

问题:

考虑到浏览器上多个标签的上下文,服务器和维护编码团队的成本较低,在Postbacks中保留这类数据的最佳方法是什么?

更新

正如@nunespascal发布的很好,一个选项是使用ViewStateSession存储在SessionPageStatePersister中。但不幸的是,这不是我的选择。然而它与我上一个例子没有什么不同,将数据保存在由ViewState上存储的UniqueId索引的Session上。

还有其他选择吗?

2 个答案:

答案 0 :(得分:2)

这个问题有一个简单的解决方案。将ViewState存储在会话中。

为此您需要使用SessionPageStatePersister

参考:Page State Persister

您需要做的只是覆盖PageStatePersister并使用SessionPageStatePersister而不是默认HiddenFieldPageStatePersister

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

这甚至可以省去维护唯一密钥的麻烦。隐藏字段将自动用于为每个页面实例保留唯一键。

答案 1 :(得分:0)

我遇到了类似的情况。我们的想法是,如果您允许每个用户使用长会话来更改网格视图,这意味着您还会遇到并发问题,因为最终您只接受对数据进行的最后一组修改。

所以,我的解决方案是允许对数据库进行更改,但要确保所有用户通过SignalR看到相同的状态。

现在,并发问题已经消失,但您仍需要动态进行更改。毕竟,您可能不想保存更改。我通过应用命令设计模式解决了这个问题。现在,任何一组更改都可以被批准或丢弃。每当您检查索引时,您将看到最后批准的gridview。转到更新页面,您会看到实时更新的gridview。另外,请修改以查看旧的已批准的gridview - 命令设计模式的其他优点 - 。