¿Las instancias de clase estática son exclusivas de una solicitud o un servidor en ASP.NET?

182

En un sitio web ASP.NET, ¿las clases estáticas son exclusivas de cada solicitud web, o se crean instancias cuando es necesario y se GCed cuando el GC decide deshacerse de ellas?

La razón por la que pregunto es porque he escrito algunas clases estáticas antes en C # y el comportamiento es diferente de lo que esperaba. Hubiera esperado que las clases estáticas fueran únicas para cada solicitud, pero no parece que ese sea el caso.

Si no son exclusivos de cada solicitud, ¿hay alguna forma de permitir que lo sean?

ACTUALIZACIÓN:
La respuesta que me dieron driis fue exactamente lo que necesitaba. Ya estaba usando una clase singleton, sin embargo, estaba usando una instancia estática y, por lo tanto, se compartía entre solicitudes incluso si los usuarios eran diferentes, lo que en este caso era algo malo. El uso HttpContext.Current.Itemsresuelve mi problema perfectamente. Para cualquiera que se encuentre con esta pregunta en el futuro, aquí está mi implementación, simplificada y acortada para que sea fácil de entender el patrón:

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
fuente
Solo un aviso: si redirige su solicitud, por ejemplo, filterContext.Result = new RedirectResult(...)perderá sus artículos porque se creará un nuevo HttpContext. Más detalles aquí: stackoverflow.com/questions/16697601/…
Reuel Ribeiro
Una pregunta relacionada con una buena respuesta se encuentra en stackoverflow.com/q/5219431 .
Theophilus

Respuestas:

146

Sus clases estáticas y los campos de instancia estática se comparten entre todas las solicitudes a la aplicación y tienen el mismo tiempo de vida que el dominio de la aplicación. Por lo tanto, debe tener cuidado al usar instancias estáticas, ya que puede tener problemas de sincronización y similares. También tenga en cuenta que las instancias estáticas no serán GC 'antes de que el grupo de aplicaciones sea reciclado, y por lo tanto, todo lo que hace referencia la instancia estática no será GC'ed. Esto puede conducir a problemas de uso de memoria.

Si necesita una instancia con el mismo tiempo de vida que una solicitud, sugeriría usar la HttpContext.Current.Itemscolección. Esto es, por diseño, un lugar para almacenar cosas que necesita durante la solicitud. Para un mejor diseño y legibilidad, puede usar el patrón Singleton para ayudarlo a administrar estos elementos. Simplemente cree una clase Singleton que almacene su instancia en HttpContext.Current.Items. (En mi biblioteca común para ASP.NET, tengo una clase SingletonRequest genérica para este propósito).

driis
fuente
3
¿Podría proporcionar una muestra de su patrón Singleton involucrando HttpContext.Current.Items?
Airn5475
Más detalles sobre mi situación: en mi aplicación web, el usuario ejecutará una biblioteca de código de clase que usa una propiedad de clase compartida. Quiero que esta propiedad sea específica del usuario, pero no quiero tener que entregar esta propiedad a las diferentes funciones. ¿Puede el diseño que mencionas manejar esto correctamente?
Airn5475
Por favor, ¿podría compartir la clase SingletonRequest?
Tebo
No almaceno ningún dato en clase estática. Utilizo la clase estática solo para obtener datos o establecer datos como una capa de datos. Entonces, ¿hay algún problema?
llamativo
"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"- ¿Hay alguna fuente para esto, porque no tiene ningún sentido y entra en conflicto con lo que he leído en otras partes? Cuando el AppPool se recicla, el dominio de la aplicación relacionado se derriba por completo y GC'd. Cuando esto sucede, las instancias estáticas relacionadas también serán GC'd porque su raíz (el AppDomain) se ha ido. Como parte del grupo de reciclaje, se crea un nuevo AppDomain y se inicializan sus instancias estáticas asociadas.
Nick
30

Los miembros estáticos solo tienen un alcance del proceso de trabajo actual, por lo que no tiene nada que ver con las solicitudes, ya que diferentes solicitudes pueden o no ser manejadas por el mismo proceso de trabajo.

  • Para compartir datos con un usuario específico y entre solicitudes, use HttpContext.Current.Session.
  • Para compartir datos dentro de una solicitud específica, use HttpContext.Current.Items.
  • Para compartir datos en toda la aplicación, escriba un mecanismo para eso o configure IIS para que funcione con un solo proceso y escriba una aplicación singleton / use.

Por cierto, el número predeterminado de procesos de trabajo es 1, por eso la web está llena de personas que piensan que los miembros estáticos tienen un alcance de toda la aplicación.

Moshe Bixenshpaner
fuente
11

Dado que los tipos están contenidos en un dominio de aplicación, esperaría que las clases estáticas estén presentes siempre que el dominio de la aplicación no se recicle, o si la solicitud es atendida por un dominio de aplicación diferente.

Se me ocurren varias formas de hacer que los objetos específicos de una solicitud en particular dependan de lo que desee hacer, por ejemplo, podría crear una instancia del objeto en Application.BeginRequest y luego almacenarlo en el objeto HttpRequest para que todos los objetos puedan acceder a él. la tubería de procesamiento de solicitudes.

Sijin
fuente
4

Si no son exclusivos de cada solicitud, ¿hay alguna forma de permitir que lo sean?

No Los miembros estáticos son propiedad del proceso ASP.NET y todos los usuarios de la aplicación web los comparten . Deberá recurrir a otras técnicas de administración de sesión, como las variables de sesión.

rp.
fuente
1

Normalmente, los métodos estáticos, las propiedades y las clases son comunes en el Applicationnivel. Mientras viva la aplicación, se comparten.

Puede especificar un comportamiento diferente utilizando el ThreadStaticatributo En ese caso, serán específicos para el hilo actual, que, creo, es específico para cada solicitud.
Sin embargo, no recomendaría esto, ya que parece demasiado complicado.

Puede usarlo HttpContext.Current.Itemspara configurar cosas para una solicitud, o HttpContext.Current.Sessionpara configurar cosas para un usuario (a través de solicitudes).

Sin embargo, en general, a menos que tenga que usar cosas como Server.Transfer, la mejor manera es básicamente crear cosas una vez y luego pasarlas explícitamente mediante la invocación de métodos.

Sklivvz
fuente
3
Jon Skeet nos muestra que ThreadStatic nunca es seguro en ASP.Net stackoverflow.com/questions/4791208/…
Mark Lindell
Votado a la baja ya que un hilo no es exclusivo de una solicitud. Por favor, elimine esta respuesta
seebiscuit