Aplicações do ASP.NET resolução de problemas com a utilização de palavras-chave estáticas

Artigo: 893666 - Ver produtos para os quais este artigo se aplica.
Coluna de voz de suporte do ASP.NET

Aplicações do ASP.NET resolução de problemas com a utilização de palavras-chave estáticas

para personalizar esta coluna às suas necessidades, pretendemos convidá-lo para submeter as suas ideias sobre tópicos que lhe interessam e problemas que pretende ver endereçados artigos de base de dados de conhecimento no futuro e colunas de voz de suporte. Pode submeter as ideias e comentários utilizando o formulário Ask For It. Também há uma hiperligação para o formulário na parte inferior desta coluna.
Expandir tudo | Reduzir tudo

Nesta página

Bem-vindo à coluna voz de suporte do Microsoft ASP.NET! Meu nome estiver Jerry Orman. Foram com a Microsoft 5 anos e ter gasto a maior parte do meu tempo relacionada com a Web tecnologias como o Microsoft FrontPage e novas tecnologias Microsoft SharePoint. Ter gasto o ano passado a trabalhar com o Microsoft ASP.NET como um engenheiro de suporte. Este mês na coluna voz de suporte, a vai descrever aplicações do ASP.NET resolução de problemas com a utilização de palavras-chave estáticas.

Statics

Este artigo descreve dois comportamentos diferentes que são causadas por palavras-chave estáticas e que pode ser difícil resolver. Deve depois de ler este artigo, pode evitar estes comportamentos nas suas aplicações e conseguir melhor diagnosticá-los se ocorrerem.

Os utilizadores vêem dados incorrectos

Um sintoma a que é muito difícil resolver ocorre quando um utilizador submete dados, mas informações outro utilizador são apresentadas ou existe numa base de dados. Isto normalmente acontece devido a utilização incorrecta de variáveis estáticas em classes. Um objecto estático é instanciada uma vez para cada domínio de aplicação e todo o processamento da aplicação partilha o mesmo objecto. Por exemplo, vamos supor que configurar uma propriedade estática numa classe utilizando o seguinte código.
using System;

namespace statics
{
	public class BadClass
	{
		private static string _MyData;

		public static string MyData
		{
			get{return _MyData;}
			set{_MyData = value;}
		}
	}
}
A propriedade MyData é estático e público. Pode acedê-lo em qualquer parte na sua aplicação utilizando a sintaxe seguinte:

BadClass.MyData

Até agora imagine que tem uma página que define o valor do MyData e, em seguida, efectua algumas trabalhar com ele. Se vários utilizadores de visitas a página ao mesmo tempo, tem agora uma condição de corrida em que o último utilizador que actualizado MyData wins. O seguinte exemplo mostra este comportamento, definindo o objecto estático durante um evento button_click . Este exemplo também torna a suspensão de thread durante 15 segundos. Isto permite que os pedidos para a mesma altura. Para o fazer, siga estes passos:
  1. Crie um formulário Web .aspx.
  2. Adicione um rótulo, um botão e uma caixa de texto. O código HTML será semelhante à seguinte.
    <body>
    	<form id="Form1" method="post" runat="server">
    		<asp:Label id="Label1" runat="server"></asp:Label>
    		<br>
    		<asp:Button id="Button1" runat="server" Text="Button"></asp:Button>
    		</br>
    		<asp:TextBox id="TextBox1" runat="server"></asp:TextBox>
    	</form>
    </body>
    
    
  3. Faça duplo clique no botão para criar um evento button_click .
    private void Button1_Click(object sender, System.EventArgs e)
    {
    	//Set the static property to the value of the text box.
    	BadClass.MyData = TextBox1.Text;
    
    	//Make the thread wait 30 seconds
    	System.Threading.Thread.Sleep(30000);
    
    	//Set the label to the value of the property.
    	Label1.Text = BadClass.MyData;
    }
  4. Abrir separado dois Microsoft Internet Explorer processa:
    1. Clique em Iniciar , aponte para Todos os programas e, em seguida, clique em Internet Explorer .
    2. Repita o passo um.
    Isto irá garantir que tem dois Iexplore.exe separado processos em execução ao mesmo tempo. Pode verificar o Gestor de tarefas para se certificar de que. Quando tiver dois processos de Iexplore.exe em execução em simultâneo, terá de sessões exclusivas para cada pedido de página. Pedidos com o mesmo ID da sessão são processados pela ordem aparecem e não executado ao mesmo tempo.
  5. Procure a página .aspx ambas as janelas do browser.
  6. Submeter Utilizador1 na caixa de texto de uma janela do browser e, em seguida, submeter User2 na caixa de texto na outra janela do browser.

    Depois de concluir as páginas, poderá ver User2 em ambos os rótulos.
Tal como foi mencionado anteriormente, ambas as páginas estão a executar em simultâneo. O primeiro pedido define a propriedade estática para o Utilizador1 e, em seguida, entra no modo de suspensão. Enquanto o thread está em pausa, outro pedido é fornecido e define o mesmo objecto para User2. O thread que processa o primeiro pedido completa e, em seguida, apresenta o valor. O valor é definido como User2.

Evitar este comportamento

A melhor forma para evitar este comportamento é para não fazer com que o objecto estático e utilizar uma instância da classe para definir e obter os valores. A propriedade já não é partilhada, uma vez que é criada uma cópia do objecto para cada pedido e não verá este comportamento. Para evitar este comportamento, siga estes passos:
  1. Remover o modificador estático do ficheiro BadClass.cs.
    using System;
    
    namespace statics
    {
    	public class BadClass
    	{
    		private string _MyData;  	//Removed static
    	
    		public string MyData		//Removed static
    		{
    			get{return _MyData;}
    			set{_MyData = value;}
    		}
    	}
    }
    
  2. Alterar evento button_click .
    private void Button1_Click(object sender, System.EventArgs e)
    {
    	//Create an instance of BadClass
            BadClass _bad = new BadClass();	
    	
    	//Set the MyData property on this instance
            _bad.MyData = TextBox1.Text;
    
            //Sleep for 30 seconds
    	System.Threading.Thread.Sleep(30000);
    
    	//Set the label to the value of the property
    	Label1.Text = _bad.MyData;
    }
    
Se tiver de utilizar o objecto estático, terá de implementar bloqueio quando utiliza o objecto estático. Isto impede que os threads aceder ao objecto ao mesmo tempo. Para o fazer, siga estes passos:
  1. Adicione um objecto estático no código subjacente a página. Este objecto será um recurso partilhado que as páginas podem obter um bloqueio no.
    static object StaticLocker = new object();
  2. Alterar o evento button_click seguinte.
    private void Button1_Click(object sender, System.EventArgs e)
    {
    	//Lock the object to prevent multiple threads from writing to the static property
    	lock(StaticLocker)
    	{
    		//Set the static property
    		BadClass.MyData = TextBox1.Text;
    
    		//Put the thread to sleep for 30 seconds
    		System.Threading.Thread.Sleep(30000);
    
    		//Set the label to the value of the static property
    		Label1.Text = BadClass.MyData;
    	}
    }
    

NullReferenceException causado por statics

Outro comportamento que ocorre quando utiliza statics é uma excepção System.NullReferenceException. Por exemplo, alterar o código de evento button_click para o seguinte.
private void Button1_Click(object sender, System.EventArgs e)
{
	BadClass.MyData = TextBox1.Text;
	System.Threading.Thread.Sleep(10000);
	Label1.Text = BadClass.MyData.ToString();
	BadClass.MyData = null;
}
se efectuar o mesmo teste como antes, quando BadClass.MyData.ToString() é chamado para o segundo pedido, irá accionar uma excepção System.NullReferenceException. System.NullReferenceException excepção ocorre porque o primeiro pedido definir o valor como nulo enquanto o segundo pedido esteve à espera. A resolução para este comportamento é o mesmo para uma propriedade estática.
Fuga de memória devida a eventos estáticos
Se configurar um evento estático e subscrever esse evento a partir de uma página .aspx, o processo será executado eventualmente memória esgotada. Vamos considerar adicione o seguinte o BadClass.cs ficheiro
public delegate void MyEvent();
public static event MyEvent BadEvent;
É, em seguida, ligue para o delegado do evento no método InitializeComponent de uma página .aspx para um método na página.
private void InitializeComponent()
{    
	//Add this with the other items (for example, this.Load).
	BadClass.BadEvent += new BadClass.MyEvent(this.TestEvent);
}
também adicionar o seguinte método à sua página. Este é o método especificado quando ao ligar o evento no método InitializeComponent :
private void TestEvent()
{
	//Do some work here.
}
Porque é que isto faz com que uma fuga de memória
Uma vez que o evento é estático e nunca sai do âmbito, estará a adicionar o método à lista de eventos que são desencadeado quando o evento ocorre sempre que a página é executada. O resultado final desta situação é que raiz de qualquer objecto que ligue ao evento estático na memória e nunca serão recolhido. Neste caso, esse objecto é a classe de página .aspx real.

Este comportamento ocorre no depurador Windbg.exe ou o depurador cdb.exe executando o ! gcroot comandos no objecto que está a adicionar o evento de. Verá saída semelhante ao seguinte.
HANDLE(Strong):c3d11d8:Root:0x90b8838(System.Object[])->0x5346f68(statics.BadClass/MyEvent)->
0x10ff928(statics.BadClass/MyEvent)->
0x10faa24(statics.BadClass/MyEvent)->
muitos pedidos de objectos foram efectuados para os seguintes eventos.
0x10e6fe0(statics.BadClass/MyEvent)->
0x533baf0(ASP.StaticsTest_aspx)
pode ver que o item inferior é a classe de página .aspx e raiz para múltiplos delegados MyEvent. Porque a raiz de uma página .aspx, não pode ser limpo. O outro efeito secundário é que tudo o que a página .aspx está a utilizar também não pode ser limpo porque estes têm raiz no objecto de página.

Para obter mais informações sobre o recolector de lixo do Microsoft .NET, visite os seguintes Web sites da MSDN:
http://msdn.microsoft.com/msdnmag/issues/1100/GCI/default.aspx
http://msdn.microsoft.com/msdnmag/issues/1200/GCI2/default.aspx
Para obter mais informações sobre o ! gcroot comando e obter este resultado, consulte a secção "Contadores de memória do .NET CLR" do seguinte Web site da MSDN:
http://msdn2.microsoft.com/en-us/library/ms972959.aspx

Evitar este comportamento

Para evitar este comportamento, pode não utilizar a palavra-chave estática no evento ou remover o processador de eventos da página quando tiver terminado a utilizá-lo. Um exemplo de ASP.NET, ligue o evento quando é chamado Page_Init . É necessário removê-la quando carrega a página adicionando um processador de eventos para o evento Page_Unload .

Adicione o seguinte método InitializeComponents .
this.Unload += new System.EventHandler(this.Page_Unload);

Add the following method to the page to remove the event:
private void Page_Unload(object sender, System.EventArgs e)
{
	BadClass.test -= new BadClass.MyEvent(this.TestEvent);
}
para obter mais informações sobre eventos, visite o seguinte site da Web MSDN:
http://msdn2.microsoft.com/en-us/library/aa645739(vs.71).aspx
Como sempre, vontade submeter ideias tópicos que pretende no futuro corrigida colunas ou na base de dados de conhecimento utilizando o formulário Ask For It.

Propriedades

Artigo: 893666 - Última revisão: terça-feira, 27 de Março de 2007 - Revisão: 1.4
A informação contida neste artigo aplica-se a:
  • Microsoft ASP.NET 1.0
  • Microsoft ASP.NET 1.1
Palavras-chave: 
kbmt kbhowto kbasp KB893666 KbMtpt
Tradução automática
IMPORTANTE: Este artigo foi traduzido por um sistema de tradução automática (também designado por Machine translation ou MT), não tendo sido portanto revisto ou traduzido por humanos. A Microsoft tem artigos traduzidos por aplicações (MT) e artigos traduzidos por tradutores profissionais. O objectivo é simples: oferecer em Português a totalidade dos artigos existentes na base de dados do suporte. Sabemos no entanto que a tradução automática não é sempre perfeita. Esta pode conter erros de vocabulário, sintaxe ou gramática? erros semelhantes aos que um estrangeiro realiza ao falar em Português. A Microsoft não é responsável por incoerências, erros ou estragos realizados na sequência da utilização dos artigos MT por parte dos nossos clientes. A Microsoft realiza actualizações frequentes ao software de tradução automática (MT). Obrigado.
Clique aqui para ver a versão em Inglês deste artigo: 893666

Submeter comentários