Le istanze di classe statiche sono uniche per una richiesta o un server in ASP.NET?


182

Su un sito Web ASP.NET, le classi statiche sono univoche per ogni richiesta Web o sono istanziate ogni volta che è necessario e vengono GCedite ogni volta che il GC decide di eliminarle?

Il motivo per cui lo chiedo è perché ho scritto alcune classi statiche in C # e il comportamento è diverso da quello che mi sarei aspettato. Mi sarei aspettato che le classi statiche fossero uniche per ogni richiesta, ma non sembra che sia così.

Se non sono univoci per ogni richiesta, c'è un modo per permetterli?

AGGIORNAMENTO:
La risposta che driis mi ha dato era esattamente ciò di cui avevo bisogno. Stavo già utilizzando una classe singleton, tuttavia utilizzava un'istanza statica e quindi veniva condivisa tra le richieste anche se gli utenti erano diversi, il che in questo caso era una cosa negativa. L'uso HttpContext.Current.Itemsrisolve perfettamente il mio problema. Per chiunque si imbatti in questa domanda in futuro, ecco la mia implementazione, semplificata e abbreviata in modo che sia facile capire il modello:

using System.Collections;
using System.Web;

public class GloballyAccessibleClass
{
    private GloballyAccessibleClass() { }

    public static GloballyAccessibleClass Instance
    {
        get
        {
            IDictionary items = HttpContext.Current.Items;
            if(!items.Contains("TheInstance"))
            {
                items["TheInstance"] = new GloballyAccessibleClass();
            }
            return items["TheInstance"] as GloballyAccessibleClass;
        }
    }
}

Solo un avvertimento: se reindirizzi la tua richiesta, ad esempio, filterContext.Result = new RedirectResult(...)perderai i tuoi articoli perché verrà creato un nuovo HttpContext. Maggiori dettagli qui: stackoverflow.com/questions/16697601/…
Reuel Ribeiro

Una domanda correlata con una buona risposta è su stackoverflow.com/q/5219431 .
Teofilo,

Risposte:


146

Le classi statiche e i campi dell'istanza statica sono condivisi tra tutte le richieste all'applicazione e hanno la stessa durata del dominio dell'applicazione. Pertanto, dovresti stare attento quando usi istanze statiche, poiché potresti avere problemi di sincronizzazione e simili. Inoltre, tenere presente che le istanze statiche non verranno GC prima che il pool di applicazioni venga riciclato e quindi tutto ciò a cui fa riferimento l'istanza statica non verrà GC. Ciò può causare problemi di utilizzo della memoria.

Se hai bisogno di un'istanza con la stessa durata di una richiesta, suggerirei di utilizzare la HttpContext.Current.Itemsraccolta. Questo è progettato per essere un posto dove riporre roba di cui hai bisogno durante la richiesta. Per una migliore progettazione e leggibilità, è possibile utilizzare il modello Singleton per aiutarti a gestire questi elementi. Basta creare una classe Singleton in cui è memorizzata la sua istanza HttpContext.Current.Items. (Nella mia libreria comune per ASP.NET, ho una classe SingletonRequest generica per questo scopo).


3
Potresti fornire un esempio del tuo modello Singleton che coinvolge HttpContext.Current.Items?
Airn5475,

Maggiori dettagli sulla mia situazione: nella mia app Web, l'utente eseguirà una libreria di classi di codice che utilizza una proprietà di classe condivisa. Voglio che questa proprietà sia specifica dell'utente, ma non voglio consegnare questa proprietà alle diverse funzioni. Il design che menzioni può gestirlo correttamente?
Airn5475,

Per favore, potresti condividere la classe SingletonRequest?
Tebo,

Non memorizzo alcun dato in classe statica. Uso la classe statica solo per ottenere dati o impostarli come livello dati. Quindi c'è qualche problema?
sgargiante

"static instances will not be GC'ed before the application pool is recycled, and therefore everything that is referenced by the static instance, will not be GC'ed"- C'è qualche fonte per questo, perché non ha alcun senso e è in conflitto con ciò che ho letto altrove. Quando l'appPool viene riciclato, il relativo dominio app viene completamente demolito e GC'd. Quando ciò accade, anche tutte le istanze statiche correlate saranno GC'd perché la loro radice (AppDomain) è sparita. Come parte del riciclo del pool, viene creato un nuovo AppDomain e vengono inizializzate le istanze statiche associate.
Nick,

30

I membri statici hanno solo una portata dell'attuale processo di lavoro, quindi non hanno nulla a che fare con le richieste, perché richieste diverse possono o meno essere gestite dallo stesso processo di lavoro.

  • Per condividere i dati con un utente specifico e tra le richieste, utilizzare HttpContext.Current.Session.
  • Per condividere i dati all'interno di una richiesta specifica, utilizzare HttpContext.Current.Items.
  • Per condividere i dati nell'intera applicazione, scrivere un meccanismo per quello oppure configurare IIS per lavorare con un singolo processo e scrivere un'applicazione singleton / use.

A proposito, il numero predefinito di processi di lavoro è 1, quindi questo è il motivo per cui il Web è pieno di persone che pensano che i membri statici abbiano un ambito dell'intera applicazione.


11

Poiché i tipi sono contenuti in un dominio di app, mi aspetto che le classi statiche siano presenti finché il dominio di app non viene riciclato o se la richiesta viene fornita da un dominio di app diverso.

Posso pensare a diversi modi per rendere gli oggetti specifici di una particolare richiesta dipende da cosa vuoi fare, ad esempio potresti istanziare l'oggetto in Application.BeginRequest e quindi memorizzarlo nell'oggetto HttpRequest in modo che sia accessibile a tutti gli oggetti in la pipeline di elaborazione della richiesta.


4

Se non sono univoci per ogni richiesta, c'è un modo per permetterli?

No. I membri statici sono di proprietà del processo ASP.NET e sono condivisi da tutti gli utenti dell'app Web. Dovrai passare ad altre tecniche di gestione della sessione come le variabili di sessione.


1

Metodi, proprietà e classi normalmente statici sono comuni a Application livello. Fino a quando l'applicazione rimane attiva, vengono condivise.

È possibile specificare un comportamento diverso utilizzando l' ThreadStaticattributo. In tal caso, saranno specifici per il thread corrente, che, credo, è specifico per ogni richiesta.
Non lo consiglierei però perché sembra troppo complicato.

È possibile utilizzare HttpContext.Current.Itemsper impostare elementi per una richiesta o HttpContext.Current.Sessionper impostare elementi per un utente (tra richieste).

In generale, tuttavia, a meno che non sia necessario utilizzare cose del genere Server.Transfer, il modo migliore è fondamentalmente creare cose una volta e poi passarle esplicitamente tramite l'invocazione del metodo.


3
Jon Skeet ci mostra che ThreadStatic non è mai sicuro in ASP.Net stackoverflow.com/questions/4791208/…
Mark Lindell,

Sottovalutato poiché una discussione non è unica per una richiesta. Per favore, rimuovi questa risposta
vedrai il
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.