排查无效的 viewstate 问题

作者 :Apurva Joshi

此疑难解答中使用的工具:

  • NA

此材料仅供参考。 Microsoft 不做任何明示或暗示的担保。

概述

视图状态是 ASP.NET 中的一项功能,允许页面自动保留状态,而无需依赖服务器状态 (,例如会话状态) 。 但是,与视图状态相关的问题可能难以调试。 在大多数情况下,当视图状态出现问题时,在 Web 浏览器中收到以下错误消息,几乎没有迹象表明可能导致问题的原因:

"The viewstate is invalid for this page and might be corrupted"

本文介绍一些可用于调试和解决视图状态问题的技术。

方案和故障排除

验证是否未遇到已修复的问题

ASP.NET 1.0 修补程序和服务包修复了许多视图状态问题,这些修补程序也是 ASP.NET 1.1 的一部分。 在跟踪已解决的问题之前,请确保已应用最新修补程序。 可以从以下 Microsoft 开发人员网络 (MSDN) 网站获取最新的 Microsoft .NET Framework更新:

https://msdn.microsoft.com/netframework/aa569276.aspx

如果在 Web 场中运行,请设置 validationKey 属性

在 Web 场中,每个客户端请求都可以在每个回发时转到其他计算机。 由于此行为,不能将 validationKey 属性设置为 Machine.config 文件中的 AutoGenerate。 相反,必须将 validationKey 属性的值设置为 Web 场上所有计算机共享的固定字符串。

有关此问题的详细信息,请单击以下文章编号以查看 Microsoft 知识库中的文章:

https://support.microsoft.com/kb/323744

不要在 Web 场中以视图状态存储动态生成的类型

当 ASP.NET 动态编译文件时,这些文件内置于具有基本随机名称的程序集 (中,例如,文件名可能jp395dun.dll) 。 如果运行的是 Web 场,则相同的文件将编译为具有不同随机名称的程序集。 通常,这不是问题,因为没有人对这些程序集名称做出假设。 但是,如果使用二进制序列化将动态编译的类型放入视图状态,则程序集的名称将作为视图状态数据的一部分包含在视图中。 当该视图状态稍后发送到 Web 场中的其他服务器时,视图状态无法反序列化,因为它使用不同的程序集名称。

解决此问题的最佳解决方法是避免使用二进制序列化。 即使遇到此问题,二进制序列化也会使用许多资源。 相反,将视图状态中的内容限制为数组、对、三元组和简单类型的组合 (,例如字符串、int 和其他类型) 。 System.Web.UI.Pair 和 System.Web.UI.Triplet 是视图状态引擎可以高效处理的简单包装器类型。

避免此问题的替代方法是将存储在视图状态的类型移到预编译程序集中,无论是在 Bin 文件夹中还是在全局程序集缓存中。 此修补程序不解决性能问题,但它保证程序集在所有计算机上具有相同的名称。

请注意,如果将复杂数据类型存储在视图状态并遇到此问题,则调用堆栈信息将包含类似于以下内容的堆栈:

[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

确定问题是否与视图状态 MAC 功能相关

视图状态机身份验证代码 (MAC) 功能的目的是使客户端无法发送包含恶意视图状态的请求。 默认情况下,此功能在Machine.config文件中的以下标志中启用。

enableViewStateMac="true"

确定处理的问题是否与 MAC 功能相关的最简单方法是关闭该功能。 为此,请将Machine.config文件中的标志更改为以下代码。

enableViewStateMac="false"

如果不再出现视图状态错误,则问题与 MAC 功能相关。

重要

仅关闭视图状态 MAC 功能,以帮助诊断问题。 不应使视图状态 MAC 处于关闭状态以解决此问题。 如果是这样,可以引入安全漏洞

一般情况下,Microsoft 建议不要关闭视图状态 MAC 功能,除非你完全确信已禁用所有不对 (输出进行 HTML 编码的控件的视图状态,例如 DataGrid 控件、DataList 控件、标签控件和其他控件) ,或者始终在每个请求上显式设置其值,使其值变为安全。

确定收到错误消息时发生什么异常

遗憾的是,本文的“概述”部分中提到的无效视图状态错误消息并不十分丰富。 错误消息通常是在处理视图状态时引发的一些异常导致的。 问题是,正在使用异常,其详细信息在错误消息中丢失。

通过使用调试器,可以确定原始异常。 为此,必须将调试器附加到 ASP.NET 进程 (Aspnet_wp.exe 或W3wp.exe) ,然后将其设置为捕获所有异常。 甚至可以配置调试诊断 1.2 工具来捕获托管异常。

尝试在会话中存储视图状态

默认情况下,视图状态通过 <输入类型=隐藏> 字段(发送到浏览器)进行舍入。 然后,浏览器在下一个请求中将字段发送回服务器。 在某些情况下,此视图状态可能会变得相当大,并且可能是问题的潜在来源。 某些浏览器无法处理如此大的隐藏字段 (和生成的大型请求) ,并且浏览器可能会截断视图状态。 截断视图状态会导致“视图状态已损坏”错误消息。 此行为最有可能发生在更简单的浏览器中。 例如,此行为可能在 PDA 上的浏览器中发生。

若要确定是否遇到此类问题,请尝试在会话中存储视图状态。 下面的示例演示如何执行此操作。

<%@ 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>

以下代码行仅在 1.0 ASP.NET 中需要,才能解决 bug 问题。 在 ASP.NET 1.1 加号中,不需要。

<input type=hidden name=__VIEWSTATE>

确定问题是否由工作进程回收引起

请考虑以下场景。

  • 在 MICROSOFT INTERNET INFORMATION SERVICES (IIS) 6.0 下运行 ASP.NET。
  • 应用程序池在本地系统帐户、网络服务帐户或管理级别帐户以外的标识下运行。
  • MACHINEKEY 元素的 <validationKey> 属性设置为配置文件中的 AutoGenerate。

在此方案中,以下过程将导致视图状态错误发生:

  1. 用户浏览页面。
  2. 托管 ASP.NET 应用程序的工作进程会回收。
  3. 用户发回页面。

此方案的解决方法是在配置文件中使用显式 validationKey 属性。

其他资源