2013-02-14 55 views
12

語境:整個ASP.NET回傳數據持久

我經常在我們的ASP.NET頁面將不得不數據顯示,到上一個GridView用戶的情況下,讓他改變他自己高興(單元格上的文本框),並且只有在實際點擊「保存按鈕」時纔將其保存到數據庫中。這些數據通常是頁面信息的虛擬狀態,這意味着用戶可以在沒有真正保存的情況下更改所有內容,直到他點擊「保存按鈕」。 在這些情況下,始終存在需要在ASP.NET Postback中持久保存的數據列表。這些數據可能是DataTable的一個實例,或者只是一些List<Someclass>

我經常看到有人執行此操作並堅持數據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的值,並且出於某種奇怪的原因,他試圖通過點擊另一頁上的Save按鈕來保存數據?我個人不喜歡這個選項。

其他方法可以將數據放在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; 
    } 
} 

在另一方面,將新的數據列表中的每個用戶進入該頁面時存儲會話。這會影響服務器內存。也許他們可能以某種方式被抹去。

問:

什麼是堅持那種跨回傳數據,考慮對瀏覽器多標籤的上下文的最好的方式,對服務器和維護編碼隊更低的成本?

更新:

由於@nunespascal很好地貼出來,其中一個方案是存儲在SessionViewState使用SessionPageStatePersister。但不幸的是,這不是我的情況。但它與我的最後一個例子並沒有太大的不同,它將數據保存在由存儲在ViewState上的UniqueId索引的會話中。

會有其他選擇嗎?

+0

第二種方法是可行的一些調整:1)使用隱藏的字段,而不是ViewState。這使您可以在ViewState在頁面上可用之前訪問它(有時很有用)。 2)與管理人員進行會話,限制一次可以存儲多少物品並拋出最舊的物品。當然,這並不能完全解決內存問題,但可以讓用戶在應用程序中有機地工作而不用擔心繁忙的用戶在內存中會有數百個大對象/集合。 – 2013-04-24 22:02:24

回答

2

這個問題有一個簡單的解決方案。將ViewState存儲在會話中。

對於您需要使用SessionPageStatePersister

參見:Page State Persister

所有你需要做的是覆蓋PageStatePersister,並使其使用SessionPageStatePersister而不是默認的HiddenFieldPageStatePersister

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

這甚至可以節省您維護獨特鑰匙的麻煩。隱藏字段將被自動用於爲每個頁面實例保留唯一的密鑰。

+0

是的,它一定會解決它。不幸的是,它不是我的情況下的選擇,但感謝您的快速答案。 – 2013-02-14 11:46:02

+0

如果我存儲在視圖狀態,並將視圖狀態存儲在會話中,那麼會如何與我發佈的最後一個示例不同?我的意思是它不會影響服務器內存,或者如果用戶不斷刷新頁面,並且每次都會將新數據存儲到會話中,那麼這將如何管理? – 2013-02-14 11:55:52

+0

是的,它會影響服務器內存。但即使將數據直接存儲在會話中,這也是您所承擔的成本。至於反覆刷新,那些會佔用會話空間。但是,如果您遇到這樣的問題,在會話中您總是可以選擇將其移至數據庫。會話最終會被清除。 – nunespascal 2013-02-14 12:13:29

0

我遇到過類似的情況。這個想法是,如果您允許每個用戶的長時間會話來更改網格視圖,這意味着您也會遇到併發問題,因爲最終您只會接受最後一組對數據的修改。

因此,我的解決方案是,允許更改數據庫,但要確保所有用戶都通過SignalR看到相同的狀態。

現在,併發問題已經消失,但您仍需要進行即時更改。畢竟,您可能不想保存更改。我已通過應用命令設計模式解決了此問題。現在任何一組更改都可以被批准或丟棄。每當你檢查索引,你會看到最後批准的gridview。轉到更新頁面,您會看到實時更新的gridview。此外,去修訂看到舊的批准gridview - 命令設計模式的另一個優點 - 。