c# - 带有 DropDownListAdapter 的 ViewStateException

标签 c# asp.net controls adapter

我收到这个 500 错误:

Sys.WebForms.PageRequestManagerServerErrorException:在服务器上处理请求时发生未知错误。服务器返回的状态码为:500

更新:

我的错误实际上是这样的: System.Web.UI.ViewStateException

if (viewStates.Length != list.Items.Count + 1)
{
    throw new ViewStateException();
}

自从我将这个适配器添加到本教程中显示的我的站点后,我就一直在使用它。

ASP.NET DropDownList with OptionGroup support

它在所有页面中加载 DropDownList 都很好,但是当我进行任何回发时,常规或 ajax 是出现错误的时间。这是我的适配器和浏览器文件的确切代码。

适配器类

public class DropDownListAdapter : WebControlAdapter
{
    private const string OptionGroupAttribute = "OptionGroup";
    private const string TagOptionGroup = "optgroup";
    private const string AttributeLabel = "label";
    protected override void RenderContents(HtmlTextWriter writer)
    {
        DropDownList list = Control as DropDownList;
        string currentOptionGroup;
        List<string> renderedOptionGroups = new List<string>();
        foreach (ListItem item in list.Items)
        {
            Page.ClientScript.RegisterForEventValidation(
                list.UniqueID, 
                item.Value);
            if (item.Attributes[OptionGroupAttribute] == null)
            {
                RenderListItem(item, writer);
            }
            else
            {
                currentOptionGroup = item.Attributes[OptionGroupAttribute];
                if (renderedOptionGroups.Contains(currentOptionGroup))
                {
                    RenderListItem(item, writer);
                }
                else
                {
                    if (renderedOptionGroups.Count > 0)
                    {
                        RenderOptionGroupEndTag(writer);
                    }
                    RenderOptionGroupBeginTag(currentOptionGroup, writer);
                    renderedOptionGroups.Add(currentOptionGroup);
                    RenderListItem(item, writer);
                }
            }
        }
        if (renderedOptionGroups.Count > 0)
        {
            RenderOptionGroupEndTag(writer);
        }
    }

    private void RenderOptionGroupBeginTag(string name, HtmlTextWriter writer)
    {
        writer.AddAttribute(AttributeLabel, name);
        writer.RenderBeginTag(TagOptionGroup);
    }

    private void RenderOptionGroupEndTag(HtmlTextWriter writer)
    {
        writer.RenderEndTag();
    }

    private void RenderListItem(ListItem item, HtmlTextWriter writer)
    {
        foreach (string key in item.Attributes.Keys)
        {
            if (key != OptionGroupAttribute)
            {
                writer.AddAttribute(key, item.Attributes[key]);
            }
        }
        writer.AddAttribute(HtmlTextWriterAttribute.Value, item.Value, true);
        if (item.Selected)
        {
            writer.AddAttribute(HtmlTextWriterAttribute.Selected, "selected");
        }
        writer.RenderBeginTag(HtmlTextWriterTag.Option);
        writer.WriteEncodedText(item.Text);
        writer.RenderEndTag();
    }

    protected override object SaveAdapterViewState()
    {
        DropDownList list = Control as DropDownList;
        object[] viewStates = new object[list.Items.Count + 2];

        int i = 0;
        foreach (ListItem item in list.Items)
            viewStates[i++] = item.Attributes[OptionGroupAttribute];

        viewStates[i++] = base.SaveAdapterViewState();
        viewStates[i] = Hash(list.Items);

        return viewStates;
    }

    private static int Hash(ListItemCollection listItems)
    {
        int hash = 0;
        foreach (ListItem listItem in listItems)
            hash += listItem.GetHashCode();

        return hash;
    }

    object[] viewStates;

    protected override void LoadAdapterViewState(object state)
    {
        viewStates = (object[])state;
        base.LoadAdapterViewState(viewStates[viewStates.Length - 1]);
    }

    protected override void OnPreRender(System.EventArgs e)
    {
        if (viewStates != null && viewStates.Length > 1)
        {
            DropDownList list = Control as DropDownList;
            if (Page.EnableEventValidation)
            {
                if (viewStates.Length != list.Items.Count + 1)
                {
                    throw new ViewStateException();
                }
            }
            if (Hash(list.Items) == (int)viewStates[viewStates.Length - 1])
            {
                int max = viewStates.Length - 2;
                if (list.Items.Count < max)
                {
                    max = list.Items.Count;
                }
                for (int i = 0; i < max; i++)
                {
                    list.Items[i].Attributes[OptionGroupAttribute] = 
                        (string)viewStates[i];
                }
            }
        }
        base.OnPreRender(e);
    }
}

浏览器文件:

<browsers>
  <browser refID="default">
    <controlAdapters>
      <adapter
          controlType="System.Web.UI.WebControls.DropDownList"
          adapterType="DropDownListAdapter" />
    </controlAdapters>
  </browser>
</browsers>

堆栈跟踪

NopSolutions.NopCommerce.Web.DropDownListAdapter.OnPreRender(EventArgs e) in ...
   // I'm guessing the issue is here
   System.Web.UI.Control.PreRenderRecursiveInternal() +8948774
   System.Web.UI.Control.PreRenderRecursiveInternal() +175
   System.Web.UI.Control.PreRenderRecursiveInternal() +175
   System.Web.UI.Control.PreRenderRecursiveInternal() +175
   System.Web.UI.Control.PreRenderRecursiveInternal() +175
   System.Web.UI.Control.PreRenderRecursiveInternal() +175
   System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint) +2496

如果有人能指出正确的方向来解决这个问题,那就太棒了。现在请不要告诉我禁用 validateRequest,因为这并不能解决问题,它只是掩盖了问题。

最佳答案

您可能已经解决了这个问题或者只是走了另一条路,但以供将来引用。

SaveAdapterViewState 中,您将状态保存到长度为 x + 2 的对象数组中:

object[] viewStates = new object[list.Items.Count + 2];

然后,在 LoadAdapterViewState 中,您使用来自 View 状态的对象数组初始化本地字段 viewStates:

viewStates = (object[])state;

最后,在 OnPreRender 中,您要确保本地字段 viewStates 的长度为 x + 1,这将失败,因为您保存了一个长度为 x + 2 的数组,这就是您从 View 状态加载它时会得到的。

关于c# - 带有 DropDownListAdapter 的 ViewStateException,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7691178/

相关文章:

c# - SqlBulkCopy 和在标识列上具有父/子关系的 DataTables

c# - 无法使用全文搜索来搜索正文

C# 与 Python 参数传递

c# - C#/ASP.NET 中的控制数组类型循环

java - Java 中动态命名类实例

c# - 帮助找到最深的拼写检查子控件

c# - 如何有条件地抑制写入事件日志的应用程序异常?

c# - 如何缩小ASPX页面

c# - ASP.NET Core 3.1 MVC 如何让用户在注册时选择自己的角色?

python - 如何使用输出缓冲控制?