У нас есть веб-сайт, использующий Webforms. Мы хотим использовать пользовательский PageStatePersister, который сохраняет состояние просмотра в кэш 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>
- Мы используем динамическое создание TabPanel с GridView внутри. GridView внутри теряет свои значения datakeys при обратной передаче
Проблема, похоже, возникает только для DataKeys, например, использование HiddenField не является проблемой.
Я также пытался использовать SessionPageStatePersister, поскольку это встроенный персистер, но и здесь возникает проблема
Ниже фрагмента кода, где фиктивные данные связаны с представлением списка и его внутренним представлением списка. Ошибка возникает при нажатии на кнопку и попытке извлечь значения datakey из внутреннего списка. Свойство «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"];
}
}
}
}
Проблема, вероятно, связана со страницей, но я не могу понять, почему!