Solucionar problemas inválidos do viewstate

Este artigo apresenta técnicas para depuração e para resolver problemas com viewstate em aplicativos do Microsoft ASP.NET.

Versão original do produto: ASP.NET
Número de KB original: 829743

Introdução

Viewstate é um recurso no ASP.NET que permite que as páginas preservem automaticamente o estado sem depender do estado do servidor (por exemplo, estado da sessão). No entanto, problemas relacionados ao modo de exibição podem ser difíceis de depurar. Na maioria dos casos, quando ocorrem problemas com o modo de exibição, você recebe a seguinte mensagem de erro no navegador da Web, com pouca indicação do que pode estar causando o problema:

O modo de exibição é inválido para esta página e pode ser corrompido.

Este artigo descreve algumas técnicas que podem ser usadas para depuração e para resolver problemas com viewstate.

Defina o atributo validationKey se você estiver executando em um farm da Web

Em um farm da Web, cada solicitação de cliente pode ir para um computador diferente em cada postback. Devido a esse comportamento, você não pode deixar o validationKey atributo definido como AutoGenerate no arquivo Machine.config . Em vez disso, você deve definir o valor do validationKey atributo como uma cadeia de caracteres fixa que é compartilhada por todos os computadores no farm da Web.

Não armazene tipos gerados dinamicamente no modo de exibição em um farm da Web

Quando ASP.NET compila arquivos dinamicamente, os arquivos são incorporados em assemblies com nomes aleatórios (por exemplo, um nome de arquivo pode ser jp395dun.dll). Se você estiver executando um farm da Web, os mesmos arquivos serão compilados em assemblies com nomes aleatórios diferentes. Normalmente, isso não é um problema porque ninguém faz suposições sobre esses nomes de assembly. Mas se você colocar um tipo compilado dinamicamente no modo de exibição usando serialização binária, o nome do assembly será incluído como parte dos dados do viewstate. Quando esse estado de exibição é enviado posteriormente para um servidor diferente no farm da Web, o modo de exibição não pode ser desserializado porque usa nomes de assembly diferentes.

A melhor resolução é evitar o uso de serialização binária. A serialização binária usa muitos recursos mesmo quando você não se despede desse problema. Em vez disso, limite o que você coloca no viewstate a uma combinação de matrizes, pares, trigêmeos e tipos simples (por exemplo, cadeias de caracteres, int e outros tipos). System.Web.UI.Pair e System.Web.UI.Triplet são tipos de wrapper simples que o mecanismo viewstate pode processar com eficiência.

Uma solução alternativa para evitar esse problema é mover os tipos que você está armazenando no viewstate para um assembly pré-compilado, na pasta Bin ou no Global Assembly cache. Essa correção não aborda o desempenho, mas garante que o assembly tenha o mesmo nome em todos os computadores.

Observação

Se você armazenar tipos de dados complexos no modo de exibição e experimentar esse problema, as informações da pilha de chamadas conterão pilhas semelhantes às seguintes:

[FileNotFoundException: Could not load file or assembly 'App_Web_fx--sar9, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null' or one of its dependencies. The system cannot find the file specified.]
 System.RuntimeTypeHandle._GetTypeByName(String name, Boolean throwOnError, Boolean ignoreCase, Boolean reflectionOnly, StackCrawlMark& stackMark, Boolean loadTypeFromPartialName) +0
System.RuntimeTypeHandle.GetTypeByName(String name, Boolean throwOnError, Boolean ignoreCase, Boolean reflectionOnly, StackCrawlMark& stackMark) +72
System.RuntimeType.PrivateGetType(String typeName, Boolean throwOnError, Boolean ignoreCase, Boolean reflectionOnly, StackCrawlMark& stackMark) +58
System.Type.GetType(String typeName, Boolean throwOnError) +57
System.Web.UI.ObjectStateFormatter.DeserializeType(SerializerBinaryReader reader) +192 
System.Web.UI.ObjectStateFormatter.DeserializeValue(SerializerBinaryReader reader) +943 
System.Web.UI.ObjectStateFormatter.DeserializeValue(SerializerBinaryReader reader) +384 
System.Web.UI.ObjectStateFormatter.DeserializeValue(SerializerBinaryReader reader) +198 
System.Web.UI.ObjectStateFormatter.DeserializeValue(SerializerBinaryReader reader) +210 
System.Web.UI.ObjectStateFormatter.DeserializeValue(SerializerBinaryReader reader) +198 
System.Web.UI.ObjectStateFormatter.Deserialize(Stream inputStream) +142

A finalidade do recurso MAC (código de autenticação do computador viewstate) é tornar impossível que os clientes enviem uma solicitação que contenha um modo de exibição mal-intencionado. Por padrão, esse recurso está habilitado no sinalizador a seguir no arquivo Machine.config .

enableViewStateMac="true"

A maneira mais simples de determinar se o problema com o qual você está lidando está relacionado ao recurso MAC é desativar o recurso. Para fazer isso, altere o sinalizador no arquivoMachine.config para o código a seguir.

enableViewStateMac="false"

Se você não receber mais erros de estado de exibição, o problema estará relacionado ao recurso MAC.

Importante

Desative apenas o recurso MAC viewstate para ajudar a diagnosticar o problema. Você não deve manter o MAC viewstate desativado para resolver o problema. Se você fizer isso, você pode introduzir falhas de segurança. Para obter mais informações, consulte Criar aplicativos de ASP.NET seguros: autenticação, autorização e comunicação segura.

Se você desativar o recurso MAC do viewstate e usar o modo de exibição para controles que não codificam HTML (por exemplo, um controle Label), os invasores podem adulterar os dados de viewstate e podem colocar dados arbitrários no modo de exibição. Esses dados arbitrários são decodificados e usados por controles quando renderizam a página postada. Como resultado, os invasores podem injetar script no aplicativo, a menos que você trabalhe para evitar o ataque. Por exemplo, um invasor pode decodificar os dados, injetar script nos dados em que um controle label está e, em seguida, vinculá-los a ele de um site. Qualquer pessoa que clicar no link seria vítima de um ataque de injeção de script que poderia potencialmente roubar seus cookies de autenticação ou ID da sessão. O script também pode permitir que um invasor altere dados de estado para controles que usam ataques específicos do viewstate e do aplicativo como resultado.

Em geral, a Microsoft recomenda que você não desative o recurso MAC viewstate, a menos que esteja confiante de que você desabilitou o modo de exibição para todos os controles que não codificam sua saída (por exemplo, controles DataGrid, controles DataList, controles label e outros controles) como HTML ou que você está sempre definindo explicitamente seus valores em cada solicitação para algo conhecido por ser seguro.

Determinar exatamente qual exceção ocorre quando você recebe a mensagem de erro

Infelizmente, a mensagem de erro de viewstate inválida mencionada na seção Introdução deste artigo não é informativa. A mensagem de erro é causada por alguma exceção que está sendo gerada quando o viewstate está sendo processado. O problema é que a exceção está sendo consumida e seus detalhes são perdidos na mensagem de erro.

Usando um depurador, você pode determinar a exceção original. Para fazer isso, você deve anexar um depurador ao processo de ASP.NET (Aspnet_wp.exe ou W3wp.exe) e configurá-lo para capturar todas as exceções. O depurador provavelmente vai parar em algumas exceções que não são relevantes, mas eventualmente atingirá a exceção viewstate e fornecerá informações úteis para solução de problemas.

As etapas a seguir são um exemplo que usa o Depurador do Runtime (Cordbg.exe).

  1. No prompt de comando, execute o iisreset comando para garantir que você tenha um bom ponto de partida e navegue até uma página em seu site.

  2. Execute cordbg.exe.

  3. Digite <pro>e pressione ENTER. Uma lista de processos gerenciados será exibida. Você deve ver o Aspnet_wp.exe ou o processo deW3wp.exe . Observe seu PID.

  4. Digite um <PID>.

    Observação

    Substitua o PID pelo PID que foi observado na etapa 3.

  5. Digite ca e para instruir Cordbg.exe a interromper todas as exceções e, em seguida, digite <gto> executar o processo.

  6. Sempre que você obtém uma exceção, digite <w> para ver a pilha. Se a pilha for uma exceção de estado de exibição (procure LoadPageStateFromPersistenceMedium na pilha), copie todas as exceções e as informações de pilha da janela de comando e salve as informações. Essas informações podem ajudá-lo a entender o problema. Se a exceção não estiver relacionada, digite <g>.

Tente armazenar o estado de exibição na sessão

Por padrão, o modo de exibição é tropeçado em rodada com um <input type=hidden> campo que é enviado para o navegador. Em seguida, o navegador envia o campo de volta para o servidor na próxima solicitação. Em alguns casos, esse estado de exibição pode ficar grande e ser uma fonte potencial de problemas. Alguns navegadores não podem lidar com um campo oculto tão grande (e a solicitação grande resultante) e os navegadores podem truncar o viewstate. Truncar o viewstate causa uma mensagem de erro "viewstate corrompido". Esse comportamento provavelmente ocorrerá em navegadores mais simples. Por exemplo, esse comportamento pode ocorrer em um navegador em um PDA.

Para determinar se você pode estar executando esse problema, tente armazenar o estado de exibição na sessão. O exemplo a seguir demonstra como fazer isso.

<%@ language=c# debug=true %> 

<script runat=server> 
protected override object LoadPageStateFromPersistenceMedium() 
{ 
    return Session["_ViewState"]; 
}

protected override void SavePageStateToPersistenceMedium(object viewState) 
{ 
    Session["_ViewState"] = viewState; 
}

void TextChanged(object o, EventArgs e) 
{ 
    Response.Write("TextChanged"); 
} 
</script> 
<form runat=server> 
<asp:button text=Test runat=server/> 
<asp:textbox ontextchanged=TextChanged runat=server/> 
<input type=hidden name=__VIEWSTATE> 
</form> 

Determinar se o problema é causado pela reciclagem do processo de trabalho

Considere o seguinte cenário.

  • Você está executando ASP.NET em Serviços de Informações da Internet da Microsoft (IIS) 6.0.
  • O pool de aplicativos está em execução em uma identidade diferente da conta do Sistema Local, da conta do Serviço de Rede ou de uma conta de nível administrativo.
  • O validationKey atributo do <machineKey> elemento é definido como AutoGenerate no arquivo de configuração.

Nesse cenário, o procedimento a seguir faz com que ocorra um erro de estado de exibição:

  1. Um usuário navega por uma página.
  2. O processo de trabalho que hospeda o aplicativo ASP.NET é reciclado.
  3. O usuário posta de volta a página.

Como solução alternativa para esse cenário, use um atributo explícito validationKey no arquivo de configuração.

Referências