Domanda

Voglio memorizzare lo stato "quot" " di alcune azioni che l'utente sta eseguendo in una serie di diversi moduli Web ASP.Net. Quali sono le mie scelte per lo stato persistente e quali sono i pro / contro di ogni soluzione?

Ho usato oggetti Session e ho usato alcuni metodi di supporto per digitare fortemente gli oggetti:

    public static Account GetCurrentAccount(HttpSessionState session)
    {
        return (Account)session[ACCOUNT];
    }

    public static void SetCurrentAccount(Account obj, HttpSessionState session)
    {
        session[ACCOUNT] = obj;
    }

Mi è stato detto da numerose fonti che "Session is evil", quindi questa è davvero la causa principale di questa domanda. Voglio sapere cosa ne pensi "best practice", e perché.

È stato utile?

Soluzione

Non c'è nulla di intrinsecamente malvagio con lo stato della sessione.

Ci sono un paio di cose da tenere a mente che potrebbero morderti:

  1. Se l'utente preme il pulsante Indietro del browser, si torna alla pagina precedente ma lo stato della sessione non viene ripristinato. Quindi il tuo CurrentAccount potrebbe non essere quello che era originariamente sulla pagina.
  2. I processi ASP.NET possono essere riciclati da IIS. Quando ciò accade, la tua prossima richiesta inizierà un nuovo processo. Se si sta utilizzando lo stato della sessione del processo, il valore predefinito sarà sparito :-(
  3. La sessione può anche scadere con lo stesso risultato se l'utente non è attivo da un po 'di tempo. L'impostazione predefinita è 20 minuti, quindi un buon pranzo lo farà.
  4. L'uso dello stato sessione fuori processo richiede che tutti gli oggetti memorizzati nello stato sessione siano serializzabili.
  5. Se l'utente apre una seconda finestra del browser, si aspetterà di avere una seconda e distinta applicazione, ma molto probabilmente lo stato della sessione sarà condiviso tra due. Quindi la modifica del CurrentAccount in una finestra del browser farà lo stesso nell'altra.

Altri suggerimenti

Le tue due scelte per l'archiviazione temporanea dei dati del modulo sono, in primo luogo, di memorizzare le informazioni di ciascun modulo nelle variabili dello stato della sessione e, in secondo luogo, di passare le informazioni del modulo utilizzando i parametri URL. L'uso dei cookie come potenziale terza opzione non è semplicemente realizzabile per il semplice motivo che è probabile che molti dei tuoi visitatori abbiano i cookie disattivati ??(ciò non influisce sui cookie di sessione, tuttavia). Inoltre, presumo per la natura della tua domanda che non desideri archiviare queste informazioni in una tabella del database fino a quando non saranno completamente impegnate.

L'uso delle variabili di sessione è la soluzione classica a questo problema, ma presenta alcuni inconvenienti. Tra questi ci sono (1) grandi quantità di dati che possono utilizzare la RAM del server se si utilizza la gestione delle sessioni inproc, (2) la condivisione delle variabili di sessione su più server in una server farm richiede ulteriori considerazioni e (3) un'app progettata in modo professionale deve evitare la scadenza della sessione (non solo lanciare una variabile di sessione e utilizzarla - se la sessione è scaduta, il cast genererà un errore). Tuttavia, per la stragrande maggioranza delle applicazioni, le variabili di sessione sono senza dubbio la strada da percorrere.

L'alternativa è passare le informazioni di ciascun modulo nell'URL. Il problema principale con questo approccio è che dovrai stare molto attento a "passare" a " informazione. Ad esempio, se si raccolgono informazioni in quattro pagine, è necessario raccogliere informazioni nella prima, passarle nell'URL alla seconda pagina in cui è necessario memorizzarle nel viewstate di quella pagina. Quindi, quando chiami la terza pagina, raccoglierai i dati del modulo dalla seconda pagina più le variabili viewstate e codificherai entrambi nell'URL, ecc. Se hai cinque o più pagine o se il visitatore salterà sul sito, tu Avrai un vero casino tra le mani. Ricorda inoltre che tutte le informazioni dovranno essere A) essere serializzate su una stringa URL-safe e B) codificate in modo tale da prevenire semplici hack basati su URL (ad es. Se metti il ??prezzo in chiaro e lo passi insieme, qualcuno potrebbe cambiare il prezzo). Tieni presente che puoi ridurre alcuni di questi problemi creando una sorta di "gestore di sessioni" e far sì che gestisca le stringhe URL per te, ma dovresti comunque essere estremamente sensibile alla possibilità che un determinato link possa spazzare via l'intera sessione di qualcuno se non è gestita correttamente.

Alla fine, utilizzo le variabili URL solo per passare dati molto limitati da una pagina all'altra (ad es. l'ID di un articolo codificato in un collegamento a quell'elemento).

Supponiamo, quindi, che gestiresti davvero i dati di un utente utilizzando la funzionalità Sessioni integrata. Perché qualcuno dovrebbe dirti che " Session is evil " ;? Bene, oltre al carico di memoria, alla server-farm e alle considerazioni sulla scadenza presentate sopra, la critica principale delle variabili Session è che sono, in effetti, variabili non tipizzate.

Fortunatamente, l'uso prudente delle variabili di sessione può evitare problemi di memoria (gli elementi di grandi dimensioni devono essere comunque conservati nel database) e se si esegue un sito abbastanza grande da richiedere una server farm, ci sono molti meccanismi disponibili per la condivisione dello stato costruito in ASP.NET (suggerimento: non utilizzerai l'archiviazione inproc).

Per evitare sostanzialmente tutti gli altri svantaggi di Session, raccomando di implementare un oggetto per conservare i dati della sessione e alcune semplici funzionalità di gestione degli oggetti Session. Quindi incorporali in un discendente della classe Page e usa questa classe discendente per tutte le tue pagine. È quindi semplice accedere ai dati della sessione tramite la classe di pagina come un insieme di valori fortemente tipizzati. Tieni presente che i campi del tuo oggetto ti daranno un modo per accedere a ciascuna delle tue variabili "session" " in modo fortemente tipizzato (ad esempio un campo per variabile).

Fammi sapere se questo è un compito semplice per te o se desideri un codice di esempio!

Per quanto ne so, Session è il modo previsto per conservare queste informazioni. Tieni presente che lo stato della sessione è generalmente memorizzato nel processo per impostazione predefinita. Se si dispone di più server Web o in caso di riavvio di IIS, si perde lo stato della sessione. Questo può essere risolto usando un servizio di stato ASP.NET o anche un database SQL per memorizzare le sessioni. Ciò garantisce che le persone riprendano la sessione, anche se vengono reindirizzate su un altro server Web o in caso di riciclo del processo di lavoro.

Uno dei motivi della sua sinistra reputazione è che gli sviluppatori affrettati lo abusano di letterali stringa nel codice dell'interfaccia utente (anziché di una classe di supporto come la tua) come chiavi dell'oggetto e finiscono con una grande borsa di stato promiscuo non verificabile. Una sorta di wrapper è un requisito entry-level per l'uso di sessioni non malvagie.

Per quanto riguarda " La sessione è cattiva " ... se stavi sviluppando in ASP classico dovrei essere d'accordo, ma ASP.NET/IIS fa un lavoro molto migliore.

La vera domanda è qual è il modo migliore per mantenere lo stato. Nel nostro caso, quando si tratta dell'utente attualmente connesso, memorizziamo quell'oggetto in Sessione, poiché costantemente ci riferiamo ad esso per nome, indirizzo e-mail, autorizzazione e così via.

Altre piccole notizie di informazioni che non necessitano di persistenza a lungo termine, usiamo una combinazione di cookie e viewstate.

Quando si desidera archiviare informazioni a cui è possibile accedere a livello globale nella propria applicazione Web, un modo per farlo è l'attributo ThreadStatic . Ciò trasforma un membro statico di un Class in un membro condiviso dal thread corrente, ma non da altri thread. Il vantaggio di ThreadStatic è che non è necessario disporre di un contesto Web. Ad esempio, se si dispone di un back-end che non fa riferimento a System.Web , ma si desidera condividere anche lì informazioni, è possibile impostare id dell'utente all'inizio di ogni richiesta nella proprietà ThreadStatic e fai riferimento nella tua dipendenza senza la necessità di avere accesso all'oggetto Session .

Poiché è statico ma solo per un singolo thread, assicuriamo che altri visitatori simultanei non ottengano la nostra sessione. Funziona, purché tu assicuri che la proprietà sia ripristinata per ogni richiesta. Questo lo rende un compagno ideale per i cookie.

Penso che usare l'oggetto Session sia OK in questo caso, ma dovresti ricordare che Session può scadere se non c'è attività del browser per lungo tempo ( HttpSessionState.Timeout determina in quanti minuti il ??provider di stato sessione termina la sessione), quindi è meglio controllare il valore esistenza prima del ritorno:

public static Account GetCurrentAccount(HttpSessionState session)
{
    if (Session[ACCOUNT]!=null)
        return (Account)Session[ACCOUNT];
    else
        throw new Exception("Can't get current account. Session expired.");
}

Le informazioni a breve termine, che devono vivere solo fino alla prossima richiesta, possono anche essere archiviate nel ViewState . Ciò significa che gli oggetti vengono serializzati e archiviati nella pagina inviata al browser, che viene quindi postata sul server su un evento clic o simile. Quindi il ViewState viene decodificato e trasformato di nuovo in oggetti, pronto per essere recuperato.

Le sessioni non sono malvagie, svolgono un'importante funzione nell'applicazione ASP.NET, fornendo dati che devono essere condivisi tra più pagine durante la "sessione" di un utente. Ci sono alcuni suggerimenti, direi di usare la gestione delle sessioni SQL quando possibile, e accertarmi che gli oggetti che stai usando nella tua raccolta di sessioni siano "serializzabili". Le migliori pratiche sarebbero utilizzare l'oggetto sessione quando è assolutamente necessario condividere le informazioni sullo stato tra le pagine e non utilizzarlo quando non è necessario. Le informazioni non saranno disponibili sul lato client, una chiave di sessione viene conservata in un cookie o tramite la stringa di query o utilizzando altri metodi a seconda di come è configurata, quindi gli oggetti sessione sono disponibili nella tabella del database ( a meno che tu non usi InProc, nel qual caso le tue sessioni avranno la possibilità di essere spazzate via durante una ricarica del sito, o saranno rese quasi inutili nella maggior parte degli ambienti cluster).

Penso che il "male" sia deriva dall'uso eccessivo della sessione. Se si inserisce qualcosa e tutto (come usare variabili globali per tutto), si finirà per avere scarse prestazioni e solo un casino.

Tutto ciò che si inserisce nell'oggetto sessione rimane lì per la durata della sessione, a meno che non venga ripulito. Una cattiva gestione della memoria archiviata utilizzando inproc e Stateserver ti costringerà a ridimensionare prima del necessario. Memorizzare solo un ID per la sessione / utente nella sessione e caricare ciò che è necessario nell'oggetto cache su richiesta utilizzando una classe di supporto. In questo modo è possibile ottimizzare la durata in base alla frequenza con cui tali dati sono stati utilizzati. La prossima versione di asp.net potrebbe avere una cache distribuita (rumor).

Sessione come male: non in ASP.NET, correttamente configurato. Sì, è l'ideale per essere il più apolidi possibile, ma la realtà è che non puoi arrivarci da qui. Tuttavia, puoi fare in modo che Session si comporti in modo da ridurne l'impatto, in particolare StateServer o sessioni di database.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top