Export (0) Print
Expand All

How to: Sample Session-State Store Provider 

Demonstrates a session-state store provider implementation.

The following code example program shows how to implement a session-state store provider. For details about how to build this provider and use it in an ASP.NET application, see Sample Session-State Store Provider.

Example

Imports System
Imports System.Web
Imports System.Web.Configuration
Imports System.Configuration
Imports System.Collections.Specialized
Imports System.Web.SessionState
Imports System.Data
Imports System.Data.Odbc
Imports System.Diagnostics
Imports System.IO


' This session state store provider supports the following schema:
' 
'   CREATE TABLE Sessions
'   (
'     SessionId       Text(80)  NOT NULL,
'     ApplicationName Text(255) NOT NULL,
'     Created         DateTime  NOT NULL,
'     Expires         DateTime  NOT NULL,
'     LockDate        DateTime  NOT NULL,
'     LockId          Integer   NOT NULL,
'     Timeout         Integer   NOT NULL,
'     Locked          YesNo     NOT NULL,
'     SessionItems    Memo,
'     Flags           Integer   NOT NULL,
'       CONSTRAINT PKSessions PRIMARY KEY (SessionId, ApplicationName)
'   )
' 
' This session state store provider does not automatically clean up 
' expired session item data. It is recommended
' that you periodically delete expired session information from the
' data store with the following code (where 'conn' is the OdbcConnection
' for the session state store provider):
' 
'   Dim commandString As String = "DELETE FROM Sessions WHERE Expires < ?"
'   Dim conn As OdbcConnection = New OdbcConnection(connectionString)
'   Dim cmd As OdbcCommand = New OdbcCommand(commandString, conn)
'   cmd.Parameters.Add("@Expires", OdbcType.DateTime).Value = DateTime.Now
'   conn.Open()
'   cmd.ExecuteNonQuery()
'   conn.Close()


Namespace Samples.AspNet.Session

  Public NotInheritable Class OdbcSessionStateStore
    Inherits SessionStateStoreProviderBase

    Private pConfig As SessionStateSection = Nothing
    Private connectionString As String
    Private pConnectionStringSettings As ConnectionStringSettings 
    Private eventSource As String = "OdbcSessionStateStore"
    Private eventLog As String = "Application"
    Private exceptionMessage As String = _
      "An exception occurred. Please contact your administrator."
    Private pApplicationName As String


    '
    ' If False, exceptions are thrown to the caller. If True,
    ' exceptions are written to the event log.
    '

    Private pWriteExceptionsToEventLog As Boolean = False

    Public Property WriteExceptionsToEventLog As Boolean
      Get
        Return pWriteExceptionsToEventLog
      End Get
      Set
        pWriteExceptionsToEventLog = value
      End Set
    End Property


    '
    ' The ApplicationName property is used to differentiate sessions
    ' in the data source by application.
    '

    Public ReadOnly Property ApplicationName As String
      Get
        Return pApplicationName
      End Get
    End Property


    '
    ' ProviderBase members
    '


    Public Overrides Sub Initialize(name As String, config As NameValueCollection)

      '
      ' Initialize values from web.config.
      '

      If config Is Nothing Then _
        Throw New ArgumentNullException("config")

      If name Is Nothing OrElse name.Length = 0 Then _
        name = "OdbcSessionStateStore"

      If String.IsNullOrEmpty(config("description")) Then
        config.Remove("description")
        config.Add("description", "Sample ODBC Session State Store provider")
      End If

      ' Initialize the abstract base class.
      MyBase.Initialize(name, config)


      '
      ' Initialize the ApplicationName property.
      '

      pApplicationName = _
        System.Web.Hosting.HostingEnvironment.ApplicationVirtualPath


      '
      ' Get <sessionState> configuration element.
      '
    
      Dim cfg As System.Configuration.Configuration = _
        WebConfigurationManager.OpenWebConfiguration(ApplicationName)
      pConfig = _
        CType(cfg.GetSection("system.web/sessionState"), SessionStateSection)

      
      '
      ' Initialize OdbcConnection.
      '

      pConnectionStringSettings = _
        ConfigurationManager.ConnectionStrings(config("connectionStringName"))

      If pConnectionStringSettings Is Nothing OrElse _
        pConnectionStringSettings.ConnectionString.Trim() = "" Then
      
        Throw New HttpException("Connection string cannot be blank.")
      End If

      connectionString = pConnectionStringSettings.ConnectionString


      '
      ' Initialize WriteExceptionsToEventLog
      '

      pWriteExceptionsToEventLog = False

      If Not config("writeExceptionsToEventLog") Is Nothing Then      
        If config("writeExceptionsToEventLog").ToUpper() = "TRUE" Then _
          pWriteExceptionsToEventLog = True
      End If
    End Sub


    '
    ' SessionStateStoreProviderBase members
    '

    Public Overrides Sub Dispose()
    
    End Sub


    '
    ' SessionStateProviderBase.SetItemExpireCallback
    '

    Public Overrides Function SetItemExpireCallback( _
      expireCallback As SessionStateItemExpireCallback) As Boolean
    
      Return False
    End Function


    '
    ' SessionStateProviderBase.SetAndReleaseItemExclusive
    '

    Public Overrides Sub SetAndReleaseItemExclusive(context As HttpContext, _
      id As String, _
      item As SessionStateStoreData, _
      lockId As Object, _
      newItem As Boolean)                                           
    
      ' Serialize the SessionStateItemCollection as a string.
      Dim sessItems As String = Serialize(CType(item.Items, SessionStateItemCollection))

      Dim conn As OdbcConnection = New OdbcConnection(connectionString)
      Dim cmd As OdbcCommand
      Dim deleteCmd As OdbcCommand = Nothing

      If newItem Then      
        ' OdbcCommand to clear an existing expired session if it exists.
        deleteCmd = New OdbcCommand("DELETE FROM Sessions " & _
          "WHERE SessionId = ? AND ApplicationName = ? AND Expires < ?", conn)
        deleteCmd.Parameters.Add("@SessionId", OdbcType.VarChar, 80).Value = id
        deleteCmd.Parameters.Add( _
          "@ApplicationName", OdbcType.VarChar, 255).Value = ApplicationName
        deleteCmd.Parameters.Add( _
          "@Expires", OdbcType.DateTime).Value = DateTime.Now

        ' OdbcCommand to insert the New session item.
        cmd = New OdbcCommand("INSERT INTO Sessions " & _
          " (SessionId, ApplicationName, Created, Expires, " & _
          "  LockDate, LockId, Timeout, Locked, SessionItems, Flags) " & _
          " Values(?, ?, ?, ?, ?, ? , ?, ?, ?, ?)", conn)
        cmd.Parameters.Add("@SessionId", OdbcType.VarChar, 80).Value = id
        cmd.Parameters.Add( _
          "@ApplicationName", OdbcType.VarChar, 255).Value = ApplicationName
        cmd.Parameters.Add( _
          "@Created", OdbcType.DateTime).Value = DateTime.Now
        cmd.Parameters.Add( _
          "@Expires", OdbcType.DateTime).Value = DateTime.Now.AddMinutes(CDbl(item.Timeout))
        cmd.Parameters.Add( _
          "@LockDate", OdbcType.DateTime).Value = DateTime.Now
        cmd.Parameters.Add("@LockId", OdbcType.Int).Value = 0
        cmd.Parameters.Add( _
          "@Timeout", OdbcType.Int).Value = item.Timeout
        cmd.Parameters.Add("@Locked", OdbcType.Bit).Value = False
        cmd.Parameters.Add( _
          "@SessionItems", OdbcType.VarChar, sessItems.Length).Value = sessItems
        cmd.Parameters.Add("@Flags", OdbcType.Int).Value = 0
      Else
      
        ' OdbcCommand to update the existing session item.
        cmd = New OdbcCommand( _
          "UPDATE Sessions SET Expires = ?, SessionItems = ?, Locked = ? " & _
          " WHERE SessionId = ? AND ApplicationName = ? AND LockId = ?", conn)
        cmd.Parameters.Add("@Expires", OdbcType.DateTime).Value = _
          DateTime.Now.AddMinutes(CDbl(item.Timeout))
        cmd.Parameters.Add("@SessionItems", _
          OdbcType.VarChar, sessItems.Length).Value = sessItems
        cmd.Parameters.Add("@Locked", OdbcType.Bit).Value = False
        cmd.Parameters.Add("@SessionId", OdbcType.VarChar, 80).Value = id
        cmd.Parameters.Add( _
          "@ApplicationName", OdbcType.VarChar, 255).Value = ApplicationName
        cmd.Parameters.Add("@LockId", OdbcType.Int).Value = lockId
      End If

      Try
        conn.Open()

        If Not deleteCmd Is Nothing Then _
          deleteCmd.ExecuteNonQuery()

        cmd.ExecuteNonQuery()
      Catch e As OdbcException
        If WriteExceptionsToEventLog Then
          WriteToEventLog(e, "SetAndReleaseItemExclusive")
          Throw New Exception(exceptionMessage)
        Else
          Throw e
        End If
      Finally
        conn.Close()
      End Try
    End Sub


    '
    ' SessionStateProviderBase.GetItem
    '

    Public Overrides Function GetItem(context As HttpContext, _
      id As String, _
      ByRef locked As Boolean, _
      ByRef lockAge As TimeSpan, _
      ByRef lockId As Object, _
      ByRef actionFlags As SessionStateActions) _
      As SessionStateStoreData 
    
      Return GetSessionStoreItem(False, context, id, locked, lockAge, lockId, actionFlags)
    End Function


    '
    ' SessionStateProviderBase.GetItemExclusive
    '

    Public Overrides Function GetItemExclusive(context As HttpContext, _
      id As String, _
      ByRef locked As Boolean, _
      ByRef lockAge As TimeSpan, _
      ByRef lockId As Object, _
      ByRef actionFlags As SessionStateActions) _
      As SessionStateStoreData 
    
      Return GetSessionStoreItem(True, context, id, locked, lockAge, lockId, actionFlags)
    End Function


    '
    ' GetSessionStoreItem is called by both the GetItem and 
    ' GetItemExclusive methods. GetSessionStoreItem retrieves the 
    ' session data from the data source. If the lockRecord parameter
    ' is True (in the case of GetItemExclusive), then GetSessionStoreItem
    ' locks the record and sets a New LockId and LockDate.
    '

    Private Function GetSessionStoreItem(lockRecord As Boolean, _
      context As HttpContext,  _
      id As String, _
      ByRef locked As Boolean, _
      ByRef lockAge As TimeSpan, _
      ByRef lockId As Object, _
      ByRef actionFlags As SessionStateActions) _
      As SessionStateStoreData 
    
      ' Initial values for Return value and out parameters.
      Dim item As SessionStateStoreData = Nothing
      lockAge = TimeSpan.Zero
      lockId = Nothing
      locked = False
      actionFlags = 0

      ' Connection to ODBC database.
      Dim conn As OdbcConnection = New OdbcConnection(connectionString)
      ' OdbcCommand for database commands.
      Dim cmd As OdbcCommand = Nothing              
      ' DataReader to read database record.
      Dim reader As OdbcDataReader = Nothing  
      ' DateTime to check if current session item is expired.
      Dim expires As DateTime         
      ' String to hold serialized SessionStateItemCollection.
      Dim serializedItems As String = ""
      ' True if a record is found in the database.
      Dim foundRecord As Boolean = False    
      ' True if the returned session item is expired and needs to be deleted.
      Dim deleteData As Boolean = False             
      ' Timeout value from the data store.
      Dim timeout As Integer = 0               

      Try
        conn.Open()

        ' lockRecord is True when called from GetItemExclusive and
        ' False when called from GetItem.
        ' Obtain a lock if possible. Ignore the record if it is expired.
        If lockRecord Then        
          cmd = New OdbcCommand( _
            "UPDATE Sessions SET" & _
            " Locked = ?, LockDate = ? " & _
            " WHERE SessionId = ? AND ApplicationName = ? AND Locked = ? AND Expires > ?", conn)
          cmd.Parameters.Add("@Locked", OdbcType.Bit).Value = True
          cmd.Parameters.Add("@LockDate", OdbcType.DateTime).Value = _
            DateTime.Now
          cmd.Parameters.Add("@SessionId", OdbcType.VarChar, 80).Value = id
          cmd.Parameters.Add("@ApplicationName", OdbcType.VarChar, _
            255).Value = ApplicationName
          cmd.Parameters.Add("@Locked", OdbcType.Int).Value = False
          cmd.Parameters.Add( _
            "@Expires", OdbcType.DateTime).Value = DateTime.Now

          If cmd.ExecuteNonQuery() = 0 Then
            ' No record was updated because the record was locked or not found.
            locked = True             
          Else
            ' The record was updated.
            locked = False
          End If
        End If

        ' Retrieve the current session item information.
        cmd = New OdbcCommand( _
          "SELECT Expires, SessionItems, LockId, LockDate, Flags, Timeout " & _
          "  FROM Sessions " & _
          "  WHERE SessionId = ? AND ApplicationName = ?", conn)
        cmd.Parameters.Add("@SessionId", OdbcType.VarChar, 80).Value = id
        cmd.Parameters.Add("@ApplicationName", OdbcType.VarChar, _
          255).Value = ApplicationName

        ' Retrieve session item data from the data source.
        reader = cmd.ExecuteReader(CommandBehavior.SingleRow)

        Do While reader.Read()        
          expires = reader.GetDateTime(0)

          If expires < DateTime.Now Then          
            ' The record was expired. Mark it as not locked.
            locked = False     
            ' The session was expired. Mark the data for deletion.
            deleteData = True
          Else
            foundRecord = True
          End If

          serializedItems = reader.GetString(1)
          lockId = reader.GetInt32(2)
          lockAge = DateTime.Now.Subtract(reader.GetDateTime(3))
          actionFlags = CType(reader.GetInt32(4), SessionStateActions)
          timeout = reader.GetInt32(5)
        Loop

        reader.Close()


        ' If the returned session item is expired, 
        ' delete the record from the data source.
        If deleteData Then        
          cmd = New OdbcCommand("DELETE FROM Sessions " & _
            "WHERE SessionId = ? AND ApplicationName = ?", conn)
          cmd.Parameters.Add("@SessionId", OdbcType.VarChar, 80).Value = id
          cmd.Parameters.Add("@ApplicationName", OdbcType.VarChar, _
            255).Value = ApplicationName

          cmd.ExecuteNonQuery()
        End If

        ' The record was not found. Ensure that locked is False.
        If Not foundRecord Then _
          locked = False
        
        ' If the record was found and you obtained a lock, then set 
        ' the lockId, clear the actionFlags,
        ' and create the SessionStateStoreItem to return.
        If foundRecord AndAlso Not locked Then        
          lockId = CInt(lockId) + 1

          cmd = New OdbcCommand("UPDATE Sessions SET" & _
            " LockId = ?, Flags = 0 " & _
            " WHERE SessionId = ? AND ApplicationName = ?", conn)
          cmd.Parameters.Add("@LockId", OdbcType.Int).Value = lockId
          cmd.Parameters.Add("@SessionId", OdbcType.VarChar, 80).Value = id
          cmd.Parameters.Add("@ApplicationName", OdbcType.VarChar, 255).Value = ApplicationName

          cmd.ExecuteNonQuery()

          ' If the actionFlags parameter is not InitializeItem, 
          ' deserialize the stored SessionStateItemCollection.
          If actionFlags = SessionStateActions.InitializeItem Then
            item = CreateNewStoreData(context, pConfig.Timeout.Minutes)
          Else
            item = Deserialize(context, serializedItems, timeout)
          End If
        End If
      Catch e As OdbcException
        If WriteExceptionsToEventLog Then
          WriteToEventLog(e, "GetSessionStoreItem")
          Throw New Exception(exceptionMessage)
        Else
          Throw e
        End If
      Finally
        If Not reader Is Nothing Then reader.Close()
        conn.Close()
      End Try

      Return item
    End Function




    '
    ' Serialize is called by the SetAndReleaseItemExclusive method to 
    ' convert the SessionStateItemCollection into a Base64 string to    
    ' be stored in an Access Memo field.
    '

    Private Function Serialize(items As SessionStateItemCollection) As String
      Dim ms As MemoryStream = New MemoryStream()
      Dim writer As BinaryWriter = New BinaryWriter(ms)

      If Not items Is Nothing Then _
        items.Serialize(writer)

      writer.Close()

      Return Convert.ToBase64String(ms.ToArray())
    End Function

    '
    ' Deserialize is called by the GetSessionStoreItem method to 
    ' convert the Base64 string stored in the Access Memo field to a 
    ' SessionStateItemCollection.
    '

    Private Function Deserialize(context As HttpContext, _
      serializedItems As String, timeout As Integer) As SessionStateStoreData
    
      Dim ms As MemoryStream = _
        New MemoryStream(Convert.FromBase64String(serializedItems))

      Dim sessionItems As SessionStateItemCollection = _
        New SessionStateItemCollection()

      If ms.Length > 0 Then
        Dim reader As BinaryReader = New BinaryReader(ms)
        sessionItems = SessionStateItemCollection.Deserialize(reader)
      End If

      Return New SessionStateStoreData(sessionItems, _
        SessionStateUtility.GetSessionStaticObjects(context), _
        timeout)
    End Function

    '
    ' SessionStateProviderBase.ReleaseItemExclusive
    '

    Public Overrides Sub ReleaseItemExclusive(context As HttpContext, _
      id As String, _
      lockId As Object)
    
      Dim conn As OdbcConnection = New OdbcConnection(connectionString)
      Dim cmd As OdbcCommand = _
        New OdbcCommand("UPDATE Sessions SET Locked = 0, Expires = ? " & _
        "WHERE SessionId = ? AND ApplicationName = ? AND LockId = ?", conn)
      cmd.Parameters.Add("@Expires", OdbcType.DateTime).Value = _
        DateTime.Now.AddMinutes(pConfig.Timeout.Minutes)
      cmd.Parameters.Add("@SessionId", OdbcType.VarChar, 80).Value = id
      cmd.Parameters.Add("@ApplicationName", OdbcType.VarChar, _
        255).Value = ApplicationName
      cmd.Parameters.Add("@LockId", OdbcType.Int).Value = lockId

      Try
        conn.Open()

        cmd.ExecuteNonQuery()
      Catch e As OdbcException
        If WriteExceptionsToEventLog Then
          WriteToEventLog(e, "ReleaseItemExclusive")
          Throw New Exception(exceptionMessage)
        Else
          Throw e
        End If
      Finally
        conn.Close()
      End Try    
    End Sub


    '
    ' SessionStateProviderBase.RemoveItem
    '

    Public Overrides Sub RemoveItem(context As HttpContext, _
      id As String, _
      lockId As Object, _
      item As SessionStateStoreData)
    
      Dim conn As OdbcConnection = New OdbcConnection(connectionString)
      Dim cmd As OdbcCommand = New OdbcCommand("DELETE * FROM Sessions " & _
        "WHERE SessionId = ? AND ApplicationName = ? AND LockId = ?", conn)
      cmd.Parameters.Add("@SessionId", OdbcType.VarChar, 80).Value = id
      cmd.Parameters.Add("@ApplicationName", OdbcType.VarChar, _
        255).Value = ApplicationName
      cmd.Parameters.Add("@LockId", OdbcType.Int).Value = lockId

      Try
        conn.Open()

        cmd.ExecuteNonQuery()
      Catch e As OdbcException
        If WriteExceptionsToEventLog Then
          WriteToEventLog(e, "RemoveItem")
          Throw New Exception(exceptionMessage)
        Else
          Throw e
        End If
      Finally
        conn.Close()
      End Try
    End Sub



    '
    ' SessionStateProviderBase.CreateUninitializedItem
    '

    Public Overrides Sub CreateUninitializedItem(context As HttpContext, _
      id As String, _
      timeout As Integer)
    
      Dim conn As OdbcConnection = New OdbcConnection(connectionString)
      Dim cmd As OdbcCommand = New OdbcCommand("INSERT INTO Sessions " & _
         " (SessionId, ApplicationName, Created, Expires, " & _
         "  LockDate, LockId, Timeout, Locked, SessionItems, Flags) " & _
         " Values(?, ?, ?, ?, ?, ? , ?, ?, ?, ?)", conn)
      cmd.Parameters.Add("@SessionId", OdbcType.VarChar, 80).Value = id
      cmd.Parameters.Add("@ApplicationName", OdbcType.VarChar, _
        255).Value = ApplicationName
      cmd.Parameters.Add("@Created", OdbcType.DateTime).Value = _
        DateTime.Now
      cmd.Parameters.Add("@Expires", OdbcType.DateTime).Value = _
        DateTime.Now.AddMinutes(CDbl(timeout))
      cmd.Parameters.Add("@LockDate", OdbcType.DateTime).Value = _
        DateTime.Now
      cmd.Parameters.Add("@LockId", OdbcType.Int).Value = 0
      cmd.Parameters.Add("@Timeout", OdbcType.Int).Value = timeout
      cmd.Parameters.Add("@Locked", OdbcType.Bit).Value = False
      cmd.Parameters.Add("@SessionItems", OdbcType.VarChar, 0).Value = ""
      cmd.Parameters.Add("@Flags", OdbcType.Int).Value = 1

      Try
        conn.Open()

        cmd.ExecuteNonQuery()
      Catch e As OdbcException
        If WriteExceptionsToEventLog Then
          WriteToEventLog(e, "CreateUninitializedItem")
          Throw New Exception(exceptionMessage)
        Else
          Throw e
        End If
      Finally
        conn.Close()
      End Try
    End Sub


    '
    ' SessionStateProviderBase.CreateNewStoreData
    '

    Public Overrides Function CreateNewStoreData( _
      context As HttpContext, _
      timeout As Integer) As SessionStateStoreData
    
      Return New SessionStateStoreData(New SessionStateItemCollection(), _
        SessionStateUtility.GetSessionStaticObjects(context), _
        timeout)
    End Function



    '
    ' SessionStateProviderBase.ResetItemTimeout
    '

    Public Overrides Sub ResetItemTimeout(context As HttpContext, _
                                          id As String)    
      Dim conn As OdbcConnection = New OdbcConnection(connectionString)
      Dim cmd As OdbcCommand = _
        New OdbcCommand("UPDATE Sessions SET Expires = ? " & _
        "WHERE SessionId = ? AND ApplicationName = ?", conn)
      cmd.Parameters.Add("@Expires", OdbcType.DateTime).Value = _
        DateTime.Now.AddMinutes(pConfig.Timeout.Minutes)
      cmd.Parameters.Add("@SessionId", OdbcType.VarChar, 80).Value = id
      cmd.Parameters.Add("@ApplicationName", OdbcType.VarChar, _
        255).Value = ApplicationName

      Try
        conn.Open()

        cmd.ExecuteNonQuery()
      Catch e As OdbcException
        If WriteExceptionsToEventLog Then
          WriteToEventLog(e, "ResetItemTimeout")
          Throw New Exception(exceptionMessage)
        Else
          Throw e
        End If
      Finally
        conn.Close()
      End Try
    End Sub


    '
    ' SessionStateProviderBase.InitializeRequest
    '

    Public Overrides Sub InitializeRequest(context As HttpContext)
    
    End Sub


    '
    ' SessionStateProviderBase.EndRequest
    '

    Public Overrides Sub EndRequest(context As HttpContext)
    
    End Sub


    '
    ' WriteToEventLog
    ' This is a helper function that writes exception detail to the 
    ' event log. Exceptions are written to the event log as a security
    ' measure to ensure Private database details are not returned to 
    ' browser. If a method does not Return a status or Boolean
    ' indicating the action succeeded or failed, the caller also 
    ' throws a generic exception.
    '

    Private Sub WriteToEventLog(e As Exception, action As String) 
      Dim log As EventLog = New EventLog()
      log.Source = eventSource
      log.Log = eventLog

      Dim message As String =  _
        "An exception occurred communicating with the data source." & vbCrLf & vbCrLf
      message &= "Action: " & action & vbCrLf & vbCrLf
      message &= "Exception: " & e.ToString()

      log.WriteEntry(message)
    End Sub
  End Class
End Namespace

See Also

Community Additions

ADD
Show:
© 2014 Microsoft