Solución de problemas de viewstate no válidos

En este artículo se presentan técnicas para depurar y resolver problemas con viewstate en aplicaciones de Microsoft ASP.NET.

              Versión original del producto: ASP.NET
Número de KB original: 829743

Introducción

Viewstate es una característica de ASP.NET que permite a las páginas conservar automáticamente el estado sin depender del estado del servidor (por ejemplo, el estado de sesión). Sin embargo, los problemas relacionados con viewstate pueden ser difíciles de depurar. En la mayoría de los casos, cuando se producen problemas con viewstate, recibe el siguiente mensaje de error en el explorador web, con poca indicación de lo que podría estar causando el problema:

Viewstate no es válido para esta página y podría estar dañado.

En este artículo se describen algunas técnicas que se pueden usar para depurar y resolver problemas con viewstate.

Establezca el atributo validationKey si se ejecuta en una granja de servidores web.

En una granja de servidores web, cada solicitud de cliente puede ir a una máquina diferente en cada postback. Debido a este comportamiento, no puede dejar el validationKey atributo establecido AutoGenerate en en el archivo Machine.config . En su lugar, debe establecer el valor del validationKey atributo en una cadena fija compartida por todas las máquinas de la granja de servidores web.

No almacenar tipos generados dinámicamente en viewstate en una granja de servidores web

Cuando ASP.NET compila archivos dinámicamente, los archivos se integran en ensamblados con nombres aleatorios (por ejemplo, un nombre de archivo podría ser jp395dun.dll). Si ejecuta una granja de servidores web, los mismos archivos se compilan en ensamblados con nombres aleatorios diferentes. Normalmente, esto no es un problema porque nadie hace suposiciones sobre esos nombres de ensamblado. Pero si alguna vez coloca un tipo compilado dinámicamente en viewstate mediante la serialización binaria, el nombre del ensamblado se incluye como parte de los datos viewstate. Cuando ese viewstate se envía más adelante a un servidor diferente de la granja de servidores web, el estado de vista no se puede deserializar porque usa nombres de ensamblado diferentes.

La mejor resolución es evitar el uso de la serialización binaria. La serialización binaria usa muchos recursos incluso cuando no se encuentra con este problema. En su lugar, limite lo que coloca en viewstate a una combinación de matrices, pares, tripletes y tipos simples (por ejemplo, cadenas, int y otros tipos). System.Web.UI.Pair y System.Web.UI.Triplet son tipos de contenedor simples que el motor viewstate puede procesar de forma eficaz.

Una corrección alternativa para evitar este problema es mover los tipos que se almacenan en viewstate a un ensamblado precompilado, ya sea en la Bin carpeta o en la Global Assembly memoria caché. Esta corrección no aborda el rendimiento, pero garantiza que el ensamblado tenga el mismo nombre en todos los equipos.

Nota:

Si almacena tipos de datos complejos en viewstate y experimenta este problema, la información de la pila de llamadas contendrá pilas similares a las siguientes:

[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

El propósito de la característica de código de autenticación de máquina (MAC) viewstate es hacer imposible que los clientes envíen una solicitud que contenga un estado de vista malintencionado. De forma predeterminada, esta característica está habilitada en la siguiente marca en el archivo Machine.config .

enableViewStateMac="true"

La manera más sencilla de determinar si el problema con el que está tratando está relacionado con la característica MAC es desactivar la característica. Para ello, cambie la marca del archivo Machine.config al código siguiente.

enableViewStateMac="false"

Si ya no recibe errores viewstate, el problema está relacionado con la característica MAC.

Importante

Desactive solo la característica viewstate MAC para ayudar a diagnosticar el problema. No debe mantener el mac viewstate desactivado para solucionar el problema. Si lo hace, podría introducir agujeros de seguridad. Para obtener más información, consulte Creación de aplicaciones de ASP.NET seguras: autenticación, autorización y comunicación segura.

Si desactiva la característica VIEWSTATE MAC y, a continuación, usa viewstate para los controles que no codifican HTML (por ejemplo, un control Label), los atacantes pueden manipular los datos de viewstate y pueden colocar datos arbitrarios en viewstate. Estos datos arbitrarios se descodifican y, a continuación, los usan los controles cuando representan la página publicada. Como resultado, los atacantes pueden insertar script en la aplicación a menos que trabaje para evitar el ataque. Por ejemplo, un atacante podría descodificar los datos, insertar script en los datos donde se encuentra un control Label y, a continuación, vincularlos desde un sitio web. Cualquier persona que haga clic en el vínculo sería víctima de un ataque por inyección de scripts que podría robar sus cookies de autenticación o su identificador de sesión. El script también podría permitir que un atacante altere los datos de estado de los controles que usan viewstate y ataques específicos de la aplicación podría producirse como resultado.

En general, Microsoft recomienda no desactivar la característica VIEWSTATE MAC a menos que esté seguro de que ha deshabilitado viewstate para todos los controles que no codifican su salida (por ejemplo, controles DataGrid, controles DataList, controles Label y otros controles) como HTML o que siempre está estableciendo explícitamente sus valores en cada solicitud en algo que se sabe que es seguro.

Determinar exactamente qué excepción se produce al recibir el mensaje de error

Desafortunadamente, el mensaje de error viewstate no válido que se menciona en la sección Introducción de este artículo no es informativo. El mensaje de error se debe a alguna excepción que se genera cuando se está procesando el estado de vista. El problema es que la excepción se está consumiendo y sus detalles se pierden en el mensaje de error.

Mediante el uso de un depurador, puede determinar la excepción original. Para ello, debe asociar un depurador al proceso de ASP.NET (Aspnet_wp.exe o W3wp.exe) y, a continuación, establecerlo para detectar todas las excepciones. El depurador probablemente se detendrá en algunas excepciones que no son pertinentes, pero finalmente alcanzará la excepción viewstate y proporcionará información útil para la solución de problemas.

Los pasos siguientes son un ejemplo que usa el depurador en tiempo de ejecución (Cordbg.exe).

  1. En el símbolo del sistema, ejecute el iisreset comando para asegurarse de que se le proporciona un buen punto de partida y, a continuación, vaya a una página del sitio.

  2. Ejecute cordbg.exe.

  3. Escriba <pro>y, a continuación, presione ENTRAR. Aparecerá una lista de procesos administrados. Debería ver el Aspnet_wp.exe o el proceso deW3wp.exe . Observe su PID.

  4. Escriba un objeto <PID>.

    Nota:

    Reemplace PID por el PID que se anotó en el paso 3.

  5. Escriba ca e para indicar a Cordbg.exe que interrumpa todas las excepciones y, a continuación, escriba <gto> ejecutar el proceso.

  6. Cada vez que obtenga una excepción, escriba <w> para ver la pila. Si la pila es una excepción viewstate (busque LoadPageStateFromPersistenceMedium en la pila), copie todas las excepciones y la información de la pila de la ventana de comandos y, a continuación, guarde la información. Esta información puede ayudarle a comprender el problema. Si la excepción no está relacionada, escriba <g>.

Pruebe a almacenar el estado de vista en la sesión.

De forma predeterminada, viewstate se redondea con un <input type=hidden> campo que se envía al explorador. A continuación, el explorador envía el campo al servidor en la siguiente solicitud. En algunos casos, este estado de vista puede ser grande y ser una posible fuente de problemas. Algunos exploradores no pueden controlar un campo oculto de gran tamaño (y la solicitud grande resultante) y los exploradores pueden truncar el estado de vista. Al truncar el estado de vista, se produce un mensaje de error "viewstate dañado". Este comportamiento es más probable que se produzca en exploradores más sencillos. Por ejemplo, este comportamiento puede producirse en un explorador en un PDA.

Para determinar si puede encontrarse con un problema de este tipo, intente almacenar el estado de vista en la sesión. En el ejemplo siguiente se muestra cómo hacerlo.

<%@ 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 si el problema se debe al reciclaje de procesos de trabajo

Imagina la siguiente situación:

  • Está ejecutando ASP.NET en Microsoft Internet Information Services (IIS) 6.0.
  • El grupo de aplicaciones se ejecuta bajo una identidad distinta de la cuenta del sistema local, la cuenta de servicio de red o una cuenta de nivel administrativo.
  • El validationKey atributo del <machineKey> elemento se establece AutoGenerate en en el archivo de configuración.

En este escenario, el procedimiento siguiente hace que se produzca un error viewstate:

  1. Un usuario examina una página.
  2. El proceso de trabajo que hospeda la aplicación ASP.NET recicla.
  3. El usuario devuelve la página.

Como solución alternativa para este escenario, use un atributo explícito validationKey en el archivo de configuración.

Referencias