예제 #1
0
        /// <summary>
        /// Uses reflection to determine if the MongoDB Session State Provider is holding onto a sessionId
        /// in it's memory cache object.
        /// </summary>
        /// <param name="mongoSessionStateProvider">The provider to use</param>
        /// <param name="sessionId">The session id to query</param>
        /// <param name="dataFromCache">The data retrieved from the cache</param>
        /// <returns>True if the session exists in the provider's cache</returns>
        private bool CheckSessionExistsInCache(MongoDBSessionStateProvider mongoSessionStateProvider, string sessionId, out ISessionStateData dataFromCache)
        {
            var mongoSessionStateProviderBaseType = mongoSessionStateProvider.GetType().BaseType;

            bool objectExistsInCache = (bool)mongoSessionStateProviderBaseType
                                       .GetMethod("CacheContains", BindingFlags.NonPublic | BindingFlags.Instance)
                                       .Invoke(mongoSessionStateProvider, new object[] { sessionId });

            dataFromCache = (DefaultSessionStateData)mongoSessionStateProviderBaseType
                            .GetMethod("CacheGet", BindingFlags.NonPublic | BindingFlags.Instance)
                            .Invoke(mongoSessionStateProvider, new object[] { sessionId });

            return(objectExistsInCache);
        }
예제 #2
0
        /// <summary>
        /// Creates a new instance of MongoDBSessionStateProvider
        /// </summary>
        /// <param name="useDotNetMemoryCache">Determines whether to use .NET's MemoryCache or CommonCore's Cache</param>
        /// <returns>A new MongoDB Session State Provider</returns>
        private MongoDBSessionStateProvider GetMongoDBSessionStateProvider(bool useDotNetMemoryCache)
        {
            string dotNetMemoryCacheName = null;

            try
            {
                var mongoWebSection   = ConfigurationManager.GetSection("mongoDbWeb");
                var mongoSessionState = mongoWebSection.GetType().InvokeMember("SessionState", BindingFlags.GetProperty, null, mongoWebSection, null);
                dotNetMemoryCacheName = mongoSessionState.GetType().InvokeMember("DotNetMemoryCacheName", BindingFlags.GetProperty, null, mongoSessionState, null) as string;
            }
            catch { }

            if (useDotNetMemoryCache)
            {
                // Pull the name from the config, or else create one by default to ensure
                // mongoDbSessionStateProvider uses the .NET MemoryCache
                if (string.IsNullOrWhiteSpace(dotNetMemoryCacheName))
                {
                    dotNetMemoryCacheName = "MongoDBMemoryCache";
                }
            }
            else
            {
                dotNetMemoryCacheName = string.Empty;
            }

            var config = new System.Collections.Specialized.NameValueCollection(_ProviderSettings.Parameters);

            config["dotNetMemoryCacheName"] = dotNetMemoryCacheName;

            var provider = new MongoDBSessionStateProvider();

            provider.Initialize(_ProviderSettings.Name, config);

            return(provider);
        }
예제 #3
0
        /// <summary>
        /// Creates sessions concurrently and stores a random binary blob in each session.  This
        /// method then waits for all the sessions to expire and verifies that each session has in
        /// fact been removed from the provider and the provider's memory cache.  It also takes a
        /// snapshot of the memory usage pre session creation, post session creation and post
        /// session expiration.  This method will fail is any session still exists in the provider
        /// or there was excessive memory usage.
        /// </summary>
        /// <param name="provider">The MongoDB provider to use for the test.</param>
        /// <param name="numberOfSessions">The number of sessions to create concurrently.</param>
        /// <param name="sessionSizeInMegabytes">The number of MB of buffer to create and store in each session.</param>
        private void CreateConcurrentSessionObjects(MongoDBSessionStateProvider provider, int numberOfSessions, byte sessionSizeInMegabytes)
        {
            var    sessions = new System.Collections.Generic.SynchronizedCollection <string>();
            double initialWorkingSet, postSessionCreationWorkingSet, postSessionExpirationWorkingSet;

            var currentProcess = System.Diagnostics.Process.GetCurrentProcess();

            initialWorkingSet = (currentProcess.WorkingSet64 / 1024.0 / 1000.0);

            int sessionSize = (sessionSizeInMegabytes * 1024 * 1024);
            var result      = Parallel.For(0, numberOfSessions, idx =>
            {
                System.Threading.Thread.Sleep(50);                 // Give a little wiggle room

                HttpRequest request   = null;
                HttpResponse response = null;
                HttpContext context   = GetContext(out request, out response);

                string sessionId = _SessionIdManager.CreateSessionID(context);
                sessions.Add(sessionId);

                byte[] dummyData = new byte[sessionSize];
                (new Random()).NextBytes(dummyData);

                var dataStore           = provider.CreateNewStoreData(context, (_TimeoutInSeconds / 60));
                dataStore.Items["Data"] = dummyData;
                provider.SetAndReleaseItemExclusive(context, sessionId, dataStore, null, true);

                TestContext.WriteLine("Created session {0} with dummy data", sessionId);
            });

            while (!result.IsCompleted)
            {
                System.Threading.Thread.Sleep(1000);
            }

            GC.Collect();
            currentProcess.Refresh();
            postSessionCreationWorkingSet = (currentProcess.WorkingSet64 / 1024.0 / 1000.0);

            var counter = _TimeoutInSeconds + 60;

            TestContext.WriteLine("Waiting {0} seconds for session expiration...", counter);

            while (counter > 0)
            {
                System.Threading.Thread.Sleep(1000);
                counter--;
            }

            TestContext.WriteLine("Checking Sessions in store and cache...");
            var sessionIds = sessions.ToArray();

            result = Parallel.ForEach <string>(sessionIds, sessionId =>
            {
                HttpRequest request   = null;
                HttpResponse response = null;
                HttpContext context   = GetContext(out request, out response);

                bool locked;
                TimeSpan lockAge;
                object lockId;
                System.Web.SessionState.SessionStateActions actions;
                var storeData = provider.GetItem(context, sessionId, out locked, out lockAge, out lockId, out actions);

                Assert.IsNull(storeData);

                // Now check the cache!
                ISessionStateData sessionStateData;
                bool existsInCache = CheckSessionExistsInCache(provider, sessionId, out sessionStateData);
                if (existsInCache || sessionStateData != null)
                {
                    TestContext.WriteLine("Session {0} still exists in cache!", sessionId);
                }
                else
                {
                    sessions.Remove(sessionId);
                }
            });

            while (!result.IsCompleted)
            {
                System.Threading.Thread.Sleep(1000);
            }

            GC.Collect();
            GC.WaitForPendingFinalizers();
            currentProcess.Refresh();
            postSessionExpirationWorkingSet = (currentProcess.WorkingSet64 / 1024.0 / 1000.0);

            TestContext.WriteLine("Memory Usage: Initial = {0}MB, PostSessionCreation = {1}MB, PostSessionExpiration = {2}MB", initialWorkingSet, postSessionCreationWorkingSet, postSessionExpirationWorkingSet);
            TestContext.WriteLine("After expiration, session count = {0}", sessions.Count);

            currentProcess.Dispose();

            double memoryDifference = postSessionExpirationWorkingSet - initialWorkingSet;

            TestContext.WriteLine("Memory Difference -> {0}MB", memoryDifference);

            bool isMemoryExhausted = (memoryDifference > 20);             // This should be based on the buffer size and number of sessions

            if (sessions.Count != 0)
            {
                Assert.Fail("{0} Sessions still exist in memory.  The memory has grown from {1}MB to {2}MB", sessions.Count, initialWorkingSet, postSessionExpirationWorkingSet);
            }
            if (isMemoryExhausted)
            {
                Assert.Fail("Excessive Memory Consumption.  Memory has grown by {0}MB", memoryDifference);
            }
        }
예제 #4
0
        /// <summary>
        /// Method that creates a new session, waits for it to automatically expire and then
        /// verifies that the session has been removed from the provider as well as the provider's
        /// memory cache.
        /// </summary>
        /// <param name="mongoSessionStateProvider">The MongoDB provider to use for the test.</param>
        private void VerifySessionExpiration(MongoDBSessionStateProvider mongoSessionStateProvider)
        {
            var mongoSessionStateProviderBaseType = mongoSessionStateProvider.GetType().BaseType;

            HttpRequest  httpRequest  = null;
            HttpResponse httpResponse = null;
            HttpContext  httpContext  = GetContext(out httpRequest, out httpResponse);

            var timeoutInMinutes = (_TimeoutInSeconds / 60);
            var storeData        = mongoSessionStateProvider.CreateNewStoreData(httpContext, timeoutInMinutes);

            storeData.Items["DummyEntry"] = "DummyValue";

            string sessionId = null;

            lock (_SessionIdManager)
            {
                sessionId = _SessionIdManager.CreateSessionID(httpContext);
            }

            object lockId = null;             // New items don't have a lockId

            mongoSessionStateProvider.SetAndReleaseItemExclusive(httpContext, sessionId, storeData, lockId, true);

            TestContext.WriteLine("Created Session {0}", sessionId);

            int counter = _TimeoutInSeconds + 60;

            TestContext.WriteLine("Waiting {0} seconds...", counter);
            while (counter > 0)
            {
                System.Threading.Thread.Sleep(1000);
                counter--;
            }

            bool     locked;
            TimeSpan lockAge;
            object   lockId2 = null;

            System.Web.SessionState.SessionStateActions actions;
            var storeDataAfterExpiry = mongoSessionStateProvider.GetItem(httpContext, sessionId, out locked, out lockAge, out lockId2, out actions);

            if (storeDataAfterExpiry == null || storeDataAfterExpiry.Items.Count == 0)
            {
                TestContext.WriteLine("Session expired from Session State Provider.  Verifying session provider cache...");

                ISessionStateData objectInCache = null;
                bool objectExistsInCache        = CheckSessionExistsInCache(mongoSessionStateProvider, sessionId, out objectInCache);

                if (objectInCache != null)
                {
                    Assert.Fail("Session data exists in cache when should have expired - Expires = {0}", objectInCache.Expires);
                }
                else if (objectInCache == null && objectExistsInCache)
                {
                    Assert.Fail("Session data has expired but the cache is retaining the object!");
                }
                else
                {
                    TestContext.WriteLine("Success - session data does not exist in cache.");
                }
            }
            else
            {
                Assert.Fail("Session expired but MongoDB Sessions State Provider still contains data!");
            }
        }
예제 #5
0
        /// <summary>
        /// Method that creates a new session using the provider supplied.  This method
        /// also verifies that the session was created, then modifies the session, then
        /// deletes the session and verifies deletion from the store and the memory cache
        /// in the provider.
        /// </summary>
        /// <param name="provider">The MongoDB provider to use for the test.</param>
        private void VerifySessionPersistence(MongoDBSessionStateProvider provider)
        {
            string itemName  = "DummyItem";
            string itemValue = "Value";

            HttpRequest  request  = null;
            HttpResponse response = null;
            HttpContext  context  = GetContext(out request, out response);

            TestContext.WriteLine("Creating Store Data");
            var dataStore = provider.CreateNewStoreData(context, (_TimeoutInSeconds / 60));

            dataStore.Items[itemName] = itemValue;

            var sessionId = _SessionIdManager.CreateSessionID(context);

            TestContext.WriteLine("Writing Store Data");
            provider.SetAndReleaseItemExclusive(context, sessionId, dataStore, null, true);

            System.Threading.Thread.Sleep(2000);

            bool     locked;
            TimeSpan lockAge;
            object   lockId;

            System.Web.SessionState.SessionStateActions actions;

            TestContext.WriteLine("Retrieving new Store Data");
            var retrievedDataStore = provider.GetItemExclusive(context, sessionId, out locked, out lockAge, out lockId, out actions);

            if (retrievedDataStore == null || retrievedDataStore.Items.Count == 0)
            {
                Assert.Fail("Retrieved data store does not contain session data");
            }

            TestContext.WriteLine("Testing Store Data");
            var dummyValue = retrievedDataStore.Items[itemName];

            Assert.AreEqual(itemValue, dummyValue);

            itemValue = "NewValue";
            retrievedDataStore.Items[itemName] = itemValue;

            TestContext.WriteLine("Updating Store Data");
            provider.SetAndReleaseItemExclusive(context, sessionId, retrievedDataStore, lockId, false);

            System.Threading.Thread.Sleep(2000);

            var retrievedDataStore2 = provider.GetItemExclusive(context, sessionId, out locked, out lockAge, out lockId, out actions);

            if (retrievedDataStore2 == null || retrievedDataStore2.Items.Count == 0)
            {
                Assert.Fail("Retrieved data store does not contain session data");
            }

            TestContext.WriteLine("Testing Store Data");
            Assert.AreEqual(itemValue, retrievedDataStore2.Items[itemName]);

            TestContext.WriteLine("Releasing Store Data");
            provider.ReleaseItemExclusive(context, sessionId, lockId);

            System.Threading.Thread.Sleep(2000);

            retrievedDataStore2 = provider.GetItemExclusive(context, sessionId, out locked, out lockAge, out lockId, out actions);
            TestContext.WriteLine("Deleting Store Data");
            provider.RemoveItem(context, sessionId, lockId, retrievedDataStore2);

            System.Threading.Thread.Sleep(2000);

            TestContext.WriteLine("Ensuring store was deleted");
            var retrievedDataStore3 = provider.GetItem(context, sessionId, out locked, out lockAge, out lockId, out actions);

            Assert.IsNull(retrievedDataStore3);

            System.Threading.Thread.Sleep(2000);

            TestContext.WriteLine("Ensuring cache is empty");
            ISessionStateData sessionStateDataFromCache = null;
            bool sessionExistsInCache = CheckSessionExistsInCache(provider, sessionId, out sessionStateDataFromCache);

            if (sessionExistsInCache)
            {
                Assert.Fail("Session should have been removed but still exists in cache");
            }

            TestContext.WriteLine("Success");
        }
예제 #6
0
        /// <summary>
        /// Method that creates a new session and touches it right before the expiry a couple of times.
        /// The final time it will not wait until after the expiration which the method will then
        /// expect the session to no longer be available.
        /// </summary>
        /// <param name="provider">The MongoDB provider to use for the test.</param>
        private void VerifySessionSlidingExpiration(MongoDBSessionStateProvider provider)
        {
            HttpRequest  request  = null;
            HttpResponse response = null;
            HttpContext  context  = GetContext(out request, out response);

            var sessionId = _SessionIdManager.CreateSessionID(context);
            var dataStore = provider.CreateNewStoreData(context, (_TimeoutInSeconds / 60));

            dataStore.Items["Dummy"] = "Value";

            TestContext.WriteLine("Creating dummy session with id {0}", sessionId);

            provider.SetAndReleaseItemExclusive(context, sessionId, dataStore, null, true);

            int iterations = 4;

            for (int i = 0; i < iterations; i++)
            {
                bool isLastIteration = (i == iterations - 1);

                int counter = _TimeoutInSeconds + (isLastIteration ? 10 : -10);
                TestContext.WriteLine("Waiting {0} seconds (expiration set to {1} seconds)...", counter, _TimeoutInSeconds);

                while (counter > 0)
                {
                    System.Threading.Thread.Sleep(1000);
                    counter--;
                }

                TestContext.WriteLine("Retrieving session again to reset expiry");

                bool     locked;
                TimeSpan lockAge;
                object   lockId;
                System.Web.SessionState.SessionStateActions actions;

                var dataStore2 = provider.GetItemExclusive(context, sessionId, out locked, out lockAge, out lockId, out actions);
                if (isLastIteration)
                {
                    if (dataStore2 != null)
                    {
                        Assert.Fail("Session has NOT expired.");
                    }

                    ISessionStateData dataFromCache;
                    bool existsInCache = CheckSessionExistsInCache(provider, sessionId, out dataFromCache);

                    if (existsInCache)
                    {
                        Assert.Fail("Session has expired however it still exists in the memory cache.");
                    }
                }
                else
                {
                    if (dataStore2 == null || dataStore2.Items.Count == 0)
                    {
                        Assert.Fail("Session Missing prior to expiry??");
                    }
                    else
                    {
                        TestContext.WriteLine("Session retrieved successfully during iteration {0}", (i + 1));
                    }
                }

                if (lockId != null)
                {
                    provider.ReleaseItemExclusive(context, sessionId, lockId);
                }
            }
        }