2013-02-14 55 views
12

Kontekst:Dane Trwałość całej postbacks ASP.NET

mam często w sytuacjach, gdy nasze strony ASP.NET musiałyby pokazują dane użytkownika na GridView, niech go zmienić, jak mu się podoba (Pole tekstowe na komórkach) i zapisz go tylko do bazy danych, gdy faktycznie trafi w "przycisk Zapisz". Dane te są zwykle stanem wirtualnym informacji na stronie, co oznacza, że ​​użytkownik może zmienić wszystko bez faktycznego zapisywania go, dopóki nie dotknie przycisku "Zapisz". W tych przypadkach zawsze jest lista danych, które należy przechowywać w raportach zwrotnych ASP.NET. Te dane mogą być instancją DataTable lub po prostu List<Someclass>.

Często widzę ludzi, którzy to wdrażają i utrzymują dane na Session. W takich przypadkach zazwyczaj widzę problemy, gdy użytkownik porusza się z otwartymi kilkoma zakładkami, czasami na tej samej stronie. Gdzie dane dwóch różnych kart zostałyby scalone i powodowały problemy z szyfrowaniem informacji.

Przykład jak sesja jest często używany:

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

Ludzie często stara się go rozwiązać, wykonując coś takiego:

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

ale co, gdy dwie karty są już załadowane, a użytkownik zmienia wartości GridView iz jakiegoś dziwnego powodu próbuje zapisać dane, naciskając przycisk Zapisz na drugiej stronie? Osobiście nie lubię tej opcji.

Innymi sposobami na zrobienie tego byłoby umieszczenie danych na ViewState. Jednak w przypadku utrzymywania zasadniczo dużych list może to mieć duży wpływ na stronę, gdy jest ona przechowywana na stronie (HiddenField).

Ale jaki jest najlepszy sposób, aby to zadziałało? Kiedyś pomyślałem, że używając Session wraz z ViewState, gdzie ViewState będzie posiadać unikalny identyfikator, który będzie indeksować zapisane dane Session. Które uniemożliwiłyby dzielenie danych pomiędzy zakładkami w przeglądarce:

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; 
    } 
} 

Z drugiej strony byłoby zapisać nową listę danych do sesji za każdym razem użytkownik wchodzi na stronę. Co wpłynie na pamięć serwera. Może w jakiś sposób można je wymazać.

Pytanie:

Jaki byłby najlepszy sposób utrzymującej tego rodzaju danych na postbacks, biorąc pod uwagę konteksty wielu kart w przeglądarce, przy niższych kosztach do serwera i do zespołu kodującego konserwacja ?

Aktualizacja:

Jak @nunespascal ładnie pisał, jedną z opcji byłoby przechowywać ViewState w Session pomocą SessionPageStatePersister. Ale niestety nie jest to opcja w mojej sprawie. A jednak nie jest to bardzo różni się od mojego ostatniego przykładu, zapisywanie danych na sesji indeksowane przez UniqueId przechowywane na ViewState.

Czy byłyby jeszcze jakieś inne opcje?

+0

Drugie podejście można wykonać za pomocą kilku poprawek: 1) użyj ukrytego pola zamiast elementu ViewState. Pozwala to uzyskać do nich dostęp, zanim funkcja ViewState będzie dostępna na stronie (czasami przydatne). 2) Zawiń sesję z menedżerem, który ogranicza liczbę przedmiotów, które mogą być przechowywane jednocześnie i wyrzuca najstarsze przedmioty. Oczywiście nie rozwiązuje to całkowicie problemu z pamięcią, ale może znacznie przyczynić się do umożliwienia użytkownikom ekologicznej pracy w aplikacji bez obawy, że zajęty użytkownik będzie miał w pamięci setki dużych obiektów/zbiorów. –

Odpowiedz

2

Istnieje proste rozwiązanie tego problemu.Przechowuj ViewState w sesji.

Do tego trzeba użyć SessionPageStatePersister

Patrz: Page State Persister

Wszystko, co musisz zrobić, to zastąpić PageStatePersister i uczynić go używać SessionPageStatePersister zamiast domyślnego HiddenFieldPageStatePersister

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

ten nawet oszczędza ci bólu głowy z utrzymaniem unikalnego klucza. Ukryte pole będzie używane automatycznie, aby zachować unikalny klucz dla każdej instancji strony.

+0

Tak, zdecydowanie by to rozwiązało. Niestety nie jest to opcja w moim przypadku, ale dzięki za szybką odpowiedź. –

+0

Jeśli przechowuję na stanie wyświetlania i przechowuję stan wyświetlania w sesji, w jaki sposób różni się on od ostatnio wysłanego przykładu? Chodzi mi o to, czy nie wpłynęłoby to na pamięć serwera, czy w jaki sposób byłoby to zarządzane, gdyby użytkownik odświeżał stronę i konsekwentnie zapisywał nowe dane do sesji za każdym razem? –

+0

Tak, wpłynie to na pamięć serwera. Jest to jednak koszt, który można ponieść, nawet jeśli dane były przechowywane bezpośrednio w sesji. Jeśli chodzi o wielokrotne odświeżanie, te będą pochłaniały przestrzeń sesji. Ale jeśli napotkasz takie problemy, podczas sesji zawsze możesz przenieść to do bazy danych. Sesje w końcu zostaną oczyszczone. – nunespascal

0

Natknąłem się na podobną sytuację. Pomysł polega na tym, że jeśli zezwalasz na długie sesje dla każdego użytkownika, aby zmienić widok siatki, oznacza to, że będziesz mieć również problem z współbieżnością, ponieważ ostatecznie zaakceptujesz tylko jeden ostatni zestaw modyfikacji danych.

Tak, moim rozwiązaniem było, aby umożliwić zmiany w bazie danych, ale upewnij się, że wszyscy użytkownicy widzą ten sam stan przez SignalR.

Teraz problem współbieżności zniknął, ale wciąż trzeba wprowadzić zmiany w locie. Może jednak nie chcesz zapisać zmian. Rozwiązałem ten problem, stosując wzór projektowania komend . Teraz każdy zestaw zmian może zostać zatwierdzony lub odrzucony. Za każdym razem, gdy sprawdzasz indeks, zobaczysz ostatni zatwierdzony gridview. Przejdź do strony aktualizacji i zobacz zaktualizowany na żywo widok siatki. Przejdź także do wersji, aby zobaczyć stary zatwierdzony widok siatki - inne zalety wzorowania komend -.