ViewStateException с DropDownListAdapter - PullRequest
       6

ViewStateException с DropDownListAdapter

4 голосов
/ 07 октября 2011

Я получаю эту ошибку 500:

Sys.WebForms.PageRequestManagerServerErrorException: An unknown error occurred while processing the request on the server. The status code returned from the server was: 500

ОБНОВЛЕНИЕ:

Моя ошибка на самом деле такова: System.Web.UI.ViewStateException

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

Я получаю его с тех пор, как добавил этот адаптер на свой сайт, показанный в этом руководстве.

ASP.NET DropDownList с поддержкой OptionGroup

Он прекрасно загружает 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>

StackTrace

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, потому что это не решает проблему, а просто закрывает ее.

1 Ответ

3 голосов
/ 25 августа 2012

Вы, вероятно, уже решили эту проблему или просто пошли другим путем, но для дальнейшего использования.

В SaveAdapterViewState вы сохраняете состояние в массиве объектов длиной x + 2:

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

Затем в LoadAdapterViewState вы инициализируете локальное поле viewStates массивом объектов, поступающим из состояния просмотра:

viewStates = (object[])state;

Наконец, в OnPreRender вы гарантируете, что локальное поле viewStates имеет длину x + 1, что не удастся, потому что вы сохранили массив длины x + 2, и это то, что вы получите, когда загрузите это из состояния просмотра.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...