536cd135cc
Former-commit-id: 5624ac747d633e885131e8349322922b6a59baaa
286 lines
9.3 KiB
C#
286 lines
9.3 KiB
C#
//------------------------------------------------------------------------------
|
|
// <copyright file="SessionViewState.cs" company="Microsoft">
|
|
// Copyright (c) Microsoft Corporation. All rights reserved.
|
|
// </copyright>
|
|
//------------------------------------------------------------------------------
|
|
|
|
using System;
|
|
using System.Collections;
|
|
using System.Diagnostics;
|
|
using System.ComponentModel;
|
|
using System.Globalization;
|
|
using System.IO;
|
|
using System.Runtime.Serialization;
|
|
using System.Text;
|
|
using System.Web;
|
|
using System.Web.SessionState;
|
|
using System.Web.Util;
|
|
using System.Web.UI;
|
|
using System.Security.Permissions;
|
|
|
|
namespace System.Web.UI.MobileControls
|
|
{
|
|
/*
|
|
* Session-based view state.
|
|
*
|
|
* When saving view state on the server as session data, some critical problems
|
|
* arise. The core issue behind most of these is how to handle the user
|
|
* clicking the Back button. When the user does this, there is no corresponding
|
|
* notification to the server, and the client and server session state are thrown
|
|
* out of sync.
|
|
*
|
|
* This class attempts to alleviate this by storing a small history of view states
|
|
* in session data.
|
|
*
|
|
* To save session view state, construct a new object, set the ViewState and ActiveForm
|
|
* properties, and call Save. You'll get back a reference that contains the
|
|
* state reference to write out.
|
|
*
|
|
* To load session view state, construct a new object, and call Load. The class will
|
|
* attempt to construct the view state from its history.
|
|
*
|
|
* Copyright (c) 2000 Microsoft Corporation
|
|
*/
|
|
|
|
[Obsolete("The System.Web.Mobile.dll assembly has been deprecated and should no longer be used. For information about how to develop ASP.NET mobile applications, see http://go.microsoft.com/fwlink/?LinkId=157231.")]
|
|
internal class SessionViewState
|
|
{
|
|
private static readonly String ViewStateKey = "ViewState";
|
|
private Object _state;
|
|
|
|
internal SessionViewState() {
|
|
}
|
|
|
|
internal /*public*/ Object ViewState
|
|
{
|
|
get
|
|
{
|
|
return _state;
|
|
}
|
|
set
|
|
{
|
|
_state = value;
|
|
}
|
|
}
|
|
|
|
internal /*public*/ Pair Save(MobilePage page)
|
|
{
|
|
SessionViewStateHistory history = (SessionViewStateHistory)page.Session[ViewStateKey];
|
|
if (history == null)
|
|
{
|
|
history = new SessionViewStateHistory(HttpContext.Current);
|
|
page.Session[ViewStateKey] = history;
|
|
}
|
|
|
|
SessionViewStateHistoryItem historyItem = new SessionViewStateHistoryItem();
|
|
SaveTo(historyItem);
|
|
#if TRACE
|
|
historyItem.Url = page.Request.FilePath;
|
|
#endif
|
|
return history.Push(historyItem);
|
|
}
|
|
|
|
internal /*public*/ void Load(MobilePage page, Pair id)
|
|
{
|
|
_state = null;
|
|
|
|
SessionViewStateHistory history = (SessionViewStateHistory)page.Session[ViewStateKey];
|
|
if (history != null)
|
|
{
|
|
SessionViewStateHistoryItem historyItem = history.Find(id);
|
|
if (historyItem != null)
|
|
{
|
|
LoadFrom(historyItem);
|
|
}
|
|
}
|
|
}
|
|
|
|
private void SaveTo(SessionViewStateHistoryItem historyItem)
|
|
{
|
|
historyItem.ViewState = _state;
|
|
}
|
|
|
|
private void LoadFrom(SessionViewStateHistoryItem historyItem)
|
|
{
|
|
_state = historyItem.ViewState;
|
|
}
|
|
|
|
#if TRACE
|
|
internal /*public*/ void Dump(MobilePage page, out ArrayList arr)
|
|
{
|
|
SessionViewStateHistory history;
|
|
if ((page is IRequiresSessionState) && !(page is IReadOnlySessionState))
|
|
{
|
|
history = (SessionViewStateHistory)page.Session[ViewStateKey];
|
|
}
|
|
else
|
|
{
|
|
history = null;
|
|
}
|
|
|
|
if (history != null)
|
|
{
|
|
history.Dump(out arr);
|
|
}
|
|
else
|
|
{
|
|
arr = new ArrayList();
|
|
}
|
|
}
|
|
#endif
|
|
|
|
[
|
|
Serializable
|
|
]
|
|
private class SessionViewStateHistoryItem : ISerializable
|
|
{
|
|
#if TRACE
|
|
public String Url;
|
|
public String Id;
|
|
#endif
|
|
public Object ViewState;
|
|
|
|
public SessionViewStateHistoryItem()
|
|
{
|
|
}
|
|
|
|
public SessionViewStateHistoryItem(SerializationInfo info, StreamingContext context)
|
|
{
|
|
String s = (String)info.GetString("s");
|
|
if (s.Length > 0)
|
|
{
|
|
ViewState = new LosFormatter().Deserialize(s);
|
|
}
|
|
else
|
|
{
|
|
ViewState = null;
|
|
}
|
|
}
|
|
|
|
[SecurityPermissionAttribute(SecurityAction.Demand, SerializationFormatter=true)]
|
|
void ISerializable.GetObjectData(SerializationInfo info, StreamingContext context)
|
|
{
|
|
if (ViewState != null)
|
|
{
|
|
StringWriter s = new StringWriter(CultureInfo.InvariantCulture);
|
|
new LosFormatter().Serialize(s, ViewState);
|
|
info.AddValue("s", s.ToString());
|
|
}
|
|
else
|
|
{
|
|
info.AddValue("s", String.Empty);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Session view state history. This is the history record kept in each session.
|
|
|
|
[
|
|
Serializable
|
|
]
|
|
private class SessionViewStateHistory
|
|
{
|
|
private int _historySize;
|
|
private SessionViewStateHistoryItem[] _history;
|
|
private int _currentHistoryIndex = 0;
|
|
private int _historyUsed = 0;
|
|
private DateTime _sessionUniqueID = DateTime.Now;
|
|
private int _currentHistoryID = 0;
|
|
|
|
public SessionViewStateHistory(HttpContext context)
|
|
{
|
|
_historySize = ControlsConfig.GetFromContext(context).SessionStateHistorySize;
|
|
if (_historySize < 1)
|
|
{
|
|
throw new Exception(
|
|
SR.GetString(SR.SessionViewState_InvalidSessionStateHistory));
|
|
}
|
|
|
|
_history = new SessionViewStateHistoryItem[_historySize];
|
|
}
|
|
|
|
public Pair Push(SessionViewStateHistoryItem item)
|
|
{
|
|
Pair id = new Pair(_sessionUniqueID, _currentHistoryID);
|
|
_currentHistoryID++;
|
|
|
|
_history[_currentHistoryIndex] = item;
|
|
_currentHistoryIndex = (_currentHistoryIndex + 1) % _historySize;
|
|
if (_historyUsed < _historySize)
|
|
{
|
|
_historyUsed++;
|
|
}
|
|
|
|
#if TRACE
|
|
item.Id = _currentHistoryID.ToString(CultureInfo.InvariantCulture);
|
|
#endif
|
|
|
|
return id;
|
|
}
|
|
|
|
public SessionViewStateHistoryItem Find(Pair id)
|
|
{
|
|
// First make sure that the page is from the current session.
|
|
DateTime uniqueID = (DateTime) id.First;
|
|
if (DateTime.Compare(uniqueID, _sessionUniqueID) != 0)
|
|
{
|
|
return null;
|
|
}
|
|
|
|
// Now check if we actually still have it.
|
|
int historyID = (int) id.Second;
|
|
int distance = _currentHistoryID - historyID;
|
|
|
|
if (distance <= 0)
|
|
{
|
|
// Shouldn't happen, but this would be a forward jump.
|
|
return null;
|
|
}
|
|
else if (distance > _historyUsed)
|
|
{
|
|
// Gone way back. Empty history, but return null.
|
|
_historyUsed = 0;
|
|
return null;
|
|
}
|
|
else
|
|
{
|
|
int foundIndex = (_currentHistoryIndex + _historySize - distance) %
|
|
_historySize;
|
|
// Make the found item the top of the stack.
|
|
_currentHistoryIndex = (foundIndex + 1) % _historySize;
|
|
_currentHistoryID = historyID + 1;
|
|
_historyUsed -= distance - 1;
|
|
return _history[foundIndex];
|
|
}
|
|
}
|
|
|
|
#if TRACE
|
|
public void Dump(out ArrayList arr)
|
|
{
|
|
arr = new ArrayList();
|
|
int n = _currentHistoryIndex;
|
|
for (int i = 0; i < _historyUsed; i++)
|
|
{
|
|
n = n - 1;
|
|
if (n == -1)
|
|
{
|
|
n = _history.Length - 1;
|
|
}
|
|
|
|
SessionViewStateHistoryItem item = _history[n];
|
|
if (item != null)
|
|
{
|
|
arr.Add(String.Format(CultureInfo.InvariantCulture, "{0}({1})", item.Url, item.Id));
|
|
}
|
|
else
|
|
{
|
|
arr.Add("(null)");
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
|
|
}
|
|
}
|