Click here to Skip to main content
15,883,792 members
Articles / DevOps / Load Testing

Sample Session Providers with PostgreSQL

Rate me:
Please Sign up or sign in to vote.
3.50/5 (3 votes)
18 Apr 2007CPOL10 min read 45.9K   478   19  
Several custom Session State providers for TextFile, ODBC, and PostgreSQL.
#define TRACE
using System;
using System.Web;
using System.Web.Configuration;
using System.Configuration;
using System.Configuration.Provider;
using System.Collections.Specialized;
using System.Web.SessionState;
using System.Data;

using System.Diagnostics;
using System.IO;

using Npgsql;
using NpgsqlTypes;

namespace ThreeOaks.PostgreSQLSession
{


/* This session state store provider supports 
    the files stored in PostgreSQLSetup

    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 NpgsqlConnection
    for the session state store provider):

  string commandString = "DELETE FROM Sessions WHERE Expires < ?";
  NpgsqlConnection conn = new NpgsqlConnection(connectionString);
  NpgsqlCommand cmd = new NpgsqlCommand(commandString, conn);
  cmd.Parameters.Add("@Expires", NpgsqlDbType.Timestamp).Value = DateTime.Now;
  conn.Open();
  cmd.ExecuteNonQuery();
  conn.Close();
  
*/
  /// <summary>
  /// A SessionStateStore provider that uses the PostgreSQL RDBMS
  /// with store procedures.
  /// </summary>
    public sealed class TestSession :
        SessionStateStoreProviderBase, ThreeOaks.SessionProviders.IThreeOaksSessionProvider
    {
        private SessionStateSection configSessionStateSection = null;
        private string connectionString;
        private ConnectionStringSettings connectionStringSettings;

        /// <summary>
        /// The connection name used in the connection configuration
        /// </summary>
        public string connectionName = "PostgreSQLSessionServices";

        //Error Logging
        private string eventSource = "PostgreSQLSessionStateStore";
        private string eventLog = "Application";
        private string exceptionMessage =
        "An exception occurred. Please contact your administrator.";

        /// <summary>
        /// Used to indicate the value hasn't been set
        /// </summary>
        private const System.Int32 IntegerNull = -99997;
        /// <summary>
        /// Stores the passed in application name
        /// </summary>
        private string _applicationName;

        /// <summary>
        /// Stores the application id in the database
        /// </summary>
        private System.Int32 _appId = IntegerNull;

        /// <summary>
        /// Holds if should write to event log of not
        /// </summary>
        private bool _writeExceptionsToEventLog = false;

        /// <summary>
        /// If false, exceptions are thrown to the caller. If true,
        /// exceptions are written to the event log.
        /// </summary>
        public bool WriteExceptionsToEventLog
        {
            get { return _writeExceptionsToEventLog; }
            set { _writeExceptionsToEventLog = value; }
        }

        /// <summary>
        /// The ApplicationName property is used to differentiate sessions
        /// in the data source by application. 
        /// </summary>
        public string ApplicationName
        {
            get { return _applicationName; }
        }


        #region command objects
        #region Application Insert
        private NpgsqlCommand _cmdAppInsert = null;

        private static class CmdAppInsertEnum
        {
            public const string ApplicationName = "@ApplicationName";
            public const string AppId = "@AppId";
        }
        /// <summary>
        /// Returns a Command that manages stored procedure for application insert
        /// </summary>
        private NpgsqlCommand CmdAppInsert
        {
            get
            {
                if (_cmdAppInsert == null)
                {
                    _cmdAppInsert = new NpgsqlCommand("aspnet_application_insert(@ApplicationName)");
                    _cmdAppInsert.CommandType = CommandType.StoredProcedure;
                    NpgsqlParameter param = new NpgsqlParameter(CmdAppInsertEnum.ApplicationName
                                                  , NpgsqlDbType.Varchar, 280);

                    //param.Value = _applicationName;
                    param.Direction = ParameterDirection.Input;
                    _cmdAppInsert.Parameters.Add(param);
                    NpgsqlParameter paramAppId = new NpgsqlParameter(CmdAppInsertEnum.AppId
                                              , NpgsqlDbType.Integer);
                    paramAppId.Direction = ParameterDirection.Output;
                    _cmdAppInsert.Parameters.Add(paramAppId);
                }
                return _cmdAppInsert;
            }
            //set { _applicationInsertCommand = null = value; }
        }
        #endregion ApplicationInsert

        #region Set and Release
        private NpgsqlCommand _cmdSetAndRelease = null;

        private static class CmdSetAndReleaseEnum
        {
            public const string NewItem = "@NewItem";
            public const string SessionId = "@SessionId";
            public const string AppId = "@AppId";
            public const string LockId = "@LockId";
            public const string Timeout = "@Timeout";
            public const string SessionItems = "@SessionItems";
        }
        /// <summary>
        /// Returns a Command that manages stored procedure for 
        /// setting the session item
        /// </summary>
        private NpgsqlCommand CmdSetAndRelease
        {
            get
            {
                if (_cmdSetAndRelease == null)
                {
                    _cmdSetAndRelease = new NpgsqlCommand(
                          @"aspnet_session_setandrelease(@NewItem,
	                @SessionId,@AppId,
	                @LockId, @Timeout,
	                @SessionItems)");
                    _cmdSetAndRelease.CommandType = CommandType.StoredProcedure;

                    _cmdSetAndRelease.Parameters.Add(CmdSetAndReleaseEnum.NewItem, NpgsqlDbType.Boolean);
                    _cmdSetAndRelease.Parameters.Add(CmdSetAndReleaseEnum.SessionId, NpgsqlDbType.Varchar, 80);
                    _cmdSetAndRelease.Parameters.Add(CmdSetAndReleaseEnum.AppId, NpgsqlDbType.Integer);
                    _cmdSetAndRelease.Parameters.Add(CmdSetAndReleaseEnum.LockId, NpgsqlDbType.Integer);
                    _cmdSetAndRelease.Parameters.Add(CmdSetAndReleaseEnum.Timeout, NpgsqlDbType.Integer);
                    _cmdSetAndRelease.Parameters.Add(CmdSetAndReleaseEnum.SessionItems,
                      NpgsqlDbType.Varchar);

                }
                return _cmdSetAndRelease;
            }
            //set { _applicationInsertCommand = null = value; }
        }
        #endregion Set and Release


        #region Get Session store item
        private NpgsqlCommand _cmdGetStoreItem = null;

        private static class CmdGetStoreItemEnum
        {
            public const string SessionId = "@SessionId";
            public const string AppId = "@AppId";
            public const string LockRecord = "@LockRecord";
            public const string LockId = "@LockId";
            public const string LockDate = "@LockDate";
            public const string Locked = "@Locked";
            public const string ActionFlags = "@ActionFlags";
            public const string SessionItems = "@SessionItems";
        }
        /// <summary>
        /// Returns a Command that manages stored procedure for
        /// getting the session item
        /// </summary>
        private NpgsqlCommand CmdGetStoreItem
        {
            get
            {
                if (_cmdGetStoreItem == null)
                {
                    _cmdGetStoreItem = new NpgsqlCommand(
                          @"aspnet_session_getsessionstoreitem2(@SessionId,
	                            @AppId,@LockRecord)");
                    _cmdGetStoreItem.CommandType = CommandType.StoredProcedure;

                    _cmdGetStoreItem.Parameters.Add(CmdGetStoreItemEnum.SessionId, NpgsqlDbType.Varchar, 80);
                    _cmdGetStoreItem.Parameters.Add(CmdGetStoreItemEnum.AppId, NpgsqlDbType.Integer);
                    _cmdGetStoreItem.Parameters.Add(CmdGetStoreItemEnum.LockRecord, NpgsqlDbType.Boolean);

                    _cmdGetStoreItem.Parameters.Add(CmdGetStoreItemEnum.LockId, NpgsqlDbType.Integer);
                    _cmdGetStoreItem.Parameters[CmdGetStoreItemEnum.LockId].Direction = ParameterDirection.Output;

                    _cmdGetStoreItem.Parameters.Add(CmdGetStoreItemEnum.LockDate, NpgsqlDbType.TimestampTZ);
                    _cmdGetStoreItem.Parameters[CmdGetStoreItemEnum.LockDate].Direction = ParameterDirection.Output;


                    _cmdGetStoreItem.Parameters.Add(CmdGetStoreItemEnum.Locked, NpgsqlDbType.Boolean);
                    _cmdGetStoreItem.Parameters[CmdGetStoreItemEnum.Locked].Direction = ParameterDirection.Output;

                    _cmdGetStoreItem.Parameters.Add(CmdGetStoreItemEnum.ActionFlags, NpgsqlDbType.Integer);
                    _cmdGetStoreItem.Parameters[CmdGetStoreItemEnum.ActionFlags].Direction = ParameterDirection.Output;

                    _cmdGetStoreItem.Parameters.Add(CmdGetStoreItemEnum.SessionItems, NpgsqlDbType.Varchar);
                    _cmdGetStoreItem.Parameters[CmdGetStoreItemEnum.SessionItems].Direction = ParameterDirection.Output;

                }
                return _cmdGetStoreItem;
            }
            //set { _applicationInsertCommand = null = value; }
        }
        #endregion Get Session Store Item

        #region Release Item
        private NpgsqlCommand _cmdReleaseItem = null;

        private static class CmdReleaseItemEnum
        {
            public const string SessionId = "@SessionId";
            public const string AppId = "@AppId";
            public const string LockId = "@LockId";

        }
        /// <summary>
        /// Returns a Command that manages stored procedure for releasing
        /// an exclusive item
        /// </summary>
        private NpgsqlCommand CmdReleaseItem
        {
            get
            {
                if (_cmdReleaseItem == null)
                {
                    _cmdReleaseItem = new NpgsqlCommand(
                          @"aspnet_session_releaseitemexclusive(@SessionId,@AppId,@LockId)");
                    _cmdReleaseItem.CommandType = CommandType.StoredProcedure;

                    _cmdReleaseItem.Parameters.Add(CmdReleaseItemEnum.SessionId, NpgsqlDbType.Varchar, 80);
                    _cmdReleaseItem.Parameters.Add(CmdReleaseItemEnum.AppId, NpgsqlDbType.Integer);
                    _cmdReleaseItem.Parameters.Add(CmdReleaseItemEnum.LockId, NpgsqlDbType.Integer);
                }
                return _cmdReleaseItem;
            }

        }
        #endregion Release Item

        #region Remove Item
        private NpgsqlCommand _cmdRemoveItem = null;

        private static class CmdRemoveItemEnum
        {
            public const string SessionId = "@SessionId";
            public const string AppId = "@AppId";
            public const string LockId = "@LockId";

        }
        /// <summary>
        /// Returns a Command that manages stored procedure for removing an item
        /// </summary>
        private NpgsqlCommand CmdRemoveItem
        {
            get
            {
                if (_cmdRemoveItem == null)
                {
                    _cmdRemoveItem = new NpgsqlCommand(
                          @"aspnet_removeitem(@SessionId,@AppId,@LockId)");
                    _cmdRemoveItem.CommandType = CommandType.StoredProcedure;

                    _cmdRemoveItem.Parameters.Add(CmdRemoveItemEnum.SessionId, NpgsqlDbType.Varchar, 80);
                    _cmdRemoveItem.Parameters.Add(CmdRemoveItemEnum.AppId, NpgsqlDbType.Integer);
                    _cmdRemoveItem.Parameters.Add(CmdRemoveItemEnum.LockId, NpgsqlDbType.Integer);
                }
                return _cmdRemoveItem;
            }

        }
        #endregion Remove Item

        #region Create Uninitialized
        private NpgsqlCommand _cmdCreateUninitialized = null;

        private static class CmdCreateUninitializedEnum
        {
            public const string SessionId = "@SessionId";
            public const string AppId = "@AppId";
            public const string Timeout = "@Timeout";

        }
        /// <summary>
        /// Returns a Command that manages stored procedure for 
        /// creating an uninitialized item
        /// </summary>
        private NpgsqlCommand CmdCreateUninitialized
        {
            get
            {
                if (_cmdCreateUninitialized == null)
                {
                    _cmdCreateUninitialized = new NpgsqlCommand(
                          @"aspnet_session_createuninitializeditem(@SessionId,@AppId,@Timeout)");
                    _cmdCreateUninitialized.CommandType = CommandType.StoredProcedure;

                    _cmdCreateUninitialized.Parameters.Add(CmdCreateUninitializedEnum.SessionId, NpgsqlDbType.Varchar, 80);
                    _cmdCreateUninitialized.Parameters.Add(CmdCreateUninitializedEnum.AppId, NpgsqlDbType.Integer);
                    _cmdCreateUninitialized.Parameters.Add(CmdCreateUninitializedEnum.Timeout, NpgsqlDbType.Integer);
                }
                return _cmdCreateUninitialized;
            }

        }
        #endregion Create Uninitialized

        #region Reset Timeout
        private NpgsqlCommand _cmdResetTimeout = null;

        private static class CmdResetTimeoutEnum
        {
            public const string SessionId = "@SessionId";
            public const string AppId = "@AppId";

        }
        /// <summary>
        /// Returns a Command that manages stored procedure for 
        /// resetting the timeout
        /// </summary>
        private NpgsqlCommand CmdResetTimeout
        {
            get
            {
                if (_cmdResetTimeout == null)
                {
                    _cmdResetTimeout = new NpgsqlCommand(
                          @"aspnet_session_resetitemtimeout(@SessionId,@AppId)");

                    _cmdResetTimeout.CommandType = CommandType.StoredProcedure;

                    _cmdResetTimeout.Parameters.Add(CmdResetTimeoutEnum.SessionId, NpgsqlDbType.Varchar, 80);
                    _cmdResetTimeout.Parameters.Add(CmdResetTimeoutEnum.AppId, NpgsqlDbType.Integer);

                }
                return _cmdResetTimeout;
            }

        }
        #endregion Create Uninitialized
        #endregion command objects

        /// <summary>
        /// Constructor for PostgreSQLSessionStateStoreSPCommon
        /// </summary>
        public TestSession()
        {
            Debug.WriteLine("In constructor", "TestSession");
            TraceWrite("Constructor");
        }

        /// <summary>
        /// Initializes values for the provider.
        /// Retrieves items from the configuration file to support the provider
        /// Adds application to application table.
        /// </summary>
        /// <param name="name"></param>
        /// <param name="config"></param>
        public override void Initialize(string name, NameValueCollection config)
        {

            Debug.WriteLine("Initialize");


            //
            // Initialize values from web.config.
            //

            if (config == null)
                throw new ArgumentNullException("config");

            if (name == null || name.Length == 0)
                name = "PostgreSQLSessionProvider";

            if (String.IsNullOrEmpty(config["description"]))
            {
                config.Remove("description");
                config.Add("description", "Sample PostgreSQL Session State Store provider");
            }


            // Initialize the abstract base class.
            base.Initialize(name, config);


            //
            // Initialize the ApplicationName property.
            //

            _applicationName =
              System.Web.Hosting.HostingEnvironment.ApplicationVirtualPath;
            if (_applicationName.Length > 279)
            {
                _applicationName = _applicationName.Substring(0, 279);
            }


            //
            // Get <sessionState> configuration element.
            //

            Configuration cfg =
              WebConfigurationManager.OpenWebConfiguration(_applicationName);
            configSessionStateSection =
              (SessionStateSection)cfg.GetSection("system.web/sessionState");

            //ProviderSettings providerSettings = configSessionStateSection.Providers[configSessionStateSection.CustomProvider];

            //
            // Initialize connection string.
            //

            //connectionStringSettings = ConfigurationManager.ConnectionStrings[config["connectionStringName"]];
            connectionStringSettings = ConfigurationManager.ConnectionStrings[connectionName];

            if (connectionStringSettings == null ||
              connectionStringSettings.ConnectionString.Trim() == "")
            {
                throw new ProviderException("Connection string cannot be blank.");
            }

            connectionString = connectionStringSettings.ConnectionString;


            //
            // Initialize WriteExceptionsToEventLog
            //

            _writeExceptionsToEventLog = false;

            if (config["writeExceptionsToEventLog"] != null)
            {
                if (config["writeExceptionsToEventLog"].ToUpper() == "TRUE")
                    _writeExceptionsToEventLog = true;
            }


            // Get application id


            try
            {
                //check application id not set.
                if (_appId == IntegerNull)
                {
                    using (NpgsqlConnection conn = new NpgsqlConnection(connectionString))
                    {
                        conn.Open();
                        NpgsqlCommand cmd = CmdAppInsert;
                        cmd.Connection = conn;
                        cmd.Parameters[CmdAppInsertEnum.ApplicationName].Value = _applicationName;
                        cmd.ExecuteNonQuery();
                        //should always return a value, unless there's an error.
                        _appId = Convert.ToInt32(cmd.Parameters[CmdAppInsertEnum.AppId].Value);

                    }
                }

            }
            catch (NpgsqlException e)
            {
                if (WriteExceptionsToEventLog)
                {
                    WriteToEventLog(e, "Initialize");
                    throw new ProviderException(exceptionMessage);
                }
                else
                    throw e;

                //return;
            }
        }


        /// <summary>
        /// SessionStateStoreProviderBase members 
        /// Needed for dispose
        /// </summary>
        public override void Dispose()
        {
        }


        /// <summary>
        /// SessionStateProviderBase.SetItemExpireCallback
        /// Set to false to tell that Expiring Item won't be called back to 
        /// ASP.NET to generate a Session_OnEnd event
        /// </summary>
        /// <param name="expireCallback"></param>
        /// <returns></returns>
        public override bool SetItemExpireCallback(SessionStateItemExpireCallback expireCallback)
        {
            Debug.WriteLine("SetItemExpireCallback");

            return false;
        }


        /// <summary>
        /// SessionStateProviderBase.SetAndReleaseItemExclusive 
        /// Sets the session data and releases any locks on the data.
        /// </summary>
        /// <param name="context"></param>
        /// <param name="id"></param>
        /// <param name="item"></param>
        /// <param name="lockId"></param>
        /// <param name="newItem"></param>
        public override void SetAndReleaseItemExclusive(HttpContext context,
          string id,
          SessionStateStoreData item,
          object lockId,
          bool newItem)
        {

            Debug.WriteLine("SetAndReleaseItemExclusive");


            try
            {
                // Serialize the SessionStateItemCollection as a string.
                string sessItems = Serialize((SessionStateItemCollection)item.Items);

                using (NpgsqlConnection conn = new NpgsqlConnection(connectionString))
                {
                    conn.Open();
                    NpgsqlCommand cmd = CmdSetAndRelease;
                    cmd.Connection = conn;
                    cmd.Parameters[CmdSetAndReleaseEnum.NewItem].Value = newItem;
                    cmd.Parameters[CmdSetAndReleaseEnum.SessionId].Value = id;
                    cmd.Parameters[CmdSetAndReleaseEnum.AppId].Value = _appId;
                    cmd.Parameters[CmdSetAndReleaseEnum.LockId].Value = lockId;
                    cmd.Parameters[CmdSetAndReleaseEnum.Timeout].Value = item.Timeout;
                    cmd.Parameters[CmdSetAndReleaseEnum.SessionItems].Size = sessItems.Length;
                    cmd.Parameters[CmdSetAndReleaseEnum.SessionItems].Value = sessItems;

                    Debug.WriteLine("sessItems.Length = " + sessItems.Length.ToString());
                    cmd.ExecuteNonQuery();
                }
            }
            catch (NpgsqlException e)
            {
                if (WriteExceptionsToEventLog)
                {
                    WriteToEventLog(e, "SetAndReleaseItemExclusive");
                    throw new ProviderException(exceptionMessage);
                }
                else
                    throw e;
            }

        }


        /// <summary>
        /// SessionStateProviderBase.GetItem 
        /// Retrieves the Session data, but does not lock the data
        /// </summary>
        /// <param name="context"></param>
        /// <param name="id"></param>
        /// <param name="locked"></param>
        /// <param name="lockAge"></param>
        /// <param name="lockId"></param>
        /// <param name="actionFlags"></param>
        /// <returns></returns>
        public override SessionStateStoreData GetItem(HttpContext context,
          string id,
          out bool locked,
          out TimeSpan lockAge,
          out object lockId,
          out SessionStateActions actionFlags)
        {

            Debug.WriteLine("GetItem");

            return GetSessionStoreItem(false, context, id, out locked,
              out lockAge, out lockId, out actionFlags);
        }



        /// <summary>
        /// SessionStateProviderBase.GetItemExclusive
        /// Retrieves the Session data exclusively
        /// </summary>
        /// <param name="context"></param>
        /// <param name="id"></param>
        /// <param name="locked"></param>
        /// <param name="lockAge"></param>
        /// <param name="lockId"></param>
        /// <param name="actionFlags"></param>
        /// <returns></returns>
        public override SessionStateStoreData GetItemExclusive(HttpContext context,
          string id,
          out bool locked,
          out TimeSpan lockAge,
          out object lockId,
          out SessionStateActions actionFlags)
        {

            Debug.WriteLine("GetItemExclusive");

            return GetSessionStoreItem(true, context, id, out locked,
              out lockAge, out lockId, out actionFlags);
        }

        /// <summary>
        /// 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. 
        /// </summary>
        /// <param name="lockRecord">Attempt to lock record or not.</param>
        /// <param name="context"></param>
        /// <param name="sessionId">session identifier</param>
        /// <param name="locked">Did this call lock the record.</param>
        /// <param name="lockAge">How long its been locked</param>
        /// <param name="lockId">id of lock</param>
        /// <param name="actionFlags"></param>
        /// <returns></returns>
        private SessionStateStoreData GetSessionStoreItem(bool lockRecord,
          HttpContext context,
          string sessionId,
          out bool locked,
          out TimeSpan lockAge,
          out object lockId,
          out SessionStateActions actionFlags)
        {

            Debug.WriteLine("GetSessionStoreItem");
            TraceWrite("GetSessionStoreItem");

            // Initial values for return value and out parameters.
            SessionStateStoreData item = null;
            lockAge = TimeSpan.Zero;
            lockId = null;
            locked = false;                           //record not locked by this call.
            actionFlags = SessionStateActions.None;
            try
            {
                // Npgsql database connection.
                using (NpgsqlConnection conn = new NpgsqlConnection(connectionString))
                {


                    // String to hold serialized SessionStateItemCollection.
                    string serializedItems = String.Empty;
                    // True if a record is found in the database.


                    conn.Open();
                    NpgsqlCommand cmd = CmdGetStoreItem;
                    cmd.Connection = conn;

                    cmd.CommandType = CommandType.StoredProcedure;
                    cmd.Parameters[CmdGetStoreItemEnum.SessionId].Value = sessionId;
                    cmd.Parameters[CmdGetStoreItemEnum.AppId].Value = _appId;
                    cmd.Parameters[CmdGetStoreItemEnum.LockRecord].Value = lockRecord;


                    cmd.ExecuteNonQuery();
                    if (Convert.IsDBNull(cmd.Parameters[CmdGetStoreItemEnum.LockDate].Value) == false)
                    {
                        lockAge = DateTime.Now.Subtract((DateTime)cmd.Parameters[CmdGetStoreItemEnum.LockDate].Value);
                        lockId = (int)cmd.Parameters[CmdGetStoreItemEnum.LockId].Value;
                        locked = (bool)cmd.Parameters[CmdGetStoreItemEnum.Locked].Value;
                        actionFlags = (SessionStateActions)cmd.Parameters[CmdGetStoreItemEnum.ActionFlags].Value;
                    }

                    //check any values found
                    if (Convert.IsDBNull(cmd.Parameters[CmdGetStoreItemEnum.SessionItems].Value) == false)
                    {
                        serializedItems = (string)cmd.Parameters[CmdGetStoreItemEnum.SessionItems].Value;

                        // If the actionFlags parameter is not InitializeItem, 
                        // deserialize the stored SessionStateItemCollection.
                        if (actionFlags == SessionStateActions.InitializeItem || serializedItems == String.Empty)
                            item = CreateNewStoreData(context, configSessionStateSection.Timeout.Minutes);
                        else
                            item = Deserialize(context, serializedItems, configSessionStateSection.Timeout.Minutes);
                    }
                    else
                    { //didn't get data back, probably cause session expired.
                        locked = false;
                        item = null;
                    }
                } //using   
            }
            catch (NpgsqlException e)
            {
                if (WriteExceptionsToEventLog)
                {
                    WriteToEventLog(e, "GetSessionStoreItem");
                    throw new ProviderException(exceptionMessage);
                }
                else
                    throw e;
            }

            return item;
        }

        /// <summary>
        /// Serialize is called by the SetAndReleaseItemExclusive method to 
        /// convert the SessionStateItemCollection into a Base64 string to    
        /// be stored in an varchar field. 
        /// </summary>
        /// <param name="items"></param>
        /// <returns></returns>
        private string Serialize(SessionStateItemCollection items)
        {

            Debug.WriteLine("Serialize");

            MemoryStream ms = null;
            try
            {
                ms = new MemoryStream();
                BinaryWriter writer = new BinaryWriter(ms);

                if (items != null)
                    items.Serialize(writer);

                Debug.WriteLine("Serialize Length: " + ms.Length.ToString());
                writer.Close();

                return Convert.ToBase64String(ms.ToArray());
            }
            finally
            {
                if (ms != null)
                {
                    ms.Close();
                }

            }
        }

        /// <summary>
        /// DeSerialize is called by the GetSessionStoreItem method to 
        /// convert the Base64 string stored in the varchar field to a 
        /// SessionStateItemCollection. 
        /// </summary>
        /// <param name="context"></param>
        /// <param name="serializedItems"></param>
        /// <param name="timeout"></param>
        /// <returns></returns>
        private SessionStateStoreData Deserialize(HttpContext context,
          string serializedItems, int timeout)
        {

            Debug.WriteLine("Deserialize");

            MemoryStream ms = null;
            SessionStateItemCollection sessionItems = null;
            try
            {
                if (serializedItems != "")
                {
                    ms =
                     new MemoryStream(Convert.FromBase64String(serializedItems));
                    BinaryReader reader = new BinaryReader(ms);
                    sessionItems = SessionStateItemCollection.Deserialize(reader);
                }
                else
                {
                    sessionItems = new SessionStateItemCollection();
                }
                return new SessionStateStoreData(sessionItems,
                  SessionStateUtility.GetSessionStaticObjects(context),
                  timeout);

            }
            finally
            {
                if (ms != null)
                {
                    ms.Close();
                }
            }
        }

        /// <summary>
        /// SessionStateProviderBase.ReleaseItemExclusive
        /// Releases the locked item by setting locked to false
        /// </summary>
        /// <param name="context"></param>
        /// <param name="id"></param>
        /// <param name="lockId"></param>
        public override void ReleaseItemExclusive(HttpContext context,
          string id,
          object lockId)
        {

            Debug.WriteLine("ReleaseItemExclusive");
            TraceWrite("ReleaseItemExclusive");

            try
            {
                using (NpgsqlConnection conn = new NpgsqlConnection(connectionString))
                {
                    NpgsqlCommand cmd = CmdReleaseItem;

                    cmd.Parameters[CmdReleaseItemEnum.SessionId].Value = id;
                    cmd.Parameters[CmdReleaseItemEnum.AppId].Value = _appId;
                    cmd.Parameters[CmdReleaseItemEnum.LockId].Value = lockId;

                    conn.Open();
                    cmd.Connection = conn;

                    cmd.ExecuteNonQuery();
                }
            }
            catch (NpgsqlException e)
            {
                if (WriteExceptionsToEventLog)
                {
                    WriteToEventLog(e, "ReleaseItemExclusive");
                    throw new ProviderException(exceptionMessage);
                }
                else
                    throw e;
            }

        }

        /// <summary>
        /// SessionStateProviderBase.RemoveItem
        /// Deletes the item. Usually called on session abandon.
        /// </summary>
        /// <param name="context"></param>
        /// <param name="id"></param>
        /// <param name="lockId"></param>
        /// <param name="item"></param>
        public override void RemoveItem(HttpContext context,
          string id, object lockId,
          SessionStateStoreData item)
        {

            Debug.WriteLine("RemoveItem");

            try
            {
                using (NpgsqlConnection conn = new NpgsqlConnection(connectionString))
                {
                    NpgsqlCommand cmd = CmdRemoveItem;

                    cmd.Parameters[CmdRemoveItemEnum.SessionId].Value = id;
                    cmd.Parameters[CmdRemoveItemEnum.AppId].Value = _appId;
                    cmd.Parameters[CmdRemoveItemEnum.LockId].Value = lockId;

                    conn.Open();
                    cmd.Connection = conn;
                    cmd.ExecuteNonQuery();
                }
            }
            catch (NpgsqlException e)
            {
                if (WriteExceptionsToEventLog)
                {
                    WriteToEventLog(e, "RemoveItem");
                    throw new ProviderException(exceptionMessage);
                }
                else
                    throw e;
            }
        }

        /// <summary>
        /// SessionStateProviderBase.CreateUninitializedItem
        /// Creates a blank item. Needed for cookieless state.
        /// </summary>
        /// <param name="context"></param>
        /// <param name="id"></param>
        /// <param name="timeout"></param>
        public override void CreateUninitializedItem(HttpContext context,
          string id,
          int timeout)
        {

            Debug.WriteLine("CreateUninitializedItem");
            try
            {
                using (NpgsqlConnection conn = new NpgsqlConnection(connectionString))
                {
                    NpgsqlCommand cmd = CmdCreateUninitialized;
                    cmd.Parameters[CmdCreateUninitializedEnum.SessionId].Value = id;
                    cmd.Parameters[CmdCreateUninitializedEnum.AppId].Value = _appId;
                    cmd.Parameters[CmdCreateUninitializedEnum.Timeout].Value = timeout;

                    conn.Open();
                    cmd.Connection = conn;

                    cmd.ExecuteNonQuery();
                }
            }
            catch (NpgsqlException e)
            {
                if (WriteExceptionsToEventLog)
                {
                    WriteToEventLog(e, "CreateUninitializedItem");
                    throw new ProviderException(exceptionMessage);
                }
                else
                    throw e;
            }

        }

        /// <summary>
        /// SessionStateProviderBase.CreateNewStoreData
        /// Creates a new data store with no session data
        /// and SessionStatic objects.
        /// </summary>
        /// <param name="context"></param>
        /// <param name="timeout"></param>
        /// <returns></returns>
        public override SessionStateStoreData CreateNewStoreData(
          HttpContext context,
          int timeout)
        {

            Debug.WriteLine("CreateNewStoreData");

            return new SessionStateStoreData(new SessionStateItemCollection(),
              SessionStateUtility.GetSessionStaticObjects(context),
              timeout);
        }



        /// <summary>
        /// SessionStateProviderBase.ResetItemTimeout
        /// Called often to bump theexpire timr for the session.
        /// </summary>
        /// <param name="context"></param>
        /// <param name="id"></param>
        public override void ResetItemTimeout(HttpContext context,
                                              string id)
        {

            Debug.WriteLine("ResetItemTimeout");
            TraceWrite("ReleaseItemExclusive");

            try
            {
                using (NpgsqlConnection conn = new NpgsqlConnection(connectionString))
                {
                    NpgsqlCommand cmd = CmdResetTimeout;

                    cmd.Parameters[CmdResetTimeoutEnum.SessionId].Value = id;
                    cmd.Parameters[CmdResetTimeoutEnum.AppId].Value = _appId;

                    conn.Open();
                    cmd.Connection = conn;
                    cmd.ExecuteNonQuery();
                }
            }
            catch (NpgsqlException e)
            {
                if (WriteExceptionsToEventLog)
                {
                    WriteToEventLog(e, "ResetItemTimeout");
                    throw new ProviderException(exceptionMessage);
                }
                else
                    throw e;
            }

        }


        /// <summary>
        /// SessionStateProviderBase.InitializeRequest
        /// Normally called at the start of each request
        /// </summary>
        /// <param name="context"></param>
        public override void InitializeRequest(HttpContext context)
        {
        }

        /// <summary>
        /// SessionStateProviderBase.EndRequest
        /// Normally called at the end of each request.
        /// </summary>
        /// <param name="context"></param>
        public override void EndRequest(HttpContext context)
        {
        }


        /// <summary>
        /// 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.
        /// </summary>
        /// <param name="e"></param>
        /// <param name="action"></param>
        private void WriteToEventLog(Exception e, string action)
        {

            Debug.WriteLine("WriteToEventLog");

            EventLog log = new EventLog();
            log.Source = eventSource;
            log.Log = eventLog;

            string message =
              "An exception occurred communicating with the data source.\n\n";
            message += "Action: " + action + "\n\n";
            message += "Exception: " + e.ToString();

            log.WriteEntry(message);
        }

        /// <summary>
        /// Deletes any Sessions that are expired
        /// </summary>
        public void DeleteExpiredSessions()
        {

            connectionStringSettings = ConfigurationManager.ConnectionStrings[connectionName];

            if (connectionStringSettings == null ||
              connectionStringSettings.ConnectionString.Trim() == "")
            {
                throw new ProviderException("Connection string cannot be blank.");
            }

            connectionString = connectionStringSettings.ConnectionString;

            using (NpgsqlConnection conn = new NpgsqlConnection(connectionString))
            {
                NpgsqlCommand cmd = new NpgsqlCommand("DELETE FROM aspnet_session WHERE Expires < CURRENT_TIMESTAMP", conn);
                conn.Open();
                cmd.ExecuteNonQuery();
                conn.Close();
            }


        }

        private long tickStart = DateTime.Now.Ticks;
        private bool traceListenerSet = false;
        private void TraceWrite(string message)
        {
            if (traceListenerSet == false)
            {
                TextWriterTraceListener listener = new TextWriterTraceListener(
                    System.Web.Hosting.HostingEnvironment.ApplicationPhysicalPath + "TestSession.Log");
                //remove default
                //Debug.Listeners.RemoveAt(0);
                //Trace.Listeners.RemoveAt(0);
                //listener.LogFileName = System.Web.Hosting.HostingEnvironment.ApplicationPhysicalPath 
                //listener.LogFileName = "c:\\"
                //                        + "TestSession.log";
                Trace.Listeners.Add(listener);
                
                traceListenerSet = true;
            }
            
            Trace.WriteLine("TickStart: " + tickStart.ToString() + " Message:" + message);
            Trace.Flush();
            


        }

    }
}

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
Team Leader
United States United States
A biography in this little spot...sure.
I've worked at GTE HawaiianTel. I've worked at Nuclear Plants. I've worked at Abbott Labs. I've consulted to Ameritech Cellular. I've consulted to Zurich North America. I've consulted to International Truck and Engine. Right now, I've consulted to Wachovia Securities to help with various projects. I've been to SHCDirect and now at Cision.

During this time, I've used all kinds of tools of the trade. Keeping it to the more familier tools, I've used VB3 to VB.NET, ASP to ASP/JAVASCRIPT/XML to ASP.NET. Currently, I'm developing with C# and ASP.NET. I built reports in Access, Excel, Crystal Reports, and Business Objects (including the Universes and ETLS). Been a DBA on SQL Server 4.2 to 2000 and a DBA for Oracle. I've built OLTP databases and DataMarts. Heck, I've even done Documentum. I've been lucky to have created software for the single user to thousands of concurrent users.

I consider myself fortunate to have met many different people and worked in many environments. It's through these experiences I've learned the most.

Comments and Discussions