Click here to Skip to main content
15,892,674 members
Articles / Web Development / ASP.NET

Manage ViewState Using ASP.NET 2.0 Provider Architecture

Rate me:
Please Sign up or sign in to vote.
3.93/5 (5 votes)
5 Jun 2007CPOL7 min read 78.4K   752   49  
Serverside ViewState management using custom providers based on ASP.NET 2.0 provider pattern architecture.
Imports System.Web.UI
Imports System.IO
Imports System.Text
Imports System.Collections.Specialized


Namespace System.Web.Configuration.Providers

	''' <summary>
	''' Manages storage of viewstate object for an ASP.NET application in a ASP.NET session object.
	''' </summary>
	''' <remarks><para><pre>
	''' RevisionHistory: 
	''' --------------------------------------------------------------------------------
	''' Date		Name			Description
	''' --------------------------------------------------------------------------------
	''' 10/11/2006	Oleg Sobol		Initial Creation, inspiration from http://www.eggheadcafe.com/articles/20040613.asp
	''' 5/11/2007	Oleg Sobol      Added ViewStateKeyName 
	''' 
	''' </pre></para></remarks>
	Public Class SessionViewStateProvider
		Inherits System.Web.UI.ViewStateProvider


		' This uses an array and mod to cycle repeatedly through an array (so limited size)

		' WARNING:  When the user uses the "back" button on the browser, IE will not rerequest the page, so 
		' if the user posts again they need the viewstate to still be present on the server.  Need to set the VIEW_STATE_NUM_PAGES
		' to a tradeoff of number of back pages allowed and the amount of memory consumed by the viewstate kept per page.  
		Private Const NUM_PAGES_IN_MEMORY As Short = 5	   ' Number of pages to keep viewstate for

		Private _applicationName As String
		Private _los As New LosFormatter
		Private _numberOfPagesInMemory As Short
		Private _pageCount As Long	' Number of pages seen by this customer
		Private _viewStateKeyName As String = "__VIEWSTATE_KEY"

#Region " Properties "

		Public Overrides Property ApplicationName() As String
			Get
				Return _applicationName
			End Get
			Set(ByVal value As String)
				_applicationName = value
			End Set
		End Property

		Public Overrides Property ViewStateKeyName() As String
			Get
				Return _viewStateKeyName
			End Get
			Set(ByVal value As String)
				_viewStateKeyName = value
			End Set
		End Property
#End Region


		Public Overloads Overrides Sub Initialize(ByVal name As String, ByVal config As NameValueCollection)
			' Verify that config isn't null
			If config Is Nothing Then Throw New ArgumentNullException("config")
			' Assign the provider a default name if it doesn't have one
			If String.IsNullOrEmpty(name) Then name = "SessionViewStateProvider"
			' Add a default "description" attribute to config if the attribute doesn�t exist or is empty
			If String.IsNullOrEmpty(config("description")) Then
				config.Remove("description")
				config.Add("description", "Session viewstate provider")
			End If
			' Call the base class's Initialize method
			MyBase.Initialize(name, config)

			' Initialize _applicationName
			_applicationName = config("applicationName")
			If String.IsNullOrEmpty(_applicationName) Then _applicationName = "/"
			config.Remove("applicationName")

			Dim numberOfPagesInMemory As String = config("numberOfPagesInMemory")
			If String.IsNullOrEmpty(numberOfPagesInMemory) OrElse Not IsNumeric(numberOfPagesInMemory) Then
				_numberOfPagesInMemory = NUM_PAGES_IN_MEMORY
			Else
				_numberOfPagesInMemory = CShort(numberOfPagesInMemory)
			End If
			config.Remove("numberOfPagesInMemory")


			' Throw an exception if unrecognized attributes remain
			If config.Count > 0 Then
				Dim attr As String = config.GetKey(0)
				If Not String.IsNullOrEmpty(attr) Then Throw New ViewStateProviderException("Unrecognized attribute: " + attr)
			End If
		End Sub


		Public Overrides Function LoadPageState(ByVal pControl As UI.Control) As Object
			Dim p As Page = CType(pControl, Page)

			If Nothing = p.Request.Form(_viewStateKeyName) Then Return Nothing


			Dim lRequestNumber As Long = 0
			Try
				lRequestNumber = Convert.ToInt64(p.Request.Form(_viewStateKeyName))
			Catch
				Return Nothing
			End Try

			' Could cycle though the array and make sure that the given request number is actually
			' present (in case the array is not big enough).  Much faster to just take the
			' given request number and recalculate where it should be stored
			Dim siIndex As Short = CType((lRequestNumber Mod _numberOfPagesInMemory), Short)

			' load viewstate from serverside storage
			Dim viewStates As String()	' Store for viewstates
			Dim viewStateKey As String = GetViewStateKey()
			If HttpContext.Current.Session.Item(viewStateKey) Is Nothing Then
				viewStates = New String(_numberOfPagesInMemory) {}
				HttpContext.Current.Session.Item(viewStateKey) = viewStates
			Else
				viewStates = CType(HttpContext.Current.Session.Item(viewStateKey), String())
			End If
			Dim viewState As String = viewStates(siIndex)


			If viewState Is Nothing Then
				Return Nothing
			Else
				Return _los.Deserialize(viewState)
			End If
		End Function


		Public Overrides Sub SavePageState(ByVal pControl As UI.Control, ByVal viewState As Object)
			' load viewstate from serverside storage
			Dim viewStates As String()	' Store for viewstates
			Dim viewStateKey As String = GetViewStateKey()
			If HttpContext.Current.Session.Item(viewStateKey) Is Nothing Then
				viewStates = New String(_numberOfPagesInMemory) {}
				HttpContext.Current.Session.Item(viewStateKey) = viewStates
			Else
				viewStates = CType(HttpContext.Current.Session.Item(viewStateKey), String())
			End If

			Dim writer As StringWriter = New StringWriter()
			_los.Serialize(writer, viewState)

			System.Math.Min(System.Threading.Interlocked.Increment(_pageCount), _pageCount - 1)
			Dim siIndex As Short = CType((_pageCount Mod _numberOfPagesInMemory), Short)
			viewStates(siIndex) = writer.ToString
			writer.Dispose()

			' Need to register the viewstate hidden field 
			' (must be present or postback things don't work, we use in our case to store the request number)
			CType(pControl, Page).ClientScript.RegisterHiddenField(_viewStateKeyName, _pageCount.ToString)
		End Sub


		''' <summary>
		''' Gets the key for ViewState from each separate session based on SessionID
		''' </summary>
		''' <returns>ViewState key in Session storage</returns>
		''' <remarks></remarks>
		Private Function GetViewStateKey() As String
			Return "__VIEWSTATE" & HttpContext.Current.Session.SessionID.ToString
		End Function

	End Class



End Namespace

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Web Developer
United States United States
Oleg Sobol has been developing web applications in ASP.NET using VB.NET for the past three years. Currently working for a leading online higher education provider, developing new online initiatives and supporting multiple education platforms.

Comments and Discussions