Les instances de classe statique sont-elles uniques à une demande ou à un serveur dans ASP.NET?

182

Sur un site Web ASP.NET, les classes statiques sont-elles uniques à chaque requête Web, ou sont-elles instanciées chaque fois que nécessaire et GC chaque fois que le GC décide de les éliminer?

La raison pour laquelle je pose la question est que j'ai déjà écrit des classes statiques en C # et que le comportement est différent de ce à quoi je m'attendais. Je me serais attendu à ce que les classes statiques soient uniques à chaque requête, mais il ne semble pas que ce soit le cas.

S'ils ne sont pas uniques à chaque demande, y a-t-il un moyen de les autoriser?

MISE À JOUR:
La réponse que driis m'a donnée était exactement ce dont j'avais besoin. J'utilisais déjà une classe singleton, mais elle utilisait une instance statique et était donc partagée entre les demandes même si les utilisateurs étaient différents, ce qui dans ce cas était une mauvaise chose. L'utilisation HttpContext.Current.Itemsrésout parfaitement mon problème. Pour tous ceux qui tombent sur cette question à l'avenir, voici mon implémentation, simplifiée et raccourcie pour qu'il soit facile de comprendre le modèle:

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;
        }
    }
}
Dan Herbert
la source
Juste un avertissement: si vous redirigez votre demande, par exemple, avec filterContext.Result = new RedirectResult(...)vous perdrez vos éléments car un nouveau HttpContext sera créé. Plus de détails ici: stackoverflow.com/questions/16697601/…
Reuel Ribeiro
Une question connexe avec une bonne réponse se trouve sur stackoverflow.com/q/5219431 .
Theophilus

Réponses:

146

Vos classes statiques et vos champs d'instance statiques sont partagés entre toutes les demandes adressées à l'application et ont la même durée de vie que le domaine d'application. Par conséquent, vous devez être prudent lorsque vous utilisez des instances statiques, car vous pourriez avoir des problèmes de synchronisation, etc. Gardez également à l'esprit que les instances statiques ne seront pas GC avant que le pool d'applications ne soit recyclé, et par conséquent, tout ce qui est référencé par l'instance statique ne sera pas GC. Cela peut entraîner des problèmes d'utilisation de la mémoire.

Si vous avez besoin d'une instance avec la même durée de vie qu'une requête, je vous suggère d'utiliser la HttpContext.Current.Itemscollection. C'est par conception censé être un endroit pour stocker les choses dont vous avez besoin tout au long de la demande. Pour une meilleure conception et une meilleure lisibilité, vous pouvez utiliser le modèle Singleton pour vous aider à gérer ces éléments. Créez simplement une classe Singleton qui stocke son instance dans HttpContext.Current.Items. (Dans ma bibliothèque commune pour ASP.NET, j'ai une classe SingletonRequest générique à cet effet).

driis
la source
3
Pourriez-vous fournir un échantillon de votre modèle Singleton impliquant HttpContext.Current.Items?
Airn5475
Plus de détails sur ma situation: dans mon application Web, l'utilisateur exécutera une bibliothèque de classes de code qui utilise une propriété de classe partagée. Je veux que cette propriété soit spécifique à l'utilisateur, mais je ne veux pas avoir à remettre cette propriété aux différentes fonctions. Le design que vous mentionnez peut-il gérer cela correctement?
Airn5475
S'il vous plaît, pourriez-vous partager la classe SingletonRequest?
Tebo
Je ne stocke aucune donnée en classe statique. J'utilise la classe statique uniquement pour obtenir des données ou définir des données en tant que couche de données. Alors y a-t-il un problème?
criard
"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"- Y a-t-il une source pour cela, car cela n'a aucun sens et entre en conflit avec ce que j'ai lu ailleurs. Lorsque l'AppPool est recyclé, le domaine d'application associé est complètement démoli et GC. Lorsque cela se produit, toutes les instances statiques associées seront également GC car leur racine (AppDomain) a disparu. Dans le cadre du recyclage du pool, un nouvel AppDomain est créé et ses instances statiques associées sont initialisées.
Nick
30

Les membres statiques ont une étendue du processus de travail actuel uniquement, donc cela n'a rien à voir avec les demandes, car différentes demandes peuvent ou non être traitées par le même processus de travail.

  • Afin de partager des données avec un utilisateur spécifique et entre les demandes, utilisez HttpContext.Current.Session.
  • Afin de partager des données dans une demande spécifique, utilisez HttpContext.Current.Items.
  • Afin de partager des données sur l'ensemble de l'application, écrivez un mécanisme pour cela ou configurez IIS pour qu'il fonctionne avec un seul processus et écrivez une application singleton / use.

À propos, le nombre par défaut de processus de travail est de 1, c'est pourquoi le Web regorge de gens qui pensent que les membres statiques ont une portée de l'application entière.

Moshe Bixenshpaner
la source
11

Étant donné que les types sont contenus dans un domaine d'application, je m'attendrais à ce que des classes statiques soient présentes tant que le domaine d'application n'est pas recyclé ou si la demande est servie par un domaine d'application différent.

Je peux penser à plusieurs façons de rendre des objets spécifiques à une demande particulière en fonction de ce que vous voulez faire, par exemple, vous pouvez instancier l'objet dans Application.BeginRequest, puis le stocker dans l'objet HttpRequest afin qu'il soit accessible par tous les objets de le pipeline de traitement des demandes.

Sijin
la source
4

S'ils ne sont pas uniques à chaque demande, y a-t-il un moyen de les autoriser?

Nan. Les membres statiques appartiennent au processus ASP.NET et sont partagés par tous les utilisateurs de l'application Web. Vous devrez vous tourner vers d'autres techniques de gestion de session telles que les variables de session.

rp.
la source
1

Normalement, les méthodes, propriétés et classes statiques sont courantes au Applicationniveau. Tant que l'application existe, elles sont partagées.

Vous pouvez spécifier un comportement différent à l'aide de l' ThreadStaticattribut. Dans ce cas, ils seront spécifiques au fil actuel, qui, je pense, est spécifique à chaque demande.
Je ne conseillerais pas cela car cela semble trop compliqué.

Vous pouvez utiliser HttpContext.Current.Itemspour configurer des éléments pour une demande ou HttpContext.Current.Sessionpour configurer des éléments pour un utilisateur (sur plusieurs demandes).

En général cependant, à moins que vous n'ayez à utiliser des choses comme Server.Transfer, le meilleur moyen consiste essentiellement à créer des choses une fois, puis à les passer explicitement via l'invocation de méthode.

Sklivvz
la source
3
Jon Skeet nous montre que ThreadStatic n'est jamais en sécurité dans ASP.Net stackoverflow.com/questions/4791208/…
Mark Lindell
Vote à la baisse car un fil de discussion n'est pas unique à une demande. Veuillez supprimer cette réponse
seebiscuit