public override void CreateUninitializedItem(HttpContext context, string id, int timeout)
        {
            SecUtility.CheckParameter(ref id, true, true, false, ProviderConfiguration.MaxStringPropertySizeInChars, "id");
            if (timeout < 0)
            {
                throw new ArgumentException("Parameter timeout must be a non-negative integer!");
            }

            try
            {
                TableServiceContext svc = CreateDataServiceContext();
                var session = new SessionRow(id, applicationName)
                                  {
                                      Lock = 0,
                                      Initialized = false,
                                      Id = id,
                                      Timeout = timeout,
                                      ExpiresUtc = DateTime.UtcNow.AddMinutes(timeout)
                                  };

                svc.AddObject(tableName, session);
                svc.SaveChangesWithRetries();
            }
            catch (InvalidOperationException e)
            {
                var innerEx = e.InnerException as DataServiceClientException;
                if (innerEx != null && innerEx.StatusCode == (int) HttpStatusCode.Conflict)
                {
                    // the data already exists so we can return because we are reusing a session
                    return;
                }
                throw new ProviderException("Error accessing the data store.", e);
            }
        }
Пример #2
0
        public override void CreateUninitializedItem(HttpContext context, string id, int timeout)
        {
            SecUtility.CheckParameter(ref id, true, true, false, ProviderConfiguration.MaxStringPropertySizeInChars, "id");
            if (timeout < 0)
            {
                throw new ArgumentException("Parameter timeout must be a non-negative integer!");
            }

            try
            {
                TableServiceContext svc = CreateDataServiceContext();
                var session             = new SessionRow(id, applicationName)
                {
                    Lock        = 0,
                    Initialized = false,
                    Id          = id,
                    Timeout     = timeout,
                    ExpiresUtc  = DateTime.UtcNow.AddMinutes(timeout)
                };

                svc.AddObject(tableName, session);
                svc.SaveChangesWithRetries();
            }
            catch (InvalidOperationException e)
            {
                var innerEx = e.InnerException as DataServiceClientException;
                if (innerEx != null && innerEx.StatusCode == (int)HttpStatusCode.Conflict)
                {
                    // the data already exists so we can return because we are reusing a session
                    return;
                }
                throw new ProviderException("Error accessing the data store.", e);
            }
        }
Пример #3
0
        public override void RemoveItem(HttpContext context, string id, object lockId, SessionStateStoreData item)
        {
            SecUtility.CheckParameter(ref id, true, true, false, ProviderConfiguration.MaxStringPropertySizeInChars, "id");

            try
            {
                TableServiceContext svc     = CreateDataServiceContext();
                SessionRow          session = GetSession(id, svc);
                if (session == null)
                {
                    return;
                }

                if (session.Lock != (int)lockId)
                {
                    return;
                }

                svc.DeleteObject(session);
                svc.SaveChangesWithRetries();
            }
            catch (InvalidOperationException e)
            {
                throw new ProviderException("Error accessing the data store!", e);
            }

            // delete associated blobs
            try
            {
                IEnumerable <IListBlobItem> e = blobProvider.ListBlobs(GetBlobNamePrefix(id));
                if (e == null)
                {
                    return;
                }

                IEnumerator <IListBlobItem> props = e.GetEnumerator();
                if (props == null)
                {
                    return;
                }

                while (props.MoveNext())
                {
                    if (props.Current != null)
                    {
                        if (!blobProvider.DeleteBlob(props.Current.Uri.ToString()))
                        {
                            // ignore this; it is possible that another thread could try to delete the blob
                            // at the same time
                        }
                    }
                }
            }
            catch (Exception e)
            {
                throw new ProviderException("Error accessing blob storage.", e);
            }
        }
Пример #4
0
        private static void ReleaseItemExclusive(TableServiceContext svc, SessionRow session, object lockId)
        {
            if ((int)lockId != session.Lock)
            {
                return;
            }

            session.ExpiresUtc = DateTime.UtcNow.AddMinutes(session.Timeout);
            session.Locked     = false;
            svc.UpdateObject(session);
            svc.SaveChangesWithRetries();
        }
Пример #5
0
        public override void ResetItemTimeout(HttpContext context, string id)
        {
            SecUtility.CheckParameter(ref id, true, true, false, ProviderConfiguration.MaxStringPropertySizeInChars, "id");

            providerRetry(() =>
            {
                TableServiceContext svc = CreateDataServiceContext();
                SessionRow session      = GetSession(id, svc);
                session.ExpiresUtc      = DateTime.UtcNow.AddMinutes(session.Timeout);
                svc.UpdateObject(session);
                svc.SaveChangesWithRetries();
            });
        }
Пример #6
0
        public override void ReleaseItemExclusive(HttpContext context, string id, object lockId)
        {
            SecUtility.CheckParameter(ref id, true, true, false, ProviderConfiguration.MaxStringPropertySizeInChars, "id");

            try
            {
                TableServiceContext svc     = CreateDataServiceContext();
                SessionRow          session = GetSession(id, svc);
                ReleaseItemExclusive(svc, session, lockId);
            }
            catch (InvalidOperationException e)
            {
                throw new ProviderException("Error accessing the data store!", e);
            }
        }
        private static void ReleaseItemExclusive(TableServiceContext svc, SessionRow session, object lockId)
        {
            if ((int) lockId != session.Lock)
            {
                return;
            }

            session.ExpiresUtc = DateTime.UtcNow.AddMinutes(session.Timeout);
            session.Locked = false;
            svc.UpdateObject(session);
            svc.SaveChangesWithRetries();
        }
        public override void SetAndReleaseItemExclusive(HttpContext context, string id, SessionStateStoreData item, object lockId, bool newItem)
        {
            SecUtility.CheckParameter(ref id, true, true, false, ProviderConfiguration.MaxStringPropertySizeInChars, "id");

            providerRetry(() =>
                              {
                                  TableServiceContext svc = CreateDataServiceContext();
                                  SessionRow session;

                                  if (!newItem)
                                  {
                                      session = GetSession(id, svc);
                                      if (session == null || session.Lock != (int) lockId)
                                      {
                                          return;
                                      }
                                  }
                                  else
                                  {
                                      session = new SessionRow(id, applicationName)
                                                    {
                                                        Lock = 1,
                                                        LockDateUtc = DateTime.UtcNow
                                                    };
                                  }

                                  session.Initialized = true;
                                  session.Timeout = item.Timeout;
                                  session.ExpiresUtc = DateTime.UtcNow.AddMinutes(session.Timeout);
                                  session.Locked = false;

                                  // yes, we always create a new blob here
                                  session.BlobName = GetBlobNamePrefix(id) + Guid.NewGuid().ToString("N");

                                  // Serialize the session and write the blob
                                  byte[] items, statics;
                                  SerializeSession(item, out items, out statics);
                                  string serializedItems = Convert.ToBase64String(items);
                                  string serializedStatics = Convert.ToBase64String(statics);
                                  var output = new MemoryStream();
                                  var writer = new StreamWriter(output);

                                  try
                                  {
                                      writer.WriteLine(serializedItems);
                                      writer.WriteLine(serializedStatics);
                                      writer.Flush();

                                      // for us, it shouldn't matter whether newItem is set to true or false
                                      // because we always create the entire blob and cannot append to an
                                      // existing one
                                      blobProvider.UploadStream(session.BlobName, output);
                                      writer.Close();
                                      output.Close();
                                  }
                                  catch (Exception e)
                                  {
                                      if (!newItem)
                                      {
                                          ReleaseItemExclusive(svc, session, lockId);
                                      }

                                      throw new ProviderException("Error accessing the data store.", e);
                                  }
                                  finally
                                  {
                                      writer.Close();
                                      output.Close();
                                  }

                                  if (newItem)
                                  {
                                      svc.AddObject(tableName, session);
                                      svc.SaveChangesWithRetries();
                                  }
                                  else
                                  {
                                      // Unlock the session and save changes
                                      ReleaseItemExclusive(svc, session, lockId);
                                  }
                              });
        }
Пример #9
0
        // we don't use the retry policy itself in this function because out parameters are not well handled by
        // retry policies
        private SessionStateStoreData GetSession(HttpContext context, string id, out bool locked, out TimeSpan lockAge, out object lockId, out SessionStateActions actions,
                                                 bool exclusive)
        {
            SecUtility.CheckParameter(ref id, true, true, false, ProviderConfiguration.MaxStringPropertySizeInChars, "id");

            SessionRow session = null;

            int  curRetry = 0;
            bool retry;

            // Assign default values to out parameters
            locked  = false;
            lockId  = null;
            lockAge = TimeSpan.Zero;
            actions = SessionStateActions.None;

            do
            {
                retry = false;
                try
                {
                    TableServiceContext svc = CreateDataServiceContext();
                    session = GetSession(id, svc);

                    // Assign default values to out parameters
                    locked  = false;
                    lockId  = null;
                    lockAge = TimeSpan.Zero;
                    actions = SessionStateActions.None;

                    // if the blob does not exist, we return null
                    // ASP.NET will call the corresponding method for creating the session
                    if (session == null)
                    {
                        return(null);
                    }

                    if (session.Initialized == false)
                    {
                        actions = SessionStateActions.InitializeItem;
                    }

                    session.ExpiresUtc = DateTime.UtcNow.AddMinutes(session.Timeout);
                    if (exclusive)
                    {
                        if (!session.Locked)
                        {
                            if (session.Lock == Int32.MaxValue)
                            {
                                session.Lock = 0;
                            }
                            else
                            {
                                session.Lock++;
                            }

                            session.LockDateUtc = DateTime.UtcNow;
                        }

                        lockId         = session.Lock;
                        locked         = session.Locked;
                        session.Locked = true;
                    }

                    lockAge = DateTime.UtcNow.Subtract(session.LockDateUtc);
                    lockId  = session.Lock;

                    if (locked)
                    {
                        return(null);
                    }

                    // let's try to write this back to the data store
                    // in between, someone else could have written something to the store for the same session
                    // we retry a number of times; if all fails, we throw an exception
                    svc.UpdateObject(session);
                    svc.SaveChangesWithRetries();
                }
                catch (InvalidOperationException e)
                {
                    // precondition fails indicates problems with the status code
                    // not found means we have had the session deleted from under us
                    if (e.InnerException is DataServiceClientException &&
                        (e.InnerException as DataServiceClientException).StatusCode == (int)HttpStatusCode.PreconditionFailed)
                    {
                        retry = true;
                    }
                    else if (e.InnerException is DataServiceClientException &&
                             (e.InnerException as DataServiceClientException).StatusCode == (int)HttpStatusCode.NotFound)
                    {
                        return(null);
                    }
                    else
                    {
                        throw new ProviderException("Error accessing the data store.", e);
                    }
                }
            } while (retry && curRetry++ < NumRetries);

            // ok, now we have successfully written back our state
            // we can now read the blob
            // we do not need to care about read/write locking when accessing the
            // blob because each time we write a new session we create a new blob with a different name
            if (actions == SessionStateActions.InitializeItem || string.IsNullOrEmpty(session.BlobName))
            {
                // Return an empty SessionStateStoreData
                return(new SessionStateStoreData(
                           new SessionStateItemCollection(),
                           SessionStateUtility.GetSessionStaticObjects(context),
                           session.Timeout));
            }
            try
            {
                BlobProperties properties;
                using (MemoryStream stream = blobProvider.GetBlobContent(session.BlobName, out properties))
                    using (var reader = new StreamReader(stream))
                    {
                        // Read Items, StaticObjects, and Timeout from the file
                        byte[] items   = Convert.FromBase64String(reader.ReadLine());
                        byte[] statics = Convert.FromBase64String(reader.ReadLine());
                        int    timeout = session.Timeout;

                        // Deserialize the session
                        return(DeserializeSession(items, statics, timeout));
                    }
            }
            catch (Exception e)
            {
                throw new ProviderException("Couldn't read session blob!", e);
            }
        }
Пример #10
0
        public override void SetAndReleaseItemExclusive(HttpContext context, string id, SessionStateStoreData item, object lockId, bool newItem)
        {
            SecUtility.CheckParameter(ref id, true, true, false, ProviderConfiguration.MaxStringPropertySizeInChars, "id");

            providerRetry(() =>
            {
                TableServiceContext svc = CreateDataServiceContext();
                SessionRow session;

                if (!newItem)
                {
                    session = GetSession(id, svc);
                    if (session == null || session.Lock != (int)lockId)
                    {
                        return;
                    }
                }
                else
                {
                    session = new SessionRow(id, applicationName)
                    {
                        Lock        = 1,
                        LockDateUtc = DateTime.UtcNow
                    };
                }

                session.Initialized = true;
                session.Timeout     = item.Timeout;
                session.ExpiresUtc  = DateTime.UtcNow.AddMinutes(session.Timeout);
                session.Locked      = false;

                // yes, we always create a new blob here
                session.BlobName = GetBlobNamePrefix(id) + Guid.NewGuid().ToString("N");

                // Serialize the session and write the blob
                byte[] items, statics;
                SerializeSession(item, out items, out statics);
                string serializedItems   = Convert.ToBase64String(items);
                string serializedStatics = Convert.ToBase64String(statics);
                var output = new MemoryStream();
                var writer = new StreamWriter(output);

                try
                {
                    writer.WriteLine(serializedItems);
                    writer.WriteLine(serializedStatics);
                    writer.Flush();

                    // for us, it shouldn't matter whether newItem is set to true or false
                    // because we always create the entire blob and cannot append to an
                    // existing one
                    blobProvider.UploadStream(session.BlobName, output);
                    writer.Close();
                    output.Close();
                }
                catch (Exception e)
                {
                    if (!newItem)
                    {
                        ReleaseItemExclusive(svc, session, lockId);
                    }

                    throw new ProviderException("Error accessing the data store.", e);
                }
                finally
                {
                    writer.Close();
                    output.Close();
                }

                if (newItem)
                {
                    svc.AddObject(tableName, session);
                    svc.SaveChangesWithRetries();
                }
                else
                {
                    // Unlock the session and save changes
                    ReleaseItemExclusive(svc, session, lockId);
                }
            });
        }