Stored ViewState in database and RadGrid

3 posts, 0 answers
  1. Luca
    Luca avatar
    2 posts
    Member since:
    Nov 2011

    Posted 24 Jan 2013 Link to this post

    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. Erin
    Erin avatar
    11 posts
    Member since:
    Jun 2012

    Posted 25 Jan 2013 Link to this post

    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?
  3. Luca
    Luca avatar
    2 posts
    Member since:
    Nov 2011

    Posted 26 Jan 2013 Link to this post

    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
      }
Back to Top