PgSessionStateStoreProvider.cs.patch

A possible Patch to fix this issue - Christoffer Timm, 08/13/2009 02:50 pm

Download (69.9 KB)

 
PgSessionStateStoreProvider.cs (working copy)
45 45

  
46 46
namespace NauckIT.PostgreSQLProvider
47 47
{
48
	public class PgSessionStateStoreProvider : SessionStateStoreProviderBase
49
	{
50
		private const string s_tableName = "Sessions";
51
		private System.Timers.Timer m_expiredSessionDeletionTimer;
52
		private string m_connectionString = string.Empty;
53
		private string m_applicationName = string.Empty;
54
		private SessionStateSection m_config = null;
55
		private bool m_enableExpireCallback = false;
56
		private SessionStateItemExpireCallback m_expireCallback = null;
48
    public class PgSessionStateStoreProvider : SessionStateStoreProviderBase
49
    {
50
        private const string s_tableName = "Sessions";
51
        private System.Timers.Timer m_expiredSessionDeletionTimer;
52
        private string m_connectionString = string.Empty;
53
        private string m_applicationName = string.Empty;
54
        private SessionStateSection m_config = null;
55
        private bool m_enableExpireCallback = false;
56
        private SessionStateItemExpireCallback m_expireCallback = null;
57 57

  
58
		/// <summary>
59
		/// System.Configuration.Provider.ProviderBase.Initialize Method
60
		/// </summary>
61
		public override void Initialize(string name, NameValueCollection config)
62
		{
63
			// Initialize values from web.config.
64
			if (config == null)
65
				throw new ArgumentNullException("config", Properties.Resources.ErrArgumentNull);
58
        /// <summary>
59
        /// System.Configuration.Provider.ProviderBase.Initialize Method
60
        /// </summary>
61
        public override void Initialize(string name, NameValueCollection config)
62
        {
63
            // Initialize values from web.config.
64
            if (config == null)
65
                throw new ArgumentNullException("config", Properties.Resources.ErrArgumentNull);
66 66

  
67
			if (string.IsNullOrEmpty(name))
68
				name = Properties.Resources.SessionStoreProviderDefaultName;
67
            if (string.IsNullOrEmpty(name))
68
                name = Properties.Resources.SessionStoreProviderDefaultName;
69 69

  
70
			if (string.IsNullOrEmpty(config["description"]))
71
			{
72
				config.Remove("description");
73
				config.Add("description", Properties.Resources.SessionStoreProviderDefaultDescription);
74
			}
70
            if (string.IsNullOrEmpty(config["description"]))
71
            {
72
                config.Remove("description");
73
                config.Add("description", Properties.Resources.SessionStoreProviderDefaultDescription);
74
            }
75 75

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

  
79
			m_applicationName = PgMembershipProvider.GetConfigValue(config["applicationName"], HostingEnvironment.ApplicationVirtualPath);
79
            m_applicationName = PgMembershipProvider.GetConfigValue(config["applicationName"], HostingEnvironment.ApplicationVirtualPath);
80 80

  
81
			// Get connection string.
82
			m_connectionString = PgMembershipProvider.GetConnectionString(config["connectionStringName"]);
81
            // Get connection string.
82
            m_connectionString = PgMembershipProvider.GetConnectionString(config["connectionStringName"]);
83 83

  
84
			// Get <sessionState> configuration element.
85
			m_config = (SessionStateSection)WebConfigurationManager.OpenWebConfiguration(HostingEnvironment.ApplicationVirtualPath).GetSection("system.web/sessionState");
84
            // Get <sessionState> configuration element.
85
            m_config = (SessionStateSection)WebConfigurationManager.OpenWebConfiguration(HostingEnvironment.ApplicationVirtualPath).GetSection("system.web/sessionState");
86 86

  
87
			// Should automatic session garbage collection be turned on?
88
			bool enableExpiredSessionAutoDeletion = Convert.ToBoolean(PgMembershipProvider.GetConfigValue(config["enableExpiredSessionAutoDeletion"], "false"), CultureInfo.InvariantCulture);
89
			
90
			if (!enableExpiredSessionAutoDeletion)
91
				return;
87
            // Should automatic session garbage collection be turned on?
88
            bool enableExpiredSessionAutoDeletion = Convert.ToBoolean(PgMembershipProvider.GetConfigValue(config["enableExpiredSessionAutoDeletion"], "false"), CultureInfo.InvariantCulture);
92 89

  
93
			m_enableExpireCallback = Convert.ToBoolean(PgMembershipProvider.GetConfigValue(config["enableSessionExpireCallback"], "false"), CultureInfo.InvariantCulture);
90
            if (!enableExpiredSessionAutoDeletion)
91
                return;
94 92

  
95
			// Load session garbage collection configuration and setup garbage collection interval timer
96
			double expiredSessionAutoDeletionInterval = Convert.ToDouble(PgMembershipProvider.GetConfigValue(config["expiredSessionAutoDeletionInterval"], "1800000"), CultureInfo.InvariantCulture); //default: 30 minutes
93
            m_enableExpireCallback = Convert.ToBoolean(PgMembershipProvider.GetConfigValue(config["enableSessionExpireCallback"], "false"), CultureInfo.InvariantCulture);
97 94

  
98
			m_expiredSessionDeletionTimer = new System.Timers.Timer(expiredSessionAutoDeletionInterval);
99
			m_expiredSessionDeletionTimer.Elapsed += new System.Timers.ElapsedEventHandler(ExpiredSessionDeletionTimer_Elapsed);
100
			m_expiredSessionDeletionTimer.Enabled = true;
101
			m_expiredSessionDeletionTimer.AutoReset = true;
102
		}
95
            // Load session garbage collection configuration and setup garbage collection interval timer
96
            double expiredSessionAutoDeletionInterval = Convert.ToDouble(PgMembershipProvider.GetConfigValue(config["expiredSessionAutoDeletionInterval"], "1800000"), CultureInfo.InvariantCulture); //default: 30 minutes
103 97

  
104
		/// <summary>
105
		/// SessionStateStoreProviderBase members
106
		/// </summary>
107
		#region SessionStateStoreProviderBase members
98
            m_expiredSessionDeletionTimer = new System.Timers.Timer(expiredSessionAutoDeletionInterval);
99
            m_expiredSessionDeletionTimer.Elapsed += new System.Timers.ElapsedEventHandler(ExpiredSessionDeletionTimer_Elapsed);
100
            m_expiredSessionDeletionTimer.Enabled = true;
101
            m_expiredSessionDeletionTimer.AutoReset = true;
102
        }
108 103

  
109
		public override void Dispose()
110
		{
111
			if (m_expiredSessionDeletionTimer == null)
112
				return;
104
        /// <summary>
105
        /// SessionStateStoreProviderBase members
106
        /// </summary>
107
        #region SessionStateStoreProviderBase members
113 108

  
114
			// cleanup timer
115
			m_expiredSessionDeletionTimer.Stop();
116
			m_expiredSessionDeletionTimer.Dispose();
117
			m_expiredSessionDeletionTimer = null;
118
		}
109
        public override void Dispose()
110
        {
111
            if (m_expiredSessionDeletionTimer == null)
112
                return;
119 113

  
120
		/// <summary>
121
		/// SessionStateProviderBase.InitializeRequest
122
		/// </summary>
123
		public override void InitializeRequest(HttpContext context)
124
		{
125
		}
114
            // cleanup timer
115
            m_expiredSessionDeletionTimer.Stop();
116
            m_expiredSessionDeletionTimer.Dispose();
117
            m_expiredSessionDeletionTimer = null;
118
        }
126 119

  
127
		/// <summary>
128
		/// SessionStateProviderBase.EndRequest
129
		/// </summary>
130
		public override void EndRequest(HttpContext context)
131
		{
132
		}
120
        /// <summary>
121
        /// SessionStateProviderBase.InitializeRequest
122
        /// </summary>
123
        public override void InitializeRequest(HttpContext context)
124
        {
125
        }
133 126

  
134
		/// <summary>
135
		/// SessionStateProviderBase.CreateNewStoreData
136
		/// </summary>
137
		public override SessionStateStoreData CreateNewStoreData(HttpContext context, int timeout)
138
		{
139
			return new SessionStateStoreData(new SessionStateItemCollection(), SessionStateUtility.GetSessionStaticObjects(context), timeout);
140
		}
127
        /// <summary>
128
        /// SessionStateProviderBase.EndRequest
129
        /// </summary>
130
        public override void EndRequest(HttpContext context)
131
        {
132
        }
141 133

  
142
		/// <summary>
143
		/// SessionStateProviderBase.CreateUninitializedItem
144
		/// </summary>
145
		public override void CreateUninitializedItem(HttpContext context, string id, int timeout)
146
		{
147
			using (NpgsqlConnection dbConn = new NpgsqlConnection(m_connectionString))
148
			{
149
				using (NpgsqlCommand dbCommand = dbConn.CreateCommand())
150
				{
151
					dbCommand.CommandText = string.Format(CultureInfo.InvariantCulture, "INSERT INTO \"{0}\" (\"SessionId\", \"ApplicationName\", \"Created\", \"Expires\", \"Timeout\", \"Locked\", \"LockId\", \"LockDate\", \"Data\", \"Flags\") Values (@SessionId, @ApplicationName, @Created, @Expires, @Timeout, @Locked, @LockId, @LockDate, @Data, @Flags)", s_tableName);
134
        /// <summary>
135
        /// SessionStateProviderBase.CreateNewStoreData
136
        /// </summary>
137
        public override SessionStateStoreData CreateNewStoreData(HttpContext context, int timeout)
138
        {
139
            return new SessionStateStoreData(new SessionStateItemCollection(), SessionStateUtility.GetSessionStaticObjects(context), timeout);
140
        }
152 141

  
153
					dbCommand.Parameters.Add("@SessionId", NpgsqlDbType.Varchar, 80).Value = id;
154
					dbCommand.Parameters.Add("@ApplicationName", NpgsqlDbType.Varchar, 255).Value = m_applicationName;
155
					dbCommand.Parameters.Add("@Created", NpgsqlDbType.TimestampTZ).Value = DateTime.Now;
156
					dbCommand.Parameters.Add("@Expires", NpgsqlDbType.TimestampTZ).Value = DateTime.Now.AddMinutes((Double)timeout);
157
					dbCommand.Parameters.Add("@Timeout", NpgsqlDbType.Integer).Value = timeout;
158
					dbCommand.Parameters.Add("@Locked", NpgsqlDbType.Boolean).Value = false;
159
					dbCommand.Parameters.Add("@LockId", NpgsqlDbType.Integer).Value = 0;
160
					dbCommand.Parameters.Add("@LockDate", NpgsqlDbType.TimestampTZ).Value = DateTime.Now;
161
					dbCommand.Parameters.Add("@Data", NpgsqlDbType.Text).Value = string.Empty;
162
					dbCommand.Parameters.Add("@Flags", NpgsqlDbType.Integer).Value = 1;
142
        /// <summary>
143
        /// SessionStateProviderBase.CreateUninitializedItem
144
        /// </summary>
145
        public override void CreateUninitializedItem(HttpContext context, string id, int timeout)
146
        {
147
            using (NpgsqlConnection dbConn = new NpgsqlConnection(m_connectionString))
148
            {
149
                using (NpgsqlCommand dbCommand = dbConn.CreateCommand())
150
                {
151
                    NpgsqlTransaction dbTrans = null;
163 152

  
164
					NpgsqlTransaction dbTrans = null;
153
                    try
154
                    {
155
                        dbConn.Open();
156
                        dbTrans = dbConn.BeginTransaction();
165 157

  
166
					try
167
					{
168
						dbConn.Open();
169
						dbCommand.Prepare();
158
                        /* 
159
                         * PATCH (cti, fixes bug #16): To prevent running into duplicate key constraint in postgres, delete Session first.
160
                         */
161
                        dbCommand.CommandText = string.Format(CultureInfo.InvariantCulture, "DELETE FROM \"{0}\" WHERE \"SessionId\" = @SessionId;", s_tableName);
170 162

  
171
						dbTrans = dbConn.BeginTransaction();
163
                        dbCommand.Parameters.Add("@SessionId", NpgsqlDbType.Varchar, 80).Value = id;
172 164

  
173
						dbCommand.ExecuteNonQuery();
165
                        dbCommand.Prepare();
174 166

  
175
						// Attempt to commit the transaction
176
						dbTrans.Commit();
177
					}
178
					catch (Exception e)
179
					{
180
						Trace.WriteLine(e.ToString());
167
                        dbCommand.ExecuteNonQuery();
168
                        /* PATCH END */
181 169

  
182
						if (dbTrans != null)
183
						{
184
							try
185
							{
186
								// Attempt to roll back the transaction
187
								Trace.WriteLine(Properties.Resources.LogRollbackAttempt);
188
								dbTrans.Rollback();
189
							}
190
							catch (NpgsqlException re)
191
							{
192
								// Rollback failed
193
								Trace.WriteLine(Properties.Resources.ErrRollbackFailed);
194
								Trace.WriteLine(re.ToString());
195
							}
196
						}
170
                        dbCommand.CommandText = string.Format(CultureInfo.InvariantCulture, "INSERT INTO \"{0}\" (\"SessionId\", \"ApplicationName\", \"Created\", \"Expires\", \"Timeout\", \"Locked\", \"LockId\", \"LockDate\", \"Data\", \"Flags\") Values (@SessionId, @ApplicationName, @Created, @Expires, @Timeout, @Locked, @LockId, @LockDate, @Data, @Flags)", s_tableName);
197 171

  
198
						throw new ProviderException(Properties.Resources.ErrOperationAborted);
199
					}
200
					finally
201
					{
202
						if (dbTrans != null)
203
							dbTrans.Dispose();
172
                        dbCommand.Parameters.Clear();
173
                        dbCommand.Parameters.Add("@SessionId", NpgsqlDbType.Varchar, 80).Value = id;
174
                        dbCommand.Parameters.Add("@ApplicationName", NpgsqlDbType.Varchar, 255).Value = m_applicationName;
175
                        dbCommand.Parameters.Add("@Created", NpgsqlDbType.TimestampTZ).Value = DateTime.Now;
176
                        dbCommand.Parameters.Add("@Expires", NpgsqlDbType.TimestampTZ).Value = DateTime.Now.AddMinutes((Double)timeout);
177
                        dbCommand.Parameters.Add("@Timeout", NpgsqlDbType.Integer).Value = timeout;
178
                        dbCommand.Parameters.Add("@Locked", NpgsqlDbType.Boolean).Value = false;
179
                        dbCommand.Parameters.Add("@LockId", NpgsqlDbType.Integer).Value = 0;
180
                        dbCommand.Parameters.Add("@LockDate", NpgsqlDbType.TimestampTZ).Value = DateTime.Now;
181
                        dbCommand.Parameters.Add("@Data", NpgsqlDbType.Text).Value = string.Empty;
182
                        dbCommand.Parameters.Add("@Flags", NpgsqlDbType.Integer).Value = 1;
204 183

  
205
						if (dbConn != null)
206
							dbConn.Close();
207
					}
208
				}
209
			}
210
		}
184
                        dbCommand.Prepare();
211 185

  
212
		/// <summary>
213
		/// SessionStateProviderBase.GetItem
214
		/// </summary>
215
		public override SessionStateStoreData GetItem(HttpContext context, string id, out bool locked, out TimeSpan lockAge, out object lockId, out SessionStateActions actions)
216
		{
217
			return GetSessionStoreItem(false, context, id, out locked, out lockAge, out lockId, out actions);
218
		}
186
                        dbCommand.ExecuteNonQuery();
219 187

  
220
		/// <summary>
221
		/// SessionStateProviderBase.GetItemExclusive
222
		/// </summary>
223
		public override SessionStateStoreData GetItemExclusive(HttpContext context, string id, out bool locked, out TimeSpan lockAge, out object lockId, out SessionStateActions actions)
224
		{
225
			return GetSessionStoreItem(true, context, id, out locked, out lockAge, out lockId, out actions);
226
		}
188
                        // Attempt to commit the transaction
189
                        dbTrans.Commit();
190
                    }
191
                    catch (Exception e)
192
                    {
193
                        Trace.WriteLine(e.ToString());
227 194

  
228
		/// <summary>
229
		/// SessionStateProviderBase.ReleaseItemExclusive
230
		/// </summary>
231
		public override void ReleaseItemExclusive(HttpContext context, string id, object lockId)
232
		{
233
			using (NpgsqlConnection dbConn = new NpgsqlConnection(m_connectionString))
234
			{
235
				using (NpgsqlCommand dbCommand = dbConn.CreateCommand())
236
				{
237
					dbCommand.CommandText = string.Format(CultureInfo.InvariantCulture, "UPDATE \"{0}\" SET \"Expires\" = @Expires, \"Locked\" = @Locked WHERE \"SessionId\" = @SessionId AND \"ApplicationName\" = @ApplicationName AND \"LockId\" = @LockId", s_tableName);
195
                        if (dbTrans != null)
196
                        {
197
                            try
198
                            {
199
                                // Attempt to roll back the transaction
200
                                Trace.WriteLine(Properties.Resources.LogRollbackAttempt);
201
                                dbTrans.Rollback();
202
                            }
203
                            catch (NpgsqlException re)
204
                            {
205
                                // Rollback failed
206
                                Trace.WriteLine(Properties.Resources.ErrRollbackFailed);
207
                                Trace.WriteLine(re.ToString());
208
                            }
209
                        }
238 210

  
239
					dbCommand.Parameters.Add("@Expires", NpgsqlDbType.TimestampTZ).Value = DateTime.Now.Add(m_config.Timeout);
240
					dbCommand.Parameters.Add("@Locked", NpgsqlDbType.Boolean).Value = false;
241
					dbCommand.Parameters.Add("@SessionId", NpgsqlDbType.Varchar, 80).Value = id;
242
					dbCommand.Parameters.Add("@ApplicationName", NpgsqlDbType.Varchar, 255).Value = m_applicationName;
243
					dbCommand.Parameters.Add("@LockId", NpgsqlDbType.Integer).Value = lockId;
244
					
245
					NpgsqlTransaction dbTrans = null;
211
                        throw new ProviderException(Properties.Resources.ErrOperationAborted);
212
                    }
213
                    finally
214
                    {
215
                        if (dbTrans != null)
216
                            dbTrans.Dispose();
246 217

  
247
					try
248
					{
249
						dbConn.Open();
250
						dbCommand.Prepare();
218
                        if (dbConn != null)
219
                            dbConn.Close();
220
                    }
221
                }
222
            }
223
        }
251 224

  
252
						dbTrans = dbConn.BeginTransaction();
225
        /// <summary>
226
        /// SessionStateProviderBase.GetItem
227
        /// </summary>
228
        public override SessionStateStoreData GetItem(HttpContext context, string id, out bool locked, out TimeSpan lockAge, out object lockId, out SessionStateActions actions)
229
        {
230
            return GetSessionStoreItem(false, context, id, out locked, out lockAge, out lockId, out actions);
231
        }
253 232

  
254
						dbCommand.ExecuteNonQuery();
233
        /// <summary>
234
        /// SessionStateProviderBase.GetItemExclusive
235
        /// </summary>
236
        public override SessionStateStoreData GetItemExclusive(HttpContext context, string id, out bool locked, out TimeSpan lockAge, out object lockId, out SessionStateActions actions)
237
        {
238
            return GetSessionStoreItem(true, context, id, out locked, out lockAge, out lockId, out actions);
239
        }
255 240

  
256
						// Attempt to commit the transaction
257
						dbTrans.Commit();
258
					}
259
					catch (NpgsqlException e)
260
					{
261
						Trace.WriteLine(e.ToString());
241
        /// <summary>
242
        /// SessionStateProviderBase.ReleaseItemExclusive
243
        /// </summary>
244
        public override void ReleaseItemExclusive(HttpContext context, string id, object lockId)
245
        {
246
            using (NpgsqlConnection dbConn = new NpgsqlConnection(m_connectionString))
247
            {
248
                using (NpgsqlCommand dbCommand = dbConn.CreateCommand())
249
                {
250
                    dbCommand.CommandText = string.Format(CultureInfo.InvariantCulture, "UPDATE \"{0}\" SET \"Expires\" = @Expires, \"Locked\" = @Locked WHERE \"SessionId\" = @SessionId AND \"ApplicationName\" = @ApplicationName AND \"LockId\" = @LockId", s_tableName);
262 251

  
263
						if (dbTrans != null)
264
						{
265
							try
266
							{
267
								// Attempt to roll back the transaction
268
								Trace.WriteLine(Properties.Resources.LogRollbackAttempt);
269
								dbTrans.Rollback();
270
							}
271
							catch (NpgsqlException re)
272
							{
273
								// Rollback failed
274
								Trace.WriteLine(Properties.Resources.ErrRollbackFailed);
275
								Trace.WriteLine(re.ToString());
276
							}
277
						}
252
                    dbCommand.Parameters.Add("@Expires", NpgsqlDbType.TimestampTZ).Value = DateTime.Now.Add(m_config.Timeout);
253
                    dbCommand.Parameters.Add("@Locked", NpgsqlDbType.Boolean).Value = false;
254
                    dbCommand.Parameters.Add("@SessionId", NpgsqlDbType.Varchar, 80).Value = id;
255
                    dbCommand.Parameters.Add("@ApplicationName", NpgsqlDbType.Varchar, 255).Value = m_applicationName;
256
                    dbCommand.Parameters.Add("@LockId", NpgsqlDbType.Integer).Value = lockId;
278 257

  
279
						throw new ProviderException(Properties.Resources.ErrOperationAborted);
280
					}
281
					finally
282
					{
283
						if (dbTrans != null)
284
							dbTrans.Dispose();
258
                    NpgsqlTransaction dbTrans = null;
285 259

  
286
						if (dbConn != null)
287
							dbConn.Close();
288
					}
289
				}
290
			}
291
		}
260
                    try
261
                    {
262
                        dbConn.Open();
263
                        dbCommand.Prepare();
292 264

  
293
		/// <summary>
294
		/// SessionStateProviderBase.RemoveItem
295
		/// </summary>
296
		public override void RemoveItem(HttpContext context, string id, object lockId, SessionStateStoreData item)
297
		{
298
			using (NpgsqlConnection dbConn = new NpgsqlConnection(m_connectionString))
299
			{
300
				using (NpgsqlCommand dbCommand = dbConn.CreateCommand())
301
				{
302
					dbCommand.CommandText = string.Format(CultureInfo.InvariantCulture, "DELETE FROM \"{0}\" WHERE \"SessionId\" = @SessionId AND \"ApplicationName\" = @ApplicationName AND \"LockId\" = @LockId", s_tableName);
265
                        dbTrans = dbConn.BeginTransaction();
303 266

  
304
					dbCommand.Parameters.Add("@SessionId", NpgsqlDbType.Varchar, 80).Value = id;
305
					dbCommand.Parameters.Add("@ApplicationName", NpgsqlDbType.Varchar, 255).Value = m_applicationName;
306
					dbCommand.Parameters.Add("@LockId", NpgsqlDbType.Integer).Value = lockId;
267
                        dbCommand.ExecuteNonQuery();
307 268

  
308
					NpgsqlTransaction dbTrans = null;
269
                        // Attempt to commit the transaction
270
                        dbTrans.Commit();
271
                    }
272
                    catch (NpgsqlException e)
273
                    {
274
                        Trace.WriteLine(e.ToString());
309 275

  
310
					try
311
					{
312
						dbConn.Open();
313
						dbCommand.Prepare();
276
                        if (dbTrans != null)
277
                        {
278
                            try
279
                            {
280
                                // Attempt to roll back the transaction
281
                                Trace.WriteLine(Properties.Resources.LogRollbackAttempt);
282
                                dbTrans.Rollback();
283
                            }
284
                            catch (NpgsqlException re)
285
                            {
286
                                // Rollback failed
287
                                Trace.WriteLine(Properties.Resources.ErrRollbackFailed);
288
                                Trace.WriteLine(re.ToString());
289
                            }
290
                        }
314 291

  
315
						dbTrans = dbConn.BeginTransaction();
292
                        throw new ProviderException(Properties.Resources.ErrOperationAborted);
293
                    }
294
                    finally
295
                    {
296
                        if (dbTrans != null)
297
                            dbTrans.Dispose();
316 298

  
317
						dbCommand.ExecuteNonQuery();
299
                        if (dbConn != null)
300
                            dbConn.Close();
301
                    }
302
                }
303
            }
304
        }
318 305

  
319
						// Attempt to commit the transaction
320
						dbTrans.Commit();
321
					}
322
					catch (Exception e)
323
					{
324
						Trace.WriteLine(e.ToString());
306
        /// <summary>
307
        /// SessionStateProviderBase.RemoveItem
308
        /// </summary>
309
        public override void RemoveItem(HttpContext context, string id, object lockId, SessionStateStoreData item)
310
        {
311
            using (NpgsqlConnection dbConn = new NpgsqlConnection(m_connectionString))
312
            {
313
                using (NpgsqlCommand dbCommand = dbConn.CreateCommand())
314
                {
315
                    dbCommand.CommandText = string.Format(CultureInfo.InvariantCulture, "DELETE FROM \"{0}\" WHERE \"SessionId\" = @SessionId AND \"ApplicationName\" = @ApplicationName AND \"LockId\" = @LockId", s_tableName);
325 316

  
326
						if (dbTrans != null)
327
						{
328
							try
329
							{
330
								// Attempt to roll back the transaction
331
								Trace.WriteLine(Properties.Resources.LogRollbackAttempt);
332
								dbTrans.Rollback();
333
							}
334
							catch (Exception re)
335
							{
336
								// Rollback failed
337
								Trace.WriteLine(Properties.Resources.ErrRollbackFailed);
338
								Trace.WriteLine(re.ToString());
339
							}
340
						}
317
                    dbCommand.Parameters.Add("@SessionId", NpgsqlDbType.Varchar, 80).Value = id;
318
                    dbCommand.Parameters.Add("@ApplicationName", NpgsqlDbType.Varchar, 255).Value = m_applicationName;
319
                    dbCommand.Parameters.Add("@LockId", NpgsqlDbType.Integer).Value = lockId;
341 320

  
342
						throw new ProviderException(Properties.Resources.ErrOperationAborted);
343
					}
344
					finally
345
					{
346
						if (dbTrans != null)
347
							dbTrans.Dispose();
321
                    NpgsqlTransaction dbTrans = null;
348 322

  
349
						if (dbConn != null)
350
							dbConn.Close();
351
					}
352
				}
353
			}
354
		}
323
                    try
324
                    {
325
                        dbConn.Open();
326
                        dbCommand.Prepare();
355 327

  
356
		/// <summary>
357
		/// SessionStateProviderBase.ResetItemTimeout
358
		/// </summary>
359
		public override void ResetItemTimeout(HttpContext context, string id)
360
		{
361
			using (NpgsqlConnection dbConn = new NpgsqlConnection(m_connectionString))
362
			{
363
				using (NpgsqlCommand dbCommand = dbConn.CreateCommand())
364
				{
365
					dbCommand.CommandText = string.Format(CultureInfo.InvariantCulture, "UPDATE \"{0}\" SET \"Expires\" = @Expires WHERE \"SessionId\" = @SessionId AND \"ApplicationName\" = @ApplicationName", s_tableName);
328
                        dbTrans = dbConn.BeginTransaction();
366 329

  
367
					dbCommand.Parameters.Add("@Expires", NpgsqlDbType.TimestampTZ).Value = DateTime.Now.Add(m_config.Timeout);
368
					dbCommand.Parameters.Add("@SessionId", NpgsqlDbType.Varchar, 80).Value = id;
369
					dbCommand.Parameters.Add("@ApplicationName", NpgsqlDbType.Varchar, 255).Value = m_applicationName;
330
                        dbCommand.ExecuteNonQuery();
370 331

  
371
					NpgsqlTransaction dbTrans = null;
332
                        // Attempt to commit the transaction
333
                        dbTrans.Commit();
334
                    }
335
                    catch (Exception e)
336
                    {
337
                        Trace.WriteLine(e.ToString());
372 338

  
373
					try
374
					{
375
						dbConn.Open();
376
						dbCommand.Prepare();
339
                        if (dbTrans != null)
340
                        {
341
                            try
342
                            {
343
                                // Attempt to roll back the transaction
344
                                Trace.WriteLine(Properties.Resources.LogRollbackAttempt);
345
                                dbTrans.Rollback();
346
                            }
347
                            catch (Exception re)
348
                            {
349
                                // Rollback failed
350
                                Trace.WriteLine(Properties.Resources.ErrRollbackFailed);
351
                                Trace.WriteLine(re.ToString());
352
                            }
353
                        }
377 354

  
378
						dbTrans = dbConn.BeginTransaction();
355
                        throw new ProviderException(Properties.Resources.ErrOperationAborted);
356
                    }
357
                    finally
358
                    {
359
                        if (dbTrans != null)
360
                            dbTrans.Dispose();
379 361

  
380
						dbCommand.ExecuteNonQuery();
362
                        if (dbConn != null)
363
                            dbConn.Close();
364
                    }
365
                }
366
            }
367
        }
381 368

  
382
						// Attempt to commit the transaction
383
						dbTrans.Commit();
384
					}
385
					catch (Exception e)
386
					{
387
						Trace.WriteLine(e.ToString());
369
        /// <summary>
370
        /// SessionStateProviderBase.ResetItemTimeout
371
        /// </summary>
372
        public override void ResetItemTimeout(HttpContext context, string id)
373
        {
374
            using (NpgsqlConnection dbConn = new NpgsqlConnection(m_connectionString))
375
            {
376
                using (NpgsqlCommand dbCommand = dbConn.CreateCommand())
377
                {
378
                    dbCommand.CommandText = string.Format(CultureInfo.InvariantCulture, "UPDATE \"{0}\" SET \"Expires\" = @Expires WHERE \"SessionId\" = @SessionId AND \"ApplicationName\" = @ApplicationName", s_tableName);
388 379

  
389
						if (dbTrans != null)
390
						{
391
							try
392
							{
393
								// Attempt to roll back the transaction
394
								Trace.WriteLine(Properties.Resources.LogRollbackAttempt);
395
								dbTrans.Rollback();
396
							}
397
							catch (Exception re)
398
							{
399
								// Rollback failed
400
								Trace.WriteLine(Properties.Resources.ErrRollbackFailed);
401
								Trace.WriteLine(re.ToString());
402
							}
403
						}
380
                    dbCommand.Parameters.Add("@Expires", NpgsqlDbType.TimestampTZ).Value = DateTime.Now.Add(m_config.Timeout);
381
                    dbCommand.Parameters.Add("@SessionId", NpgsqlDbType.Varchar, 80).Value = id;
382
                    dbCommand.Parameters.Add("@ApplicationName", NpgsqlDbType.Varchar, 255).Value = m_applicationName;
404 383

  
405
						throw new ProviderException(Properties.Resources.ErrOperationAborted);
406
					}
407
					finally
408
					{
409
						if (dbTrans != null)
410
							dbTrans.Dispose();
384
                    NpgsqlTransaction dbTrans = null;
411 385

  
412
						if (dbConn != null)
413
							dbConn.Close();
414
					}
415
				}
416
			}
417
		}
386
                    try
387
                    {
388
                        dbConn.Open();
389
                        dbCommand.Prepare();
418 390

  
419
		/// <summary>
420
		/// SessionStateProviderBase.SetAndReleaseItemExclusive
421
		/// </summary>
422
		public override void SetAndReleaseItemExclusive(HttpContext context, string id, SessionStateStoreData item, object lockId, bool newItem)
423
		{
424
			// Serialize the SessionStateItemCollection as a string
425
			string serializedItems = Serialize((SessionStateItemCollection)item.Items);
391
                        dbTrans = dbConn.BeginTransaction();
426 392

  
427
			using (NpgsqlConnection dbConn = new NpgsqlConnection(m_connectionString))
428
			{
429
				using (NpgsqlCommand dbCommand = dbConn.CreateCommand(),
430
						delCommand = dbConn.CreateCommand())
431
				{
432
					if (newItem)
433
					{
434
						// Delete existing expired session if exist
435
						delCommand.CommandText = string.Format(CultureInfo.InvariantCulture, "DELETE FROM \"{0}\" WHERE \"SessionId\" = @SessionId AND \"ApplicationName\" = @ApplicationName", s_tableName);
393
                        dbCommand.ExecuteNonQuery();
436 394

  
437
						delCommand.Parameters.Add("@SessionId", NpgsqlDbType.Varchar, 80).Value = id;
438
						delCommand.Parameters.Add("@ApplicationName", NpgsqlDbType.Varchar, 255).Value = m_applicationName;
395
                        // Attempt to commit the transaction
396
                        dbTrans.Commit();
397
                    }
398
                    catch (Exception e)
399
                    {
400
                        Trace.WriteLine(e.ToString());
439 401

  
440
						// Insert new session data
441
						dbCommand.CommandText = string.Format(CultureInfo.InvariantCulture, "INSERT INTO \"{0}\" (\"SessionId\", \"ApplicationName\", \"Created\", \"Expires\", \"Timeout\", \"Locked\", \"LockId\", \"LockDate\", \"Data\", \"Flags\") Values (@SessionId, @ApplicationName, @Created, @Expires, @Timeout, @Locked, @LockId, @LockDate, @Data, @Flags)", s_tableName);
402
                        if (dbTrans != null)
403
                        {
404
                            try
405
                            {
406
                                // Attempt to roll back the transaction
407
                                Trace.WriteLine(Properties.Resources.LogRollbackAttempt);
408
                                dbTrans.Rollback();
409
                            }
410
                            catch (Exception re)
411
                            {
412
                                // Rollback failed
413
                                Trace.WriteLine(Properties.Resources.ErrRollbackFailed);
414
                                Trace.WriteLine(re.ToString());
415
                            }
416
                        }
442 417

  
443
						dbCommand.Parameters.Add("@SessionId", NpgsqlDbType.Varchar, 80).Value = id;
444
						dbCommand.Parameters.Add("@ApplicationName", NpgsqlDbType.Varchar, 255).Value = m_applicationName;
445
						dbCommand.Parameters.Add("@Created", NpgsqlDbType.TimestampTZ).Value = DateTime.Now;
446
						dbCommand.Parameters.Add("@Expires", NpgsqlDbType.TimestampTZ).Value = DateTime.Now.AddMinutes((Double)item.Timeout);
447
						dbCommand.Parameters.Add("@Timeout", NpgsqlDbType.Integer).Value = item.Timeout;
448
						dbCommand.Parameters.Add("@Locked", NpgsqlDbType.Boolean).Value = false;
449
						dbCommand.Parameters.Add("@LockId", NpgsqlDbType.Integer).Value = 0;
450
						dbCommand.Parameters.Add("@LockDate", NpgsqlDbType.TimestampTZ).Value = DateTime.Now;
451
						dbCommand.Parameters.Add("@Data", NpgsqlDbType.Text).Value = serializedItems;
452
						dbCommand.Parameters.Add("@Flags", NpgsqlDbType.Integer).Value = 0;
453
					}
454
					else
455
					{
456
						// Update existing session
457
						dbCommand.CommandText = string.Format(CultureInfo.InvariantCulture, "UPDATE \"{0}\" SET \"Expires\" = @Expires, \"Locked\" = @Locked, \"Data\" = @Data WHERE \"SessionId\" = @SessionId AND \"ApplicationName\" = @ApplicationName AND \"LockId\" = @LockId", s_tableName);
418
                        throw new ProviderException(Properties.Resources.ErrOperationAborted);
419
                    }
420
                    finally
421
                    {
422
                        if (dbTrans != null)
423
                            dbTrans.Dispose();
458 424

  
459
						dbCommand.Parameters.Add("@Expires", NpgsqlDbType.TimestampTZ).Value = DateTime.Now.AddMinutes((Double)item.Timeout);
460
						dbCommand.Parameters.Add("@Locked", NpgsqlDbType.Boolean).Value = false;
461
						dbCommand.Parameters.Add("@Data", NpgsqlDbType.Text).Value = serializedItems;
462
						dbCommand.Parameters.Add("@SessionId", NpgsqlDbType.Varchar, 80).Value = id;
463
						dbCommand.Parameters.Add("@ApplicationName", NpgsqlDbType.Varchar, 255).Value = m_applicationName;
464
						dbCommand.Parameters.Add("@LockId", NpgsqlDbType.Integer).Value = lockId;
465
					}
425
                        if (dbConn != null)
426
                            dbConn.Close();
427
                    }
428
                }
429
            }
430
        }
466 431

  
467
					NpgsqlTransaction dbTrans = null;
432
        /// <summary>
433
        /// SessionStateProviderBase.SetAndReleaseItemExclusive
434
        /// </summary>
435
        public override void SetAndReleaseItemExclusive(HttpContext context, string id, SessionStateStoreData item, object lockId, bool newItem)
436
        {
437
            // Serialize the SessionStateItemCollection as a string
438
            string serializedItems = Serialize((SessionStateItemCollection)item.Items);
468 439

  
469
					try
470
					{
471
						dbConn.Open();
472
						dbTrans = dbConn.BeginTransaction();
440
            using (NpgsqlConnection dbConn = new NpgsqlConnection(m_connectionString))
441
            {
442
                using (NpgsqlCommand dbCommand = dbConn.CreateCommand(),
443
                        delCommand = dbConn.CreateCommand())
444
                {
445
                    if (newItem)
446
                    {
447
                        // Delete existing expired session if exist
448
                        delCommand.CommandText = string.Format(CultureInfo.InvariantCulture, "DELETE FROM \"{0}\" WHERE \"SessionId\" = @SessionId AND \"ApplicationName\" = @ApplicationName", s_tableName);
473 449

  
474
						if (newItem)
475
						{
476
							delCommand.Prepare();
477
							delCommand.ExecuteNonQuery();
478
						}
450
                        delCommand.Parameters.Add("@SessionId", NpgsqlDbType.Varchar, 80).Value = id;
451
                        delCommand.Parameters.Add("@ApplicationName", NpgsqlDbType.Varchar, 255).Value = m_applicationName;
479 452

  
480
						dbCommand.Prepare();
481
						dbCommand.ExecuteNonQuery();
453
                        // Insert new session data
454
                        dbCommand.CommandText = string.Format(CultureInfo.InvariantCulture, "INSERT INTO \"{0}\" (\"SessionId\", \"ApplicationName\", \"Created\", \"Expires\", \"Timeout\", \"Locked\", \"LockId\", \"LockDate\", \"Data\", \"Flags\") Values (@SessionId, @ApplicationName, @Created, @Expires, @Timeout, @Locked, @LockId, @LockDate, @Data, @Flags)", s_tableName);
482 455

  
483
						// Attempt to commit the transaction
484
						dbTrans.Commit();
485
					}
486
					catch (Exception e)
487
					{
488
						Trace.WriteLine(e.ToString());
456
                        dbCommand.Parameters.Add("@SessionId", NpgsqlDbType.Varchar, 80).Value = id;
457
                        dbCommand.Parameters.Add("@ApplicationName", NpgsqlDbType.Varchar, 255).Value = m_applicationName;
458
                        dbCommand.Parameters.Add("@Created", NpgsqlDbType.TimestampTZ).Value = DateTime.Now;
459
                        dbCommand.Parameters.Add("@Expires", NpgsqlDbType.TimestampTZ).Value = DateTime.Now.AddMinutes((Double)item.Timeout);
460
                        dbCommand.Parameters.Add("@Timeout", NpgsqlDbType.Integer).Value = item.Timeout;
461
                        dbCommand.Parameters.Add("@Locked", NpgsqlDbType.Boolean).Value = false;
462
                        dbCommand.Parameters.Add("@LockId", NpgsqlDbType.Integer).Value = 0;
463
                        dbCommand.Parameters.Add("@LockDate", NpgsqlDbType.TimestampTZ).Value = DateTime.Now;
464
                        dbCommand.Parameters.Add("@Data", NpgsqlDbType.Text).Value = serializedItems;
465
                        dbCommand.Parameters.Add("@Flags", NpgsqlDbType.Integer).Value = 0;
466
                    }
467
                    else
468
                    {
469
                        // Update existing session
470
                        dbCommand.CommandText = string.Format(CultureInfo.InvariantCulture, "UPDATE \"{0}\" SET \"Expires\" = @Expires, \"Locked\" = @Locked, \"Data\" = @Data WHERE \"SessionId\" = @SessionId AND \"ApplicationName\" = @ApplicationName AND \"LockId\" = @LockId", s_tableName);
489 471

  
490
						if (dbTrans != null)
491
						{
492
							try
493
							{
494
								// Attempt to roll back the transaction
495
								Trace.WriteLine(Properties.Resources.LogRollbackAttempt);
496
								dbTrans.Rollback();
497
							}
498
							catch (Exception re)
499
							{
500
								// Rollback failed
501
								Trace.WriteLine(Properties.Resources.ErrRollbackFailed);
502
								Trace.WriteLine(re.ToString());
503
							}
504
						}
472
                        dbCommand.Parameters.Add("@Expires", NpgsqlDbType.TimestampTZ).Value = DateTime.Now.AddMinutes((Double)item.Timeout);
473
                        dbCommand.Parameters.Add("@Locked", NpgsqlDbType.Boolean).Value = false;
474
                        dbCommand.Parameters.Add("@Data", NpgsqlDbType.Text).Value = serializedItems;
475
                        dbCommand.Parameters.Add("@SessionId", NpgsqlDbType.Varchar, 80).Value = id;
476
                        dbCommand.Parameters.Add("@ApplicationName", NpgsqlDbType.Varchar, 255).Value = m_applicationName;
477
                        dbCommand.Parameters.Add("@LockId", NpgsqlDbType.Integer).Value = lockId;
478
                    }
505 479

  
506
						throw new ProviderException(Properties.Resources.ErrOperationAborted);
507
					}
508
					finally
509
					{
510
						if (dbTrans != null)
511
							dbTrans.Dispose();
480
                    NpgsqlTransaction dbTrans = null;
512 481

  
513
						if (dbConn != null)
514
							dbConn.Close();
515
					}
516
				}
517
			}
518
		}
482
                    try
483
                    {
484
                        dbConn.Open();
485
                        dbTrans = dbConn.BeginTransaction();
519 486

  
520
		/// <summary>
521
		/// SessionStateProviderBase.SetItemExpireCallback
522
		/// </summary>
523
		public override bool SetItemExpireCallback(SessionStateItemExpireCallback expireCallback)
524
		{
525
			// Accept and store callback if session expire callback is enabled. If not, return false in order to inform SessionStateModule
526
			// the session expire callback is not supported.
527
			if (!m_enableExpireCallback)
528
				return false;
487
                        if (newItem)
488
                        {
489
                            delCommand.Prepare();
490
                            delCommand.ExecuteNonQuery();
491
                        }
529 492

  
530
			m_expireCallback = expireCallback;
531
			return true;
532
		}
493
                        dbCommand.Prepare();
494
                        dbCommand.ExecuteNonQuery();
533 495

  
534
		#endregion
496
                        // Attempt to commit the transaction
497
                        dbTrans.Commit();
498
                    }
499
                    catch (Exception e)
500
                    {
501
                        Trace.WriteLine(e.ToString());
535 502

  
536
		#region private methods
503
                        if (dbTrans != null)
504
                        {
505
                            try
506
                            {
507
                                // Attempt to roll back the transaction
508
                                Trace.WriteLine(Properties.Resources.LogRollbackAttempt);
509
                                dbTrans.Rollback();
510
                            }
511
                            catch (Exception re)
512
                            {
513
                                // Rollback failed
514
                                Trace.WriteLine(Properties.Resources.ErrRollbackFailed);
515
                                Trace.WriteLine(re.ToString());
516
                            }
517
                        }
537 518

  
538
		/// <summary>
539
		/// Retrieves the session data from the data source.
540
		/// </summary>
541
		/// <param name="lockRecord">If true GetSessionStoreItem locks the record and sets a new LockId and LockDate.</param>	
542
		private SessionStateStoreData GetSessionStoreItem(bool lockRecord, HttpContext context, string id, out bool locked, out TimeSpan lockAge, out object lockId, out SessionStateActions actionFlags)
543
		{
544
			SessionStateStoreData result = null;
545
			lockAge = TimeSpan.Zero;
546
			lockId = null;
547
			locked = false;
548
			actionFlags = 0;
549
			DateTime expires = DateTime.MinValue;
550
			int timeout = 0;
551
			string serializedItems = null;
519
                        throw new ProviderException(Properties.Resources.ErrOperationAborted);
520
                    }
521
                    finally
522
                    {
523
                        if (dbTrans != null)
524
                            dbTrans.Dispose();
552 525

  
553
			using (NpgsqlConnection dbConn = new NpgsqlConnection(m_connectionString))
554
			{
555
				NpgsqlTransaction dbTrans = null;
556
				try
557
				{
558
					dbConn.Open();
559
					dbTrans = dbConn.BeginTransaction();
526
                        if (dbConn != null)
527
                            dbConn.Close();
528
                    }
529
                }
530
            }
531
        }
560 532

  
561
					// Retrieve the current session item information and lock row
562
					using (NpgsqlCommand dbCommand = dbConn.CreateCommand())
563
					{
564
						dbCommand.CommandText = string.Format(CultureInfo.InvariantCulture, "SELECT \"Expires\", \"Timeout\", \"Locked\", \"LockId\", \"LockDate\", \"Data\", \"Flags\" FROM \"{0}\" WHERE \"SessionId\" = @SessionId AND \"ApplicationName\" = @ApplicationName FOR UPDATE", s_tableName);
533
        /// <summary>
534
        /// SessionStateProviderBase.SetItemExpireCallback
535
        /// </summary>
536
        public override bool SetItemExpireCallback(SessionStateItemExpireCallback expireCallback)
537
        {
538
            // Accept and store callback if session expire callback is enabled. If not, return false in order to inform SessionStateModule
539
            // the session expire callback is not supported.
540
            if (!m_enableExpireCallback)
541
                return false;
565 542

  
566
						dbCommand.Parameters.Add("@SessionId", NpgsqlDbType.Varchar, 80).Value = id;
567
						dbCommand.Parameters.Add("@ApplicationName", NpgsqlDbType.Varchar, 255).Value = m_applicationName;
543
            m_expireCallback = expireCallback;
544
            return true;
545
        }
568 546

  
569
						using (NpgsqlDataReader reader = dbCommand.ExecuteReader(System.Data.CommandBehavior.SingleRow))
570
						{
571
							while (reader.Read())
572
							{
573
								expires = reader.GetDateTime(0);
574
								timeout = reader.GetInt32(1);
575
								locked = reader.GetBoolean(2);
576
								lockId = reader.GetInt32(3);
577
								lockAge = DateTime.Now.Subtract(reader.GetDateTime(4));
547
        #endregion
578 548

  
579
								if (!reader.IsDBNull(5))
580
									serializedItems = reader.GetString(5);
549
        #region private methods
581 550

  
582
								actionFlags = (SessionStateActions)reader.GetInt32(6);
583
							}
584
							reader.Close();
585
						}
586
					}
551
        /// <summary>
552
        /// Retrieves the session data from the data source.
553
        /// </summary>
554
        /// <param name="lockRecord">If true GetSessionStoreItem locks the record and sets a new LockId and LockDate.</param>	
555
        private SessionStateStoreData GetSessionStoreItem(bool lockRecord, HttpContext context, string id, out bool locked, out TimeSpan lockAge, out object lockId, out SessionStateActions actionFlags)
556
        {
557
            SessionStateStoreData result = null;
558
            lockAge = TimeSpan.Zero;
559
            lockId = null;
560
            locked = false;
561
            actionFlags = 0;
562
            DateTime expires = DateTime.MinValue;
563
            int timeout = 0;
564
            string serializedItems = null;
587 565

  
588
					// If record was not found, is expired or is locked, return.
589
					if (expires < DateTime.Now || locked)
590
						return result;
566
            using (NpgsqlConnection dbConn = new NpgsqlConnection(m_connectionString))
567
            {
568
                NpgsqlTransaction dbTrans = null;
569
                try
570
                {
571
                    dbConn.Open();
572
                    dbTrans = dbConn.BeginTransaction();
591 573

  
592
					// If the actionFlags parameter is not InitializeItem, deserialize the stored SessionStateItemCollection
593
					if (actionFlags == SessionStateActions.InitializeItem)
594
						result = CreateNewStoreData(context, Convert.ToInt32(m_config.Timeout.TotalMinutes));
595
					else
596
						result = new SessionStateStoreData(Deserialize(serializedItems), SessionStateUtility.GetSessionStaticObjects(context), Convert.ToInt32(m_config.Timeout.TotalMinutes));
574
                    // Retrieve the current session item information and lock row
575
                    using (NpgsqlCommand dbCommand = dbConn.CreateCommand())
576
                    {
577
                        dbCommand.CommandText = string.Format(CultureInfo.InvariantCulture, "SELECT \"Expires\", \"Timeout\", \"Locked\", \"LockId\", \"LockDate\", \"Data\", \"Flags\" FROM \"{0}\" WHERE \"SessionId\" = @SessionId AND \"ApplicationName\" = @ApplicationName FOR UPDATE", s_tableName);
597 578

  
598
					if (lockRecord)
599
					{
600
						lockId = (int)lockId + 1;
601
						// Obtain a lock to the record
602
						using (NpgsqlCommand dbCommand = dbConn.CreateCommand())
603
						{
604
							dbCommand.CommandText = string.Format(CultureInfo.InvariantCulture, "UPDATE \"{0}\" SET \"Locked\" = @Locked, \"LockId\" = @LockId,\"LockDate\" = @LockDate, \"Flags\" = @Flags WHERE \"SessionId\" = @SessionId AND \"ApplicationName\" = @ApplicationName", s_tableName);
579
                        dbCommand.Parameters.Add("@SessionId", NpgsqlDbType.Varchar, 80).Value = id;
580
                        dbCommand.Parameters.Add("@ApplicationName", NpgsqlDbType.Varchar, 255).Value = m_applicationName;
605 581

  
606
							dbCommand.Parameters.Add("@Locked", NpgsqlDbType.Boolean).Value = true;
607
							dbCommand.Parameters.Add("@LockId", NpgsqlDbType.Integer).Value = lockId;
608
							dbCommand.Parameters.Add("@LockDate", NpgsqlDbType.TimestampTZ).Value = DateTime.Now;
609
							dbCommand.Parameters.Add("@Flags", NpgsqlDbType.Integer).Value = 0;
610
							dbCommand.Parameters.Add("@SessionId", NpgsqlDbType.Varchar, 80).Value = id;
611
							dbCommand.Parameters.Add("@ApplicationName", NpgsqlDbType.Varchar, 255).Value = m_applicationName;
582
                        using (NpgsqlDataReader reader = dbCommand.ExecuteReader(System.Data.CommandBehavior.SingleRow))
583
                        {
584
                            while (reader.Read())
585
                            {
586
                                expires = reader.GetDateTime(0);
587
                                timeout = reader.GetInt32(1);
588
                                locked = reader.GetBoolean(2);
589
                                lockId = reader.GetInt32(3);
590
                                lockAge = DateTime.Now.Subtract(reader.GetDateTime(4));
612 591

  
613
							dbCommand.ExecuteNonQuery();
614
						}
615
					}
592
                                if (!reader.IsDBNull(5))
593
                                    serializedItems = reader.GetString(5);
616 594

  
617
					// Attempt to commit the transaction
618
					dbTrans.Commit();
619
				}
620
				catch (Exception e)
621
				{
622
					Trace.WriteLine(e.ToString());
595
                                actionFlags = (SessionStateActions)reader.GetInt32(6);
596
                            }
597
                            reader.Close();
598
                        }
599
                    }
623 600

  
624
					if (dbTrans != null)
625
					{
626
						try
627
						{
628
							// Attempt to roll back the transaction
629
							Trace.WriteLine(Properties.Resources.LogRollbackAttempt);
630
							dbTrans.Rollback();
631
						}
632
						catch (Exception re)
633
						{
634
							// Rollback failed
635
							Trace.WriteLine(Properties.Resources.ErrRollbackFailed);
636
							Trace.WriteLine(re.ToString());
637
						}
638
					}
601
                    // If record was not found, is expired or is locked, return.
602
                    if (expires < DateTime.Now || locked)
603
                        return result;
639 604

  
640
					throw new ProviderException(Properties.Resources.ErrOperationAborted);
641
				}
642
				finally
643
				{
644
					if (dbTrans != null)
645
						dbTrans.Dispose();
605
                    // If the actionFlags parameter is not InitializeItem, deserialize the stored SessionStateItemCollection
606
                    if (actionFlags == SessionStateActions.InitializeItem)
607
                        result = CreateNewStoreData(context, Convert.ToInt32(m_config.Timeout.TotalMinutes));
608
                    else
609
                        result = new SessionStateStoreData(Deserialize(serializedItems), SessionStateUtility.GetSessionStaticObjects(context), Convert.ToInt32(m_config.Timeout.TotalMinutes));
646 610

  
647
					if (dbConn != null)
648
						dbConn.Close();
649
				}
611
                    if (lockRecord)
612
                    {
613
                        lockId = (int)lockId + 1;
614
                        // Obtain a lock to the record
615
                        using (NpgsqlCommand dbCommand = dbConn.CreateCommand())
616
                        {
617
                            dbCommand.CommandText = string.Format(CultureInfo.InvariantCulture, "UPDATE \"{0}\" SET \"Locked\" = @Locked, \"LockId\" = @LockId,\"LockDate\" = @LockDate, \"Flags\" = @Flags WHERE \"SessionId\" = @SessionId AND \"ApplicationName\" = @ApplicationName", s_tableName);
650 618

  
651
				return result;
652
			}
653
		}
619
                            dbCommand.Parameters.Add("@Locked", NpgsqlDbType.Boolean).Value = true;
620
                            dbCommand.Parameters.Add("@LockId", NpgsqlDbType.Integer).Value = lockId;
621
                            dbCommand.Parameters.Add("@LockDate", NpgsqlDbType.TimestampTZ).Value = DateTime.Now;
622
                            dbCommand.Parameters.Add("@Flags", NpgsqlDbType.Integer).Value = 0;
623
                            dbCommand.Parameters.Add("@SessionId", NpgsqlDbType.Varchar, 80).Value = id;
624
                            dbCommand.Parameters.Add("@ApplicationName", NpgsqlDbType.Varchar, 255).Value = m_applicationName;
654 625

  
655
		/// <summary>
656
		/// Convert a SessionStateItemCollection into a Base64 string
657
		/// </summary>
658
		private static string Serialize(SessionStateItemCollection items)
659
		{
660
			if (items == null || items.Count < 1)
661
				return string.Empty;
626
                            dbCommand.ExecuteNonQuery();
627
                        }
628
                    }
662 629

  
663
			using (MemoryStream mStream = new MemoryStream())
664
			{
665
				using (BinaryWriter bWriter = new BinaryWriter(mStream))
666
				{
667
					items.Serialize(bWriter);
668
					bWriter.Close();
669
				}
630
                    // Attempt to commit the transaction
631
                    dbTrans.Commit();
632
                }
633
                catch (Exception e)
634
                {
635
                    Trace.WriteLine(e.ToString());
670 636

  
671
				return Convert.ToBase64String(mStream.ToArray());
672
			}
673
		}
637
                    if (dbTrans != null)
638
                    {
639
                        try
640
                        {
641
                            // Attempt to roll back the transaction
642
                            Trace.WriteLine(Properties.Resources.LogRollbackAttempt);
643
                            dbTrans.Rollback();
644
                        }
645
                        catch (Exception re)
646
                        {
647
                            // Rollback failed
648
                            Trace.WriteLine(Properties.Resources.ErrRollbackFailed);
649
                            Trace.WriteLine(re.ToString());
650
                        }
651
                    }
674 652

  
675
		/// <summary>
676
		/// Convert a Base64 string into a SessionStateItemCollection
677
		/// </summary>
678
		/// <param name="serializedItems"></param>
679
		/// <returns></returns>
680
		private static SessionStateItemCollection Deserialize(string serializedItems)
681
		{
682
			SessionStateItemCollection sessionItems = new SessionStateItemCollection();
653
                    throw new ProviderException(Properties.Resources.ErrOperationAborted);
654
                }
655
                finally
656
                {
657
                    if (dbTrans != null)
658
                        dbTrans.Dispose();
683 659

  
684
			if (string.IsNullOrEmpty(serializedItems))
685
				return sessionItems;
660
                    if (dbConn != null)
661
                        dbConn.Close();
662
                }
686 663

  
687
			using (MemoryStream mStream = new MemoryStream(Convert.FromBase64String(serializedItems)))
688
			{
689
				using (BinaryReader bReader = new BinaryReader(mStream))
690
				{
691
					sessionItems = SessionStateItemCollection.Deserialize(bReader);
692
					bReader.Close();
693
				}
694
			}
664
                return result;
665
            }
666
        }
695 667

  
696
			return sessionItems;
697
		}
668
        /// <summary>
669
        /// Convert a SessionStateItemCollection into a Base64 string
670
        /// </summary>
671
        private static string Serialize(SessionStateItemCollection items)
672
        {
673
            if (items == null || items.Count < 1)
674
                return string.Empty;
698 675

  
699
		/// <summary>
700
		/// The ExpiredSessionDeletionTimer_Elapsed performs automatic session garbage collection by removing expired sessions from
701
		/// the database.
702
		/// </summary>
703
		/// <param name="source"></param>
704
		/// <param name="e"></param>
705
		private void ExpiredSessionDeletionTimer_Elapsed(object source, System.Timers.ElapsedEventArgs e)
706
		{
707
			/*
708
			 * Determine mode of session garbage collection. If the session expire callback is disabled
709
			 * one may simple delete all expired session from the session table. If however the session expire callback
710
			 * is enabled, we need to load the session data for every expired session and invoke the expire callback
711
			 * for each of these sessions prior to deletion.
712
			 * Also check if an expire call back was actually defined. If m_expireCallback is null we also don't have to take
713
			 * the more expensive path where every session is enumerated while there's no real need to do so.
714
			 */
676
            using (MemoryStream mStream = new MemoryStream())
677
            {
678
                using (BinaryWriter bWriter = new BinaryWriter(mStream))
679
                {
680
                    items.Serialize(bWriter);
681
                    bWriter.Close();
682
                }
715 683

  
716
			if (m_enableExpireCallback && m_expireCallback != null)
717
				InvokeExpireCallbackAndDeleteSession();
684
                return Convert.ToBase64String(mStream.ToArray());
685
            }
686
        }
718 687

  
719
			else
720
				DeleteExpiredSessionsFromDatabase();
721
		}
688
        /// <summary>
689
        /// Convert a Base64 string into a SessionStateItemCollection
690
        /// </summary>
691
        /// <param name="serializedItems"></param>
692
        /// <returns></returns>
693
        private static SessionStateItemCollection Deserialize(string serializedItems)
694
        {
695
            SessionStateItemCollection sessionItems = new SessionStateItemCollection();
722 696

  
723
		/// <summary>
724
		/// Load the session data for every expired session and invoke the expire callback
725
		/// for each of these sessions prior to deletion.
726
		/// </summary>
727
		private void InvokeExpireCallbackAndDeleteSession()
728
		{
729
			Dictionary<string, SessionStateStoreData> expiredSessions = null;
697
            if (string.IsNullOrEmpty(serializedItems))
698
                return sessionItems;
730 699

  
731
			// Start out by enumerating all expired sessions
732
			using (NpgsqlConnection dbConn = new NpgsqlConnection(m_connectionString))
733
			{
734
				using (NpgsqlCommand selectCommand = dbConn.CreateCommand())
735
				{
736
					selectCommand.CommandText = string.Format(CultureInfo.InvariantCulture, "SELECT \"SessionId\", \"Data\" FROM \"{0}\" WHERE \"Expires\" < @Expires AND \"ApplicationName\" = @ApplicationName", s_tableName);
700
            using (MemoryStream mStream = new MemoryStream(Convert.FromBase64String(serializedItems)))
701
            {
702
                using (BinaryReader bReader = new BinaryReader(mStream))
703
                {
704
                    sessionItems = SessionStateItemCollection.Deserialize(bReader);
705
                    bReader.Close();
706
                }
707
            }
737 708

  
738
					selectCommand.Parameters.Add("@Expires", NpgsqlDbType.TimestampTZ).Value = DateTime.Now;
739
					selectCommand.Parameters.Add("@ApplicationName", NpgsqlDbType.Varchar, 255).Value = m_applicationName;
709
            return sessionItems;
710
        }
740 711

  
741
					try
742
					{
743
						dbConn.Open();
744
						selectCommand.Prepare();
712
        /// <summary>
713
        /// The ExpiredSessionDeletionTimer_Elapsed performs automatic session garbage collection by removing expired sessions from
714
        /// the database.
715
        /// </summary>
716
        /// <param name="source"></param>
717
        /// <param name="e"></param>
718
        private void ExpiredSessionDeletionTimer_Elapsed(object source, System.Timers.ElapsedEventArgs e)
719
        {
720
            /*
721
             * Determine mode of session garbage collection. If the session expire callback is disabled
722
             * one may simple delete all expired session from the session table. If however the session expire callback
723
             * is enabled, we need to load the session data for every expired session and invoke the expire callback
724
             * for each of these sessions prior to deletion.
725
             * Also check if an expire call back was actually defined. If m_expireCallback is null we also don't have to take
726
             * the more expensive path where every session is enumerated while there's no real need to do so.
727
             */
745 728

  
746
						using (NpgsqlDataReader reader = selectCommand.ExecuteReader())
747
						{
748
							if (!reader.HasRows)
749
								return;
729
            if (m_enableExpireCallback && m_expireCallback != null)
730
                InvokeExpireCallbackAndDeleteSession();
750 731

  
751
							expiredSessions = new Dictionary<string, SessionStateStoreData>(reader.RecordsAffected);
732
            else
733
                DeleteExpiredSessionsFromDatabase();
734
        }
752 735

  
753
							// Get session data from data reader and reconstruct session.
754
							// NOTE:	I'm not sure if I should pass any static objects to the constructor of the SessionStateStoreData class.
755
							//			Seems to me you should not since garbage collection is say highly unlikely to be run in an actual http context.
756
							while (reader.Read())
757
							{
758
								string sessionId = reader.GetString(0);
759
								string serializedItems = reader.IsDBNull(1) ? null : reader.GetString(1);
736
        /// <summary>
737
        /// Load the session data for every expired session and invoke the expire callback
738
        /// for each of these sessions prior to deletion.
739
        /// </summary>
740
        private void InvokeExpireCallbackAndDeleteSession()
741
        {
742
            Dictionary<string, SessionStateStoreData> expiredSessions = null;
760 743

  
761
								expiredSessions.Add(sessionId, new SessionStateStoreData(Deserialize(serializedItems), new HttpStaticObjectsCollection(), Convert.ToInt32(m_config.Timeout.TotalMinutes)));
762
							}
763
						}
764
					}
765
					catch (Exception ex)
766
					{
767
						Trace.WriteLine(ex.ToString());
744
            // Start out by enumerating all expired sessions
745
            using (NpgsqlConnection dbConn = new NpgsqlConnection(m_connectionString))
746
            {
747
                using (NpgsqlCommand selectCommand = dbConn.CreateCommand())
748
                {
749
                    selectCommand.CommandText = string.Format(CultureInfo.InvariantCulture, "SELECT \"SessionId\", \"Data\" FROM \"{0}\" WHERE \"Expires\" < @Expires AND \"ApplicationName\" = @ApplicationName", s_tableName);
768 750

  
769
						if (dbConn != null)
770
							dbConn.Close();
751
                    selectCommand.Parameters.Add("@Expires", NpgsqlDbType.TimestampTZ).Value = DateTime.Now;
752
                    selectCommand.Parameters.Add("@ApplicationName", NpgsqlDbType.Varchar, 255).Value = m_applicationName;
771 753

  
772
						throw new ProviderException(Properties.Resources.ErrOperationAborted);
773
					}
774
				}
754
                    try
755
                    {
756
                        dbConn.Open();
757
                        selectCommand.Prepare();
775 758

  
776
				using (NpgsqlCommand deleteCommand = dbConn.CreateCommand())
777
				{
778
					deleteCommand.CommandText = string.Format(CultureInfo.InvariantCulture, "DELETE FROM \"{0}\" WHERE \"SessionId\" = @SessionId AND \"ApplicationName\" = @ApplicationName", s_tableName);
759
                        using (NpgsqlDataReader reader = selectCommand.ExecuteReader())
760
                        {
761
                            if (!reader.HasRows)
762
                                return;
779 763

  
780
					deleteCommand.Parameters.Add("@SessionId", NpgsqlDbType.Varchar, 80);
781
					deleteCommand.Parameters.Add("@ApplicationName", NpgsqlDbType.Varchar, 255).Value = m_applicationName;
764
                            expiredSessions = new Dictionary<string, SessionStateStoreData>(reader.RecordsAffected);
782 765

  
783
					NpgsqlTransaction dbTrans = null;
766
                            // Get session data from data reader and reconstruct session.
767
                            // NOTE:	I'm not sure if I should pass any static objects to the constructor of the SessionStateStoreData class.
768
                            //			Seems to me you should not since garbage collection is say highly unlikely to be run in an actual http context.
769
                            while (reader.Read())
770
                            {
771
                                string sessionId = reader.GetString(0);
772
                                string serializedItems = reader.IsDBNull(1) ? null : reader.GetString(1);
784 773

  
785
					try
786
					{
787
						deleteCommand.Prepare();
788
						dbTrans = dbConn.BeginTransaction();
774
                                expiredSessions.Add(sessionId, new SessionStateStoreData(Deserialize(serializedItems), new HttpStaticObjectsCollection(), Convert.ToInt32(m_config.Timeout.TotalMinutes)));
775
                            }
776
                        }
777
                    }
778
                    catch (Exception ex)
779
                    {
780
                        Trace.WriteLine(ex.ToString());
789 781

  
790
						// Actually invoke session expire callback and delete session from the session table.
791
						foreach (KeyValuePair<string, SessionStateStoreData> expiredSession in expiredSessions)
792
						{
793
							// TODO: use async invocation insted?
794
							m_expireCallback.Invoke(expiredSession.Key, expiredSession.Value);
782
                        if (dbConn != null)
783
                            dbConn.Close();
795 784

  
796
							deleteCommand.Parameters["@SessionId"].Value = expiredSession.Key;
785
                        throw new ProviderException(Properties.Resources.ErrOperationAborted);
786
                    }
787
                }
797 788

  
798
							deleteCommand.ExecuteNonQuery();
799
						}
789
                using (NpgsqlCommand deleteCommand = dbConn.CreateCommand())
790
                {
791
                    deleteCommand.CommandText = string.Format(CultureInfo.InvariantCulture, "DELETE FROM \"{0}\" WHERE \"SessionId\" = @SessionId AND \"ApplicationName\" = @ApplicationName", s_tableName);
800 792

  
801
						// Attempt to commit the transaction
802
						dbTrans.Commit();
803
					}
804
					catch (Exception ex)
805
					{
806
						Trace.WriteLine(ex.ToString());
793
                    deleteCommand.Parameters.Add("@SessionId", NpgsqlDbType.Varchar, 80);
794
                    deleteCommand.Parameters.Add("@ApplicationName", NpgsqlDbType.Varchar, 255).Value = m_applicationName;
807 795

  
808
						if (dbTrans != null)
809
						{
810
							try
811
							{
812
								// Attempt to roll back the transaction
813
								Trace.WriteLine(Properties.Resources.LogRollbackAttempt);
814
								dbTrans.Rollback();
815
							}
816
							catch (Exception re)
817
							{
818
								// Rollback failed
819
								Trace.WriteLine(Properties.Resources.ErrRollbackFailed);
820
								Trace.WriteLine(re.ToString());
821
							}
822
						}
796
                    NpgsqlTransaction dbTrans = null;
823 797

  
824
						throw new ProviderException(Properties.Resources.ErrOperationAborted);
825
					}
826
					finally
827
					{
828
						if (dbTrans != null)
829
							dbTrans.Dispose();
798
                    try
799
                    {
800
                        deleteCommand.Prepare();
801
                        dbTrans = dbConn.BeginTransaction();
830 802

  
831
						if (dbConn != null)
832
							dbConn.Close();
833
					}
834
				}
835
			}
836
		}
803
                        // Actually invoke session expire callback and delete session from the session table.
804
                        foreach (KeyValuePair<string, SessionStateStoreData> expiredSession in expiredSessions)
805
                        {
806
                            // TODO: use async invocation insted?
807
                            m_expireCallback.Invoke(expiredSession.Key, expiredSession.Value);
837 808

  
838
		/// <summary>
839
		/// Delete all expired session from the session table.
840
		/// </summary>
841
		private void DeleteExpiredSessionsFromDatabase()
842
		{
843
			using (NpgsqlConnection dbConn = new NpgsqlConnection(m_connectionString))
844
			{
845
				using (NpgsqlCommand dbCommand = dbConn.CreateCommand())
846
				{
847
					dbCommand.CommandText = string.Format(CultureInfo.InvariantCulture, "DELETE FROM \"{0}\" WHERE \"Expires\" < @Expires AND \"ApplicationName\" = @ApplicationName", s_tableName);
809
                            deleteCommand.Parameters["@SessionId"].Value = expiredSession.Key;
848 810

  
849
					dbCommand.Parameters.Add("@Expires", NpgsqlDbType.TimestampTZ).Value = DateTime.Now;
850
					dbCommand.Parameters.Add("@ApplicationName", NpgsqlDbType.Varchar, 255).Value = m_applicationName;
811
                            deleteCommand.ExecuteNonQuery();
812
                        }
851 813

  
852
					NpgsqlTransaction dbTrans = null;
814
                        // Attempt to commit the transaction
815
                        dbTrans.Commit();
816
                    }
817
                    catch (Exception ex)
818
                    {
819
                        Trace.WriteLine(ex.ToString());
853 820

  
854
					try
855
					{
856
						dbConn.Open();
857
						dbCommand.Prepare();
821
                        if (dbTrans != null)
822
                        {
823
                            try
824
                            {
825
                                // Attempt to roll back the transaction
826
                                Trace.WriteLine(Properties.Resources.LogRollbackAttempt);
827
                                dbTrans.Rollback();
828
                            }
829
                            catch (Exception re)
830
                            {
831
                                // Rollback failed
832
                                Trace.WriteLine(Properties.Resources.ErrRollbackFailed);
833
                                Trace.WriteLine(re.ToString());
834
                            }
835
                        }
858 836

  
859
						dbTrans = dbConn.BeginTransaction();
837
                        throw new ProviderException(Properties.Resources.ErrOperationAborted);
838
                    }
839
                    finally
840
                    {
841
                        if (dbTrans != null)
842
                            dbTrans.Dispose();
860 843

  
861
						dbCommand.ExecuteNonQuery();
844
                        if (dbConn != null)
845
                            dbConn.Close();
846
                    }
847
                }
848
            }
849
        }
862 850

  
863
						// Attempt to commit the transaction
864
						dbTrans.Commit();
865
					}
866
					catch (Exception ex)
867
					{
868
						Trace.WriteLine(ex.ToString());
... This diff was truncated because it exceeds the maximum size that can be displayed.