Never give up - LEO

人 只有在合适的地方 才能体现出最大的价值
  博客园  :: 首页  :: 联系 :: 订阅 订阅  :: 管理
前几天遇到一个页面错误,其实这个错误表面上看上去挺简单的,信息也很明确,可就这个错误让我整了一天。错误信息如下图:


这种错误我想很多人可能都遇到过,视图状态被破坏掉了,页面无法显示,我到网上搜搜,很多关于这样的错误描叙和解决办法。刚开始我还挺高兴,觉得这个没什么难,三下两下就能搞定。
既然是ViewState出了问题,那么我就先把页面的ViewState去掉再试,去掉以后运行很正常,但这毕竟不是解决问题的最佳办法。
页面的ViewStates是可以通过enableViewState参数来设置是否有效。在asp.net2.0中又加入了ViewState加密的功能,下面这两个属性很关键:
enableViewStateMac
指定从客户端回发页时,ASP.NET 是否应该对页的视图状态运行消息身份验证代码 (MAC)。如果为 True,将检查加密的视图状态,以验证视图状态是否已在客户端被篡改。默认值为 True。
 
viewStateEncryptionMode
指定视图状态的加密模式。ViewStateEncryptionMode 属性重写配置文件中设置的该属性。
此属性可以为下列可能值之一。
Always
 视图状态始终加密。
Auto
 视图状态根据控件的请求而加密。
Never
 视图状态从不加密,即使控件请求加密时也是如此。
此属性是 .NET Framework 2.0 版中的新属性。
默认值为 Auto。


引发上面这种错误的一般原因都是因为网页还没有完全下载完,页面的ViewState不完全,然后就有了Postback,这样就导致了ViewState验证错误。这种解决方法一般就是在页面或者web.config中加上或更改pages属性,如下:
<pages enableEventValidation="false" viewStateEncryptionMode ="Never" /> 
这样页面就不会进行验证。
学到了这个以后呢,我就立马去修改我的page设置,满以为能顺利过关,可没想到错误依旧,这下我可头大了,难道是缓存。我又把缓存删掉再试,还不行;然后又把电脑重启,问题依旧。。。。。。。
这下可就郁闷了。。。
后来我突然想到,上个版本没有遇到过这样的问题,为什么现在遇到了呢,开发环境都一样?
于是我把上个版本弄出来,两个一起看,代码上面尽然一模一样,项目的配置属性也都是一样的。但是前个版本就是运行正常。我又仔细看了看错误,有下面这么一段,这段错误很奇怪,写着重复定义错误,但是又不知道这个错误出自哪里,而且这个错误跟ViewState好像没什么关系,百思不得其解。


[XmlSchemaException: The global element 'SM_DyColumns' has already been declared.]
   System.Xml.Schema.XmlSchemaSet.InternalValidationCallback(Object sender, ValidationEventArgs e) +20
   System.Xml.Schema.BaseProcessor.SendValidationEvent(XmlSchemaException e, XmlSeverityType severity) +62
   System.Xml.Schema.BaseProcessor.AddToTable(XmlSchemaObjectTable table, XmlQualifiedName qname, XmlSchemaObject item) +896
   System.Xml.Schema.Preprocessor.Preprocess(XmlSchema schema, String targetNamespace, ArrayList imports) +4418
   System.Xml.Schema.Preprocessor.Execute(XmlSchema schema, String targetNamespace, Boolean loadExternals) +698
   System.Xml.Schema.XmlSchemaSet.PreprocessSchema(XmlSchema& schema, String targetNamespace) +214
   System.Xml.Schema.XmlSchemaSet.Add(String targetNamespace, XmlSchema schema) +39
   System.Xml.Schema.XmlSchemaSet.Add(XmlSchema schema) +158
   System.Data.DataSet.ReadXSDSchema(XmlReader reader, Boolean denyResolving) +214
   System.Data.DataSet.ReadXmlSchema(XmlReader reader, Boolean denyResolving) +371
   System.Data.DataTable.DeserializeDataTable(SerializationInfo info, StreamingContext context, Boolean isSingleTable, SerializationFormat remotingFormat) +302
   System.Data.DataTable..ctor(SerializationInfo info, StreamingContext context) +261

 

最后的办法就只能用排除法了,这几天改了一些东西,我想肯定有关系,于是我把改过的东西一个一个排除测试,最后令我惊讶的尽然是数据访问层的更改导致出现了这样的错误。这就纳闷了,数据层跟ViewState有什么关系啊?
然后我又把数据层一个一个方法的进行排除,终于定为到了一个方法上面,但是这个方法运行很正常。可把这个方法一换,页面就好了。
我在运行监视里看看是不是数据集返回的有问题,突然发现有两个相同的名字,然后想起前面那个与ViewState完全没关系的重复定义错误.该不会是问题出在这吧?可怎么会有两个相同的名字呢?存储过程肯定没问题,前版本调用的是同样的。
我看了看,原来出在这一句:
DataSet returnDataSet = new DataSet("TableName");
tempAdapter.Fill(returnDataSet, "TableName");

我new DataSet时给DataSet附上了一个名字,然后再Fill时又给DataSet的表里面附了一个相同的名字,这样数据集和表的名字就一样了。我把数据集的名字改掉后,页面的错误尽然消失了。

到这里,问题解决了,可留下个疑问,为什么会出现这样的错误呢?
再回头仔细看看那个重复定义的错误,感觉明白了点。ViewState把表格对象保存后,可能用的是xml格式,但是DataSet和DataTable的名字一样,导致xml结构上出了问题,所以当ViewState重新读取时发生错误。这也是我的理解,还希望大家给点意见。

为了方便大家把问题重现,我加了段测试代码:
<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default3.aspx.cs" Inherits="Default3" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
    
<title>Untitled Page</title>
</head>
<body>
    
<form id="form1" runat="server">
    
<div>
        
<asp:Button ID="Button1" runat="server" OnClick="Button1_Click" Text="Button" />
        
<asp:TextBox ID="TextBox1" runat="server"></asp:TextBox>
    
</div>
    
</form>
</body>
</html>
 1using System;
 2using System.Data;
 3using System.Configuration;
 4using System.Collections;
 5using System.Web;
 6using System.Web.Security;
 7using System.Web.UI;
 8using System.Web.UI.WebControls;
 9using System.Web.UI.WebControls.WebParts;
10using System.Web.UI.HtmlControls;
11
12public partial class Default3 : System.Web.UI.Page
13{
14    protected void Page_Load(object sender, EventArgs e)
15    {
16        if (!IsPostBack)
17        {
18            DataSet ds = new DataSet("dsname");
19            DataTable dt = new DataTable("dsname");
20            dt.Columns.Add("col",typeof(System.String));
21            DataRow dr = dt.NewRow();
22            dr["col"= "aa";
23            dt.Rows.Add(dr);
24
25            ds.Tables.Add(dt);
26            ViewState["bb"= ds.Tables["dsname"];
27        }

28    }

29    protected void Button1_Click(object sender, EventArgs e)
30    {
31        DataTable dt = (DataTable)ViewState["bb"];
32        this.TextBox1.Text = dt.Rows[0][0].ToString();
33    }

34   
35}

36


大家运行后就可以得到上面的错误,把DataSet的name改了后便正常了。