使用自定义PageStatePersister

时间:2019-05-16 07:00:21

标签: c# webforms session-state

我们有一个使用Webforms的网站。我们要使用自定义的PageStatePersister,它将viewstate保存到redis缓存中(请参见下面的代码)。在页面级别,我们重写PageStatePersister属性以使用我们的PageStatePersister。到目前为止,一切工作正常,但是当我们在另一个控件中拥有一个控件时,我们会遇到一些问题。

   public class RedisPageStatePersister : PageStatePersister
    {
        const string ViewStateFieldName = "__VIEWSTATEKEY";
        const string ViewStateKeyPrefix = "ViewState_";

        public RedisPageStatePersister(Page page) : base(page)
        {
        }



        public override void Load()
        {
            var key = Page.UniqueID;


            // The cache key for this viewstate is stored in a hidden field, so grab it
            string viewStateKey = Page.Request.Form[ViewStateFieldName] as string;

            // Grab the viewstate data using the key to look it up
            if (viewStateKey != null)
            {
                var database = RedisConnectorHelper.Connection.GetDatabase(1);

                var viewstate = database.StringGet(viewStateKey);

                if (!viewstate.IsNull)
                {
                    Pair p = (Pair)StateFormatter.Deserialize(database.StringGet(viewStateKey));

                    ViewState = p.First;
                    ControlState = p.Second;
                }
            }
        }

        public override void Save()
        {
            string viewStateKey = Page.Request.Form[ViewStateFieldName] as string;

            if (viewStateKey == null)
            {
                viewStateKey = ViewStateKeyPrefix + Guid.NewGuid().ToString();
            }

            // Put viewstate data on writer
            var viewStateSerialized = StateFormatter.Serialize(new Pair(base.ViewState, base.ControlState));

            // Store the viewstate's key in a hidden field, so on postback we can grab it from the cache
            Page.ClientScript.RegisterHiddenField(ViewStateFieldName, viewStateKey);

            // Get the Redis database
            var database = RedisConnectorHelper.Connection.GetDatabase(1);

            // Save viewstate to the database
            database.StringSet(viewStateKey, viewStateSerialized, TimeSpan.FromMinutes(15));
        }
    }

例如:

  • 使用ListViews时。我们在另一个ListView中有一个带有DataKeys的ListView。回发时,不会为嵌套的ListView还原数据键
    <asp:ListView runat="server" ID="lvOuter" DataKeyNames="These,Keys,Work">
        <ItemTemplate>
            <asp:ListView runat="server" ID="lvInner" DataKeyNames="These,Keys,Dont,Work">
                <ItemTemplate></ItemTemplate>
            </asp:ListView>
        </ItemTemplate>
    </asp:ListView>
  • 我们使用带有GridView的动态创建TabPanel。 GridView中的数据键值在回发时会丢失

似乎只是DataKeys遇到了问题,例如使用HiddenField没问题。

我也尝试使用SessionPageStatePersister,因为这是一个内置的持久性,但是这里也会出现问题

下面的代码段中,虚拟数据已绑定到列表视图及其内部列表视图。单击按钮并尝试检索内部列表视图的数据键值时,将发生错误。属性“ DataKeys”是一个空列表,因此将引发IndexOutOfRangeException。

    public partial class InnerListViewTest : Page
    {
        public class Outer
        {
            public List<Inner> Inner { get; set; }

            public string Key1 { get; set; }

            public string Key2 { get; set; }
        }

        public class Inner
        {
            public string InnerKey1 { get; set; }
            public string InnerKey2 { get; set; }
        }

        protected void Page_Load(object sender, EventArgs e)
        {

            if (!IsPostBack)
            {
                var data = new List<Outer>();
                for (int i = 0; i < 5; i++)
                {
                    data.Add(new Outer()
                    {
                        Inner = new List<Inner>()
                        {
                            new Inner() {
                                InnerKey1 = "InnerData1_" + i,
                                InnerKey2 = "InnerData2_" + i
                            },
                            new Inner() {
                                InnerKey1 = "InnerData3_" + i,
                                InnerKey2 = "InnerData4_" + i
                            },
                            new Inner() {
                                InnerKey1 = "InnerData5_" + i,
                                InnerKey2 = "InnerData6_" + i
                            }
                        },
                        Key1 = "Data1_" + i,
                        Key2 = "Data2_" + i
                    });
                }

                lvOuter.DataSource = data;
                lvOuter.DataBind();
            }
        }

        protected void lvOuter_ItemDataBound(object sender, ListViewItemEventArgs e)
        {
            var outerData = e.Item.DataItem as Outer;

            var lvInner = e.Item.FindControl("lvInner") as ListView;
            lvInner.DataSource = outerData.Inner;
            lvInner.DataBind();
        }

        protected void Unnamed_Click(object sender, EventArgs e)
        {
            foreach (ListViewItem outerItem in lvOuter.Items)
            {
                var lvInner = outerItem.FindControl("lvInner") as ListView;

                foreach (ListViewItem innerItem in lvInner.Items)
                {
                    var innerKey1 = lvInner.DataKeys[innerItem.DataItemIndex]["InnerKey1"];
                    var innerKey2 = lvInner.DataKeys[innerItem.DataItemIndex]["InnerKey2"];

                }
            }
        }
    }

问题可能出在pagepersister,但我似乎找不到原因!

1 个答案:

答案 0 :(得分:1)

我已经找到了自己的答案!必须使用PageAdapter启用PageStatePersister,而不是覆盖Page的属性!