我们有一个使用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));
}
}
例如:
<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>
似乎只是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,但我似乎找不到原因!
答案 0 :(得分:1)
我已经找到了自己的答案!必须使用PageAdapter启用PageStatePersister,而不是覆盖Page的属性!