2013-02-14 11 views
12

Contesto:dati Persistenza attraverso postback ASP.NET

ho spesso trovato in situazioni in cui le nostre pagine ASP.NET avrebbero dovuto mostrare i dati per l'utente su un GridView, fargli modificarlo a suo piacimento (Casella di testo sulle celle) e salvarlo solo nel database quando effettivamente colpisce il "Pulsante Salva". Questi dati sono di solito uno stato virtuale delle informazioni sulla pagina, il che significa che l'utente può cambiare tutto senza realmente salvarlo fino a quando non preme il pulsante "Salva". In questi casi, è sempre presente un elenco di dati che deve essere mantenuto tra i postback ASP.NET. Questi dati potrebbero essere un'istanza di DataTable o solo alcuni List<Someclass>.

Spesso vedo persone che implementano questo e persistono i dati su Session. In questi casi, inoltre, di solito vedo problemi quando si tratta di un utente che naviga con più schede aperte, alcune volte nella stessa pagina. Dove i dati di due diverse schede verrebbero unite e causerebbero problemi di criptazione delle informazioni.

Esempio di sessione è usato spesso:

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

gente spesso cerca di risolverlo facendo qualcosa di simile a questo:

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

Ma che dire quando due schede sono già caricati e l'utente sta cambiando i valori di GridView e per qualche strano motivo prova a salvare i dati premendo il pulsante Salva sull'altra pagina? Personalmente non mi piace questa opzione.

Altri modi per fare questo sarebbe inserire i dati su ViewState. Tuttavia, quando si tratta di persistere in elenchi di grandi dimensioni, può influire pesantemente sulla pagina quando viene memorizzata nella pagina (HiddenField).

Ma qual è il modo migliore per farlo funzionare? Una volta, ho pensato di utilizzare Session insieme a ViewState dove lo ViewState avrebbe conservato un identificatore univoco che indicizzerebbe i dati salvati Session. Che impedirebbe la condivisione dei dati tra le schede del browser:

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

D'altra parte sarebbe memorizzare un nuovo elenco di dati alla sessione ogni volta che l'utente entra nella pagina. Che potrebbe avere un impatto sulla memoria del server. Forse potrebbero essere cancellati in qualche modo.

Domanda:

Quale sarebbe il modo migliore di persistente quel tipo di dati tra Postback, considerando i contesti di più schede sul browser, con il minor costo per il server e per la squadra di manutenzione di codifica ?

Aggiornamento:

Come @nunespascal ben postato, una possibilità potrebbe essere quella di memorizzare il ViewState nel Session utilizzando il SessionPageStatePersister. Ma sfortunatamente non è un'opzione per il mio caso. Eppure non è molto diverso dal mio ultimo esempio, salvando i dati sulla Sessione indicizzati da un UniqueId memorizzato su ViewState.

Ci sarebbero altre opzioni?

+0

Secondo approccio realizzabile con alcune modifiche: 1) utilizzare un campo nascosto anziché ViewState. Questo ti consente di accedervi prima che ViewState sia disponibile sulla pagina (utile a volte). 2) Wrap Session con un manager che limita il numero di elementi che possono essere memorizzati in una sola volta e lancia gli oggetti più vecchi. Naturalmente, questo non risolve completamente il problema di memoria, ma può andare un lungo cammino verso consentendo agli utenti di lavorare organicamente nella vostra applicazione senza preoccuparsi che un utente occupato avrà centinaia di oggetti di grandi dimensioni/set in memoria. –

risposta

2

C'è una soluzione semplice a questo problema.Memorizza ViewState nella sessione.

Per questo è necessario utilizzare il SessionPageStatePersister

consultare: Page State Persister

Tutto quello che dovete fare è ignorare la PageStatePersister e farlo utilizzare SessionPageStatePersister invece di quello predefinito HiddenFieldPageStatePersister

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

Questo ti risparmia anche il mal di testa di mantenere una chiave unica. Un campo nascosto verrà utilizzato automaticamente per mantenere una chiave univoca per istanza della pagina.

+0

Sì, lo risolverebbe sicuramente. Sfortunatamente non è un'opzione per il mio caso, ma grazie per la risposta rapida. –

+0

Se mi Store su ViewState, e memorizzare il ViewState sulla sessione, come vorrei che essere diverso dall'ultimo esempio ho postato? Voglio dire, non avrebbe impatto sulla memoria del server, o come sarebbe gestito se l'utente continua ad aggiornare la pagina e di conseguenza la memorizzazione di nuovi dati alla sessione ogni volta? –

+0

Sì, avrebbe un impatto sulla memoria del server. Ma questo è un costo che dovresti sopportare anche se hai archiviato i dati direttamente nella sessione. Per quanto riguarda gli aggiornamenti ripetuti, quelli occuperanno lo spazio delle sessioni. Ma se si affrontano tali problemi, con la sessione si ha sempre la possibilità di spostarli in un database. Alla fine le sessioni sarebbero state eliminate. – nunespascal

0

ho incontrato una situazione simile. L'idea è che se si consente lunghe sessioni per ogni utente per cambiare la visualizzazione a griglia, questo significa che avrete anche un problema di concorrenza perché alla fine si accetta una sola ultima serie di modifiche ai propri dati.

Quindi, la mia soluzione era, per consentire modifiche sul database, ma assicurarmi che tutti gli utenti vedessero lo stesso stato tramite SignalR.

Ora, il problema di concorrenza è scomparso, ma è comunque necessario apportare le modifiche al volo. Potresti non voler salvare le modifiche dopo tutto. Ho risolto questo problema applicando il modello di progettazione comando. Ora qualsiasi serie di modifiche può essere approvata o scartata. Ogni volta che controlli l'indice vedrai l'ultimo gridview approvato. Vai alla pagina di aggiornamento e vedi il gridview aggiornato dal vivo. Inoltre, vai alle revisioni per vedere il vecchio gridview approvato, oltre ad altri vantaggi del modello di progettazione dei comandi.