This is a migrated thread and some comments may be shown as answers.

Stored ViewState in database and RadGrid

2 Answers 145 Views
General Discussions
This is a migrated thread and some comments may be shown as answers.
Luca
Top achievements
Rank 1
Luca asked on 24 Jan 2013, 01:37 PM
We are trying to reduce the grid ViewState using a PageStatePersister and database.
Everything is working fine also using the advanced data-binding except for the exporting functionality (xls, pdf or csv) does not matter the format.

The exported file is correct, we ignore the paging and the whole data is saved correctly, but if we click for example on the pager, the RadGrid loses the paging and also the excel button on the command items, this happens only if we have already exported a file.

The same code without the PageStatePersister works fine.

We can't figure out where the error is, do you have any clues?

public class SqlPageStatePersister : PageStatePersister
  {
    private const string VSKEY = "__VSKEY";
    private const string VSPREFIX = "VIEWSTATE_";
 
    private static readonly PageViewStateRepository Repository = new PageViewStateRepository();
 
    public SqlPageStatePersister(Page page)
      : base(page)
    {
    }
 
    public override void Load()
    {
      if (!Page.IsPostBack) return;
 
      string vsKey = Page.Request.Form[VSKEY];
 
      // Sanity Checks
      if (string.IsNullOrEmpty(vsKey)) throw new ViewStateException();
      if (!vsKey.StartsWith(VSPREFIX)) throw new ViewStateException();
 
      IStateFormatter frmt = StateFormatter;
      string state = GetViewState(vsKey);
 
      if (string.IsNullOrEmpty(state)) return;
 
      var statePair = frmt.Deserialize(state) as Pair;
 
      if (statePair == null) return;
 
      ViewState = statePair.First;
      ControlState = statePair.Second;
    }
 
    public override void Save()
    {
      if (Page.Session == null)
        throw new InvalidOperationException("Session is required for SqlPageStatePersister (SessionID -> Key)");
 
      if (ViewState != null || ControlState != null)
      {
        string vsKey;
 
        if (!Page.IsPostBack)
        {
          string sessionId = Page.Session.SessionID;
          string pageUrl = Page.Request.Path;
          vsKey = string.Format("{0}{1}_{2}_{3}", VSPREFIX, pageUrl, sessionId, DateTime.Now.Ticks);
        }
        else
        {
          vsKey = Page.Request.Form[VSKEY];
          if (string.IsNullOrEmpty(vsKey)) throw new ViewStateException();
        }
 
        IStateFormatter frmt = StateFormatter;
        string state = frmt.Serialize(new Pair(ViewState, ControlState));
        StoreViewState(vsKey, state);
 
        Page.Cache.Add(vsKey, vsKey, null, DateTime.Now.AddMinutes(Page.Session.Timeout),
                       Cache.NoSlidingExpiration, CacheItemPriority.Low, ViewStateCacheRemoveCallback);
        Page.ClientScript.RegisterHiddenField(VSKEY, vsKey);
      }
    }
 
    #region Database
 
    private static void StoreViewState(string key, string viewStateData)
    {
      var item = new PageViewState {ID = key, Value = viewStateData, LastUpdatedOn = DateTime.Now};
      Repository.InsertOrUpdate(item);
    }
 
    private static string GetViewState(string key)
    {
      PageViewState vs = Repository.Select(key);
      if (vs != null)
        return vs.Value;
      return string.Empty;
    }
 
    private static void ViewStateCacheRemoveCallback(string key, object value, CacheItemRemovedReason reason)
    {
      Repository.Delete(Repository.Select(key));
    }
 
    #endregion
  }
}

public class SqlPageAdapter : PageAdapter
{
  public override PageStatePersister GetStatePersister()
  {
    return new SqlPageStatePersister(Page);
  }
}

<browsers>
  <browser refID="Default">
    <controlAdapters>
      <adapter
          controlType="System.Web.UI.Page"
          adapterType="DataValidator.PageState.SqlPageAdapter" />
    </controlAdapters>
  </browser>
</browsers>

<telerik:RadGrid ID="RadGrid1" runat="server" AllowFilteringByColumn="True" AllowPaging="True"
    CellSpacing="0" GridLines="None" OnNeedDataSource="NeedDataSource" AllowSorting="True"
    AutoGenerateColumns="False" OnItemDataBound="RadGrid1_ItemDataBound" EnableViewState="True"
    OnItemCommand="RadGrid1_ItemCommand">
    <MasterTableView DataKeyNames="ID" PageSize="20" CommandItemDisplay="Top" EnableViewState="True">
        <CommandItemSettings ShowAddNewRecordButton="false" ShowExportToExcelButton="true">
        </CommandItemSettings>
        <Columns>
            <telerik:GridBoundColumn DataField="Version" HeaderText="Version" SortExpression="Version"
                UniqueName="Version" FilterControlWidth="95px" />
            <telerik:GridDateTimeColumn DataField="Date" HeaderText="Date" SortExpression="Date"
                UniqueName="Date" FilterControlWidth="95px" PickerType="DatePicker" EnableTimeIndependentFiltering="true" />
            <telerik:GridBoundColumn DataField="Level" HeaderText="Level" SortExpression="Level"
                UniqueName="Level" FilterControlWidth="95px" />
            <telerik:GridBoundColumn DataField="Message" HeaderText="Type" SortExpression="Message"
                UniqueName="Message" FilterControlWidth="95px" />
            <telerik:GridBoundColumn DataField="Exception" HeaderText="Message" SortExpression="Exception"
                UniqueName="Exception">
            </telerik:GridBoundColumn>
            <telerik:GridBoundColumn DataField="UserName" HeaderText="UserName" SortExpression="UserName"
                UniqueName="UserName" FilterControlWidth="95px" />
            <telerik:GridBoundColumn DataField="Page" HeaderText="Page" SortExpression="Page"
                UniqueName="Page" FilterControlWidth="95px" />
        </Columns>
    </MasterTableView>
    <ExportSettings ExportOnlyData="true" IgnorePaging="true" OpenInNewWindow="true">
        <Excel Format="Biff"></Excel>
    </ExportSettings>
    <FilterMenu EnableImageSprites="False">
    </FilterMenu>
    <PagerStyle Mode="NumericPages"></PagerStyle>
</telerik:RadGrid>

namespace DataValidator._uc
{
  public partial class LogCtrl : UserControlHelper, IGridUserControl
  {
    protected void Page_Load(object sender, EventArgs e)
    {
    }
 
    #region Implementation of IGridUserControl
 
    public void NeedDataSource(object sender, GridNeedDataSourceEventArgs e)
    {
      var lr = new LogRepository();
      RadGrid1.DataSource = lr.Select();
    }
 
    public void UpdateCommand(object sender, GridCommandEventArgs e)
    {
    }
 
    public void DeleteCommand(object sender, GridCommandEventArgs e)
    {
    }
 
    public void InsertCommand(object sender, GridCommandEventArgs e)
    {
    }
 
    #endregion
 
    protected void RadGrid1_ItemDataBound(object sender, GridItemEventArgs e)
    {
      if (e.Item is GridDataItem)
      {
        var log = (Log) e.Item.DataItem;
        if (log != null)
        {
          string message = log.Exception;
          if (message.Length > 100)
            message = string.Format("{0}...", message.Substring(0, 46));
          e.Item.Cells[6].Wrap = false;
          e.Item.Cells[6].ToolTip = log.Exception;
          e.Item.Cells[6].Text = message;
        }
      }
    }
 
    protected void RadGrid1_ItemCommand(object sender, GridCommandEventArgs e)
    {
      if (e.CommandName == RadGrid.ExportToExcelCommandName)
      {
        PageHelper.Exporting = true;
      }
    }
  }
}

2 Answers, 1 is accepted

Sort by
0
Erin
Top achievements
Rank 1
answered on 25 Jan 2013, 08:12 PM
We are working on something very similar, and saving the ViewState on the server. 

I saw this post titled Built-In Export Issues from back in August that just recommended "removing the save/retrieve functionality [to fix] the problem" but we really would rather keep that, since it cuts our load times by 70%. 

Would someone from Telerik please look into this?
0
Luca
Top achievements
Rank 1
answered on 26 Jan 2013, 07:50 AM
Hi Erin, we have changed our PageStatePersister deriving from HiddenFieldPageStatePersister and now for us it is working properly. It adds a little bit more overhead on ViewState round trip, but it is acceptable...

using System;
using System.Web.Caching;
using System.Web.UI;
using DataValidator.Models;
using DataValidator.Repositories;
 
namespace DataValidator.PageState
{
  public class SqlPageStatePersister : HiddenFieldPageStatePersister
  {
    private static readonly PageViewStateRepository Repository = new PageViewStateRepository();
 
    public SqlPageStatePersister(Page page)
      : base(page)
    {
    }
 
    public void Deserialize(string serializedViewState)
    {
      object vsPair = StateFormatter.Deserialize(serializedViewState) as Pair;
      if (vsPair != null && (vsPair is Pair))
      {
        var myPair = vsPair as Pair;
        ViewState = myPair.First;
        ControlState = myPair.Second;
      }
      else
      {
        ViewState = vsPair;
      }
    }
 
    public string Serialize()
    {
      var vsPair = new Pair(ViewState, ControlState);
      return StateFormatter.Serialize(vsPair);
    }
 
    public override void Load()
    {
      base.Load();
      string currentViewState = ViewState.ToString();
      if (currentViewState.Length == 36)
      {
        string vs = GetViewState(currentViewState);
        Deserialize(vs);
      }
    }
 
    public override void Save()
    {
      string Id = Guid.NewGuid().ToString();
      string Data = Serialize();
      StoreViewState(Id, Data);
 
      ViewState = Id;
      ControlState = "";
 
      Page.Cache.Add(Id, Id, null, DateTime.Now.AddMinutes(Page.Session.Timeout),
                     Cache.NoSlidingExpiration, CacheItemPriority.Low, ViewStateCacheRemoveCallback);
 
      base.Save();
    }
 
    #region Database
 
    private static void StoreViewState(string key, string viewStateData)
    {
      var item = new PageViewState {ID = key, Value = viewStateData, LastUpdatedOn = DateTime.Now};
      Repository.InsertOrUpdate(item);
    }
 
    private static string GetViewState(string key)
    {
      PageViewState vs = Repository.Select(key);
      if (vs != null)
        return vs.Value;
      return string.Empty;
    }
 
    private static void ViewStateCacheRemoveCallback(string key, object value, CacheItemRemovedReason reason)
    {
      Repository.Delete(Repository.Select(key));
    }
 
    #endregion
  }
Tags
General Discussions
Asked by
Luca
Top achievements
Rank 1
Answers by
Erin
Top achievements
Rank 1
Luca
Top achievements
Rank 1
Share this question
or