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?
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. –