Stato dell'applicazione

È possibile condividere le informazioni in tutta l'applicazione utilizzando la classe HttpApplicationState, a cui si accede in genere mediante la proprietà Application dell'oggetto HttpContext. Tale classe espone un dizionario di coppie chiave-valore che possono essere utilizzate per archiviare sia gli oggetti .NET Framework che i valori scalari relativi alle varie richieste Web di più client.

In questo argomento viene descritto lo stato dell'applicazione, il relativo utilizzo, gli insiemi e la sincronizzazione che lo caratterizzano.

Cenni preliminari sullo stato dell'applicazione

Un'applicazione ASP.NET è l'insieme di tutti i file, le pagine, i gestori, i moduli e il codice che risiedono in una specifica directory virtuale e nelle relative sottodirectory e che gli utenti possono richiedere tramite la gerarchia di tale directory.

Se ad esempio si sviluppa un'applicazione che consente di calcolare il rendimento degli investimenti per la rete Intranet aziendale, è possibile pubblicarla in una directory virtuale denominata \Invest su un server Web. La struttura della directory per tale applicazione può essere simile alla seguente:

\Invest

   \bin

   \image

   \xml

La prima volta che un client richiede una risorsa URL dallo spazio dei nomi della directory virtuale di una specifica applicazione ASP.NET, viene creata un'istanza della classe HttpApplicationState. Questa situazione si verifica per ogni applicazione Web archiviata nel computer. L'accesso a questa istanza basata su una singola applicazione è fornito da una proprietà HttpContext denominata Application. Tutti gli HttpModules e gli HttpHandlers, quali le pagine ASP.NET, hanno accesso a un'istanza del contesto e possono pertanto accedere alla proprietà Application durante una data richiesta Web.

In ASP.NET è disponibile il seguente supporto dello stato dell'applicazione:

  • Una funzionalità di stato di facile utilizzo compatibile con le versioni precedenti di ASP, in grado di funzionare con tutti i linguaggi .NET supportati e coerente con le altre API di .NET Framework.
  • Un dizionario dello stato dell'applicazione disponibile per tutti i gestori delle richieste richiamati all'interno di un'applicazione. A differenza di IIS (Internet Information Services) e delle versioni precedenti di ASP, in cui solo le pagine possono accedere allo stato dell'applicazione, tutte le istanze IHttpHandler e IHttpModule possono archiviare e recuperare le variabili globali all'interno del dizionario.
  • Un meccanismo di sincronizzazione semplice e intuitivo che consente agli sviluppatori di coordinare con facilità l'accesso simultaneo alle variabili archiviate nello stato dell'applicazione.
  • Valori relativi allo stato dell'applicazione accessibili solo dal codice eseguito nel contesto dell'applicazione di origine. Ad altre applicazioni in esecuzione sul sistema non è consentito di accedere ai valori o modificarli.

Il modo più diffuso di accedere allo stato dell'applicazione è tramite la proprietà Application dell'oggetto Page.

Utilizzo dello stato dell'applicazione

Le variabili relative allo stato dell'applicazione sono in effetti variabili globali per una specifica applicazione ASP.NET. Analogamente agli sviluppatori delle applicazioni del lato client, i programmatori ASP.NET devono sempre tenere conto dell'impatto provocato dall'archiviazione degli oggetti come variabile globale.

In questo contesto sono particolarmente importanti i seguenti problemi:

  • L'impatto sulla memoria generato dall'archiviazione nello stato dell'applicazione. La memoria occupata dalle variabili archiviate nello stato dell'applicazione non viene liberata fino a quando il valore non viene rimosso o sostituito, a differenza di un pagina Web singola in cui tutte le risorse vengono eliminate al termine di una richiesta Web. Conservando, ad esempio, in modo permanente nello stato dell'applicazione set di record da 10 MB utilizzati raramente, le risorse di sistema non vengono utilizzate in modo ottimale. In questo caso estremo è possibile individuare soluzioni migliori utilizzando la cache di ASP.NET.
  • Le implicazioni in termini di simultaneità e sincronizzazione determinate dall'archiviazione e dall'accesso a una variabile globale in un ambiente server con multithreading. Più thread presenti in un'applicazione possono accedere contemporaneamente ai valori archiviati nello stato dell'applicazione. Assicurarsi sempre che gli oggetti con ambito di applicazione e un modello di threading Free contengano un supporto di sincronizzazione incorporato. Tutti gli oggetti personalizzati destinati al Common Language Runtime dispongono di un modello di threading Free. Se un oggetto con ambito di applicazione non dispone di un modello di threading Free, è necessario assicurarsi che i metodi di sincronizzazione espliciti vengano codificati in base ad esso per evitare blocchi critici, condizioni di competizione e violazioni di accesso.
  • Le implicazioni in termini di scalabilità determinate dall'archiviazione e dall'accesso a una variabile globale in un ambiente server con multithreading. I blocchi dovrebbero essere utilizzati tutte le volte che si tenta di scrivere o aggiornare un file. I blocchi che proteggono le risorse globali sono anch'essi globali e il codice in esecuzione su più thread che accedono alle risorse globali finisce per contendersi questi blocchi. Per questo motivo nel sistema operativo i thread di lavoro vengono bloccati fino a quando il blocco non risulta disponibile. In ambienti server con carico elevato questo blocco può provocare un notevole sovraccarico del thread sul sistema. Nei sistemi a più processori può condurre a un sottoutilizzo del processore (in quanto tutti i thread di un processore possono essere bloccati in attesa di un blocco condiviso) e a una riduzione significativa della scalabilità complessiva.
  • Le implicazioni in termini di durata per le informazioni archiviate nello stato dell'applicazione. Il dominio dell'applicazione .NET Framework o il processo contenente un'applicazione basata su .NET può essere eliminato e distrutto in qualsiasi momento durante l'esecuzione dell'applicazione, in seguito a blocchi del sistema, aggiornamenti del codice, riavvii dei processi pianificati e così via. Poiché i dati archiviati nello stato dell'applicazione non sono permanenti, essi andranno persi se l'host in cui sono contenuti viene distrutto. Per consentire allo stato di superare questo tipo di errori, è consigliabile archiviarlo in un database o in un altro archivio permanente.
  • Lo stato dell'applicazione non viene condiviso su un Web farm, in cui un'applicazione è contenuta su più server, o un Web garden, in cui un'applicazione è contenuta in più processi sullo stesso server. Le variabili archiviate nello stato dell'applicazione in uno di questi scenari sono globali solo rispetto a questo particolare processo in cui viene eseguita l'applicazione. Ogni processo applicativo può contenere valori differenti. Non è possibile quindi utilizzare lo stato dell'applicazione per archiviare valori univoci o aggiornare contatori globali, ad esempio, in scenari Web farm e Web garden.

Nonostante tali problemi, le variabili a livello di applicazione progettate correttamente possono essere molto efficaci nelle applicazioni Web. È possibile eseguire il caricamento e il calcolo delle informazioni un'unica volta o in modo saltuario e quindi utilizzare lo stato dell'applicazione per eseguirne l'archiviazione nella cache e consentire un accesso rapido alla memoria durante le richieste Web successive.

Il sito Web di un mercato azionario, ad esempio, può recuperare informazioni complete sul mercato finanziario (nell'ordine di 40 MB di dati) da un database ogni 5 minuti durante la giornata e archiviarle nella cache dello stato dell'applicazione per consentire a tutte le richieste di ricerca successive di accedervi. Il risultato è un notevole miglioramento delle prestazioni per ciascuna richiesta, in quanto le richieste in arrivo non necessitano di percorsi di andata e ritorno tra processi, computer e database. D'altra parte, l'utilizzo della cache consente di sfruttare in modo migliore le risorse per i grossi blocchi di dati temporanei.

Insiemi dello stato dell'applicazione

La classe HttpApplicationState espone due insiemi di stato: Contents e StaticObjects.

L'insieme Contents espone tutti gli elementi delle variabili che sono stati aggiunti all'insieme dello stato dell'applicazione direttamente tramite codice. Esempio:

'  Visual Basic code from within a page, a handler, or Global.asax.
Application("Message") = "MyMsg"
Application("AppStartTime") = Now
[C#]
// C# code from within a page, a handler, or Global.asax.
Application["Message"] = " MyMsg";
Application["AppStartTime"] = DateTime.Now;

Per compatibilità con le versioni precedenti di ASP, è anche possibile accedere a queste variabili utilizzando la proprietà Contents dell'oggetto applicazione, come mostrato nell'esempio che segue.

' Visual Basic code from within a page, a handler, or Global.asax.
Application.Contents("Message") = " MyMsg"
Application.Contents("AppStartTime") = Now
[C#]
// Visual Basic code from within a page, a handler, or Global.asax.
Application.Contents["Message"] = " MyMsg";
Application.Contents["AppStartTime"] = DateTime.Now;

L'insieme StaticObjects espone tutti gli elementi delle variabili che sono stati aggiunti all'insieme dello stato dell'applicazione tramite i tag <object runat="server"> del file Global.asax con ambito di applicazione. Esempio:

' Global.asax definition.
<object runat="server" scope="application" ID="MyInfo" PROGID="MSWC.MYINFO">
</OBJECT>

Gli oggetti non possono essere aggiunti all'insieme StaticObjects da un punto qualsiasi di un'applicazione ASP.NET. Se si cerca di aggiungere oggetti direttamente tramite codice, l'insieme genera un'eccezione NotSupportedException.

Si noti che il compilatore di pagine .NET inserisce automaticamente i riferimenti ai membri in tutti gli oggetti archiviati nell'insieme StaticObjects durante la fase di compilazione delle pagine, in modo che gli sviluppatori possano accedere a questi oggetti dell'applicazione durante la fase di richiesta delle pagine senza fare riferimento all'insieme Application. Esempio:

<html>
   </body>
      Application Level Title: <%= MyInfo.Title %>
   <body>
</html>

Sincronizzazione dello stato dell'applicazione

Più thread all'interno di un'applicazione possono accedere contemporaneamente ai valori archiviati nello stato dell'applicazione. Di conseguenza, quando si crea un elemento che deve accedere ai valori dello stato dell'applicazione, assicurarsi sempre che l'oggetto stato dell'applicazione disponga di un modello di threading Free ed esegua la sincronizzazione interna oppure che vengano eseguiti i passaggi di sincronizzazione manuale come protezione dalle condizioni di competizione, dai blocchi critici e dalle violazioni di accesso.

Nella classe HttpApplicationState sono disponibili due metodi, Lock e Unlock, che consentono l'accesso alle variabili dello stato dell'applicazione a un solo thread alla volta.

La chiamata del metodo Lock sull'oggetto Application può provocare il blocco da parte di ASP.NET dei tentativi di accesso allo stato dell'applicazione da parte del codice in esecuzione su altri thread di lavoro. Tali thread vengono sbloccati solo quando il thread denominato Lock chiama il corrispondente metodo Unlock sull'oggetto Application.

Nell'esempio che segue viene descritto come utilizzare il blocco per evitare condizioni di competizione.

' Visual Basic code from within a page, a handler, or Global.asax.
Application.Lock()
Application("SomeGlobalCounter") = _
   CType(Application("SomeGlobalCounter"), Integer) + 1
Application.UnLock()
[C#]
// C# code from within a page, a handler, or Global.asax.
Application.Lock();
Application["SomeGlobalCounter"] =
   (int)Application["SomeGlobalCounter"] + 1;
Application.UnLock();

Se non si chiama il metodo Unlock in maniera esplicita, .NET Framework rimuove automaticamente il blocco quando la richiesta viene completata, quando si verifica il timeout della richiesta o quando si verifica un errore non gestito durante l'esecuzione della richiesta che quindi non viene soddisfatta. Questo sblocco automatico consente di evitare il blocco critico dell'applicazione.

Vedere anche

Gestione dello stato di ASP.NET | Applicazioni ASP.NET