As instâncias de classe estática são exclusivas para uma solicitação ou um servidor no ASP.NET?

182

Em um site ASP.NET, as classes estáticas são exclusivas para cada solicitação da Web ou são instanciadas sempre que necessário e submetidas ao GC sempre que o GC decide descartá-las?

A razão pela qual pergunto é porque escrevi algumas classes estáticas antes em C # e o comportamento é diferente do que eu esperava. Eu esperava que as classes estáticas fossem exclusivas para cada solicitação, mas não parece ser esse o caso.

Se eles não são exclusivos para cada solicitação, existe uma maneira de permitir que eles sejam?

ATUALIZAÇÃO:
A resposta que driis me deu foi exatamente o que eu precisava. Eu já estava usando uma classe singleton, no entanto, estava usando uma instância estática e, portanto, estava sendo compartilhada entre solicitações, mesmo que os usuários fossem diferentes, o que, nesse caso, era uma coisa ruim. Usar HttpContext.Current.Itemsresolve meu problema perfeitamente. Para quem se deparar com essa questão no futuro, aqui está minha implementação, simplificada e abreviada para facilitar a compreensão do padrão:

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
fonte
Apenas um alerta: se você redirecionar sua solicitação, por exemplo, filterContext.Result = new RedirectResult(...)você perderá seus itens porque um novo HttpContext será criado. Mais detalhes aqui: stackoverflow.com/questions/16697601/…
Reuel Ribeiro
Uma pergunta relacionada com uma boa resposta está em stackoverflow.com/q/5219431 .
Theophilus

Respostas:

146

Suas classes estáticas e campos de instância estática são compartilhados entre todas as solicitações ao aplicativo e têm a mesma vida útil do domínio do aplicativo. Portanto, você deve ter cuidado ao usar instâncias estáticas, pois você pode ter problemas de sincronização e similares. Lembre-se também de que instâncias estáticas não serão submetidas ao GC antes que o pool de aplicativos seja reciclado e, portanto, tudo o que for referenciado pela instância estática não será submetido ao GC. Isso pode levar a problemas de uso de memória.

Se você precisar de uma instância com a mesma duração de uma solicitação, sugiro usar a HttpContext.Current.Itemscoleção. Esse design foi concebido para ser um local para armazenar coisas de que você precisa durante a solicitação. Para melhor design e legibilidade, você pode usar o padrão Singleton para ajudá-lo a gerenciar esses itens. Basta criar uma classe Singleton que armazene sua instância no HttpContext.Current.Items. (Na minha biblioteca comum do ASP.NET, tenho uma classe SingletonRequest genérica para esse fim).

driis
fonte
3
Você poderia fornecer uma amostra do seu padrão Singleton envolvendo HttpContext.Current.Items?
precisa saber é o seguinte
Mais detalhes sobre minha situação: no meu aplicativo Web, o usuário executará uma biblioteca de classes de código que usa uma propriedade de classe compartilhada. Quero que essa propriedade seja específica do usuário, mas não quero entregar essa propriedade às diferentes funções. O design que você mencionou pode lidar com isso corretamente?
precisa saber é o seguinte
Por favor, você poderia compartilhar a classe SingletonRequest?
TCE #
Eu não guardo nenhum dado na classe estática. Eu uso a classe estática apenas para obter dados ou definir dados como uma camada de dados. Então, há algum problema?
berrante
"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"- Existe alguma fonte para isso, porque não faz sentido e entra em conflito com o que li em outro lugar. Quando o AppPool é reciclado, o Domínio do Aplicativo relacionado é completamente destruído e armazenado em GC. Quando isso acontece, qualquer instância estática relacionada também será submetida ao GC porque sua raiz (o AppDomain) desapareceu. Como parte da reciclagem do pool, um novo AppDomain é criado e suas instâncias estáticas associadas são inicializadas.
Nick
30

Os membros estáticos têm apenas um escopo do processo de trabalho atual, portanto, nada tem a ver com solicitações, porque solicitações diferentes podem ou não ser tratadas pelo mesmo processo de trabalho.

  • Para compartilhar dados com um usuário específico e entre solicitações, use HttpContext.Current.Session.
  • Para compartilhar dados em uma solicitação específica, use HttpContext.Current.Items.
  • Para compartilhar dados em todo o aplicativo, escreva um mecanismo para isso ou configure o IIS para trabalhar com um único processo e escreva um aplicativo singleton / use.

A propósito, o número padrão de processos de trabalho é 1; é por isso que a web está cheia de pessoas pensando que membros estáticos têm um escopo de todo o aplicativo.

Moshe Bixenshpaner
fonte
11

Como os tipos estão contidos em um domínio de aplicativo, seria de esperar que as classes estáticas estivessem presentes desde que o domínio do aplicativo não fosse reciclado ou se a solicitação fosse atendida por um domínio de aplicativo diferente.

Posso pensar em várias maneiras de tornar objetos específicos para uma solicitação específica, dependendo do que você deseja fazer, por exemplo, você pode instanciar o objeto em Application.BeginRequest e armazená-lo no objeto HttpRequest para que ele possa ser acessado por todos os objetos em o pipeline de processamento de solicitações.

Sijin
fonte
4

Se eles não são exclusivos para cada solicitação, existe uma maneira de permitir que eles sejam?

Não. Os membros estáticos pertencem ao processo ASP.NET e são compartilhados por todos os usuários do aplicativo Web. Você precisará recorrer a outras técnicas de gerenciamento de sessões, como variáveis ​​de sessão.

rp.
fonte
1

Métodos, propriedades e classes normalmente estáticos são comuns no Application nível. Enquanto o aplicativo permanecer, eles serão compartilhados.

Você pode especificar um comportamento diferente usando o ThreadStaticatributo Nesse caso, eles serão específicos para o segmento atual, que, eu acho, é específico para cada solicitação.
Eu não recomendaria isso, embora pareça complicado demais.

Você pode usar HttpContext.Current.Itemspara configurar itens para uma solicitação ou HttpContext.Current.Sessionpara um usuário (entre solicitações).

Em geral, porém, a menos que você precise usar coisas como Server.Transfer, a melhor maneira é basicamente criar coisas uma vez e depois transmiti-las explicitamente via invocação de método.

Sklivvz
fonte
3
Jon Skeet nos mostra que ThreadStatic nunca está seguro em ASP.Net stackoverflow.com/questions/4791208/...
Mark Lindell
Votado para baixo, pois um segmento não é exclusivo de uma solicitação. Por favor, remova esta resposta
seebiscuit