2008-10-12 14 views
155

En un sitio web ASP.NET, ¿las clases estáticas son exclusivas de cada solicitud web, o se crean instancias siempre que sea necesario y GCed cada vez que el GC decide deshacerse de ellas?¿Las instancias de clases estáticas son únicas para una solicitud o un servidor en ASP.NET?

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 hubiera esperado. Hubiera esperado que las clases estáticas fueran únicas para cada solicitud, pero no parece que sea así.

Si no son exclusivas de cada solicitud, ¿hay alguna manera de permitir que lo estén?

ACTUALIZACIÓN:
El driis respuesta me dio fue exactamente lo que necesitaba. Ya estaba usando una clase singleton, sin embargo, estaba usando una instancia estática y, por lo tanto, estaba siendo compartida entre las solicitudes, incluso si los usuarios eran diferentes, lo que en este caso era algo malo. Usar HttpContext.Current.Items resuelve mi problema perfectamente. Para cualquier persona que se topa con esta pregunta en el futuro, aquí está mi aplicación, simplificado y abreviado 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; 
     } 
    } 
} 
+0

Solo un aviso: si redirigir su solicitud, digamos, con 'filterContext.Result = new RedirectResult (...)' perderá sus elementos porque se creará un nuevo HttpContext. Más detalles aquí: https://stackoverflow.com/questions/16697601/response-redirect-does-not-preserve-httpcontext-current-items –

Respuesta

119

Las clases estáticas y los campos de instancia estáticos se comparten entre todas las solicitudes a la aplicación y tienen la misma duración 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. Tenga en cuenta también que las instancias estáticas no se someterán a GC antes de que se reutilice el grupo de aplicaciones, y por lo tanto, todo lo que se haga referencia a la instancia estática no se someterá a GC. Esto puede conducir a problemas de uso de memoria.

Si necesita una instancia con la misma duración que una solicitud, le sugiero que utilice la colección HttpContext.Current.Items. Esto es por diseño destinado a ser un lugar para almacenar cosas que necesita a lo largo de 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 genérica SingletonRequest para este propósito).

+2

¿Podría proporcionar una muestra de su patrón de Singleton que implica 'HttpContext.Current.Items'? – Airn5475

+0

Más detalles sobre mi situación: en mi aplicación web, el usuario ejecutará una biblioteca de clase de código que usa una propiedad de clase compartida. Quiero que esta propiedad sea específica del usuario, pero no quiero tener que pasar esta propiedad a las diferentes funciones. ¿Puede el diseño que mencionas manejar esto correctamente? – Airn5475

+0

¿Podría compartir la clase SingletonRequest? – Tebo

11

Dado que los tipos están contenidos en un dominio de aplicación, esperaría clases estáticas estar presente siempre que el dominio de la aplicación no se recicle, o si la solicitud recibe servicio de un dominio de aplicación diferente.

Creo que hay varias maneras de hacer que los objetos específicos para una solicitud en particular dependan de lo que quieras hacer, por ej. puede crear una instancia del objeto en Application.BeginRequest y luego almacenarlo en el objeto HttpRequest para que todos los objetos de la canalización de procesamiento de solicitud puedan acceder a él.

4

Si no son exclusivas de cada solicitud, ¿hay alguna manera de permitir que estén?

Nope. Los miembros estáticos son propiedad del proceso ASP.NET y se comparten con todos los usuarios de la aplicación web. Tendrá que recurrir a otras técnicas de gestión de sesión, como las variables de sesión.

0

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

Puede especificar un comportamiento diferente utilizando el atributo ThreadStatic. En ese caso, serán específicos del hilo actual, que creo que es específico para cada solicitud.
No lo aconsejaría, ya que parece demasiado complicado.

Puede usar HttpContext.Current.Items para configurar cosas para una solicitud, o HttpContext.Current.Session para configurar cosas para un usuario (a través de las solicitudes).

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 a través de la invocación del método.

+3

Jon Skeet nos muestra que ThreadStatic nunca es seguro en ASP.Net http://stackoverflow.com/questions/4791208/threadstaticattribute-in-asp-net –

+1

ThreadStatic no es seguro y no es único por solicitud –

+0

Vota abajo ya que el hilo no es exclusivo de una solicitud. Por favor, elimine esta respuesta – seebiscuit

16

Los miembros estáticos tienen un alcance del proceso de trabajo actual solamente, 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 trabaje 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 gente pensando que los miembros estáticos tienen un alcance de toda la aplicación.

Cuestiones relacionadas