Friday, May 09, 2008

ASP.NET State with Microsoft SQL Server - A Session Monitor Application

I am the product development manager for the 360° Project Management Competency Assessment (360° PMCA™), an online assessment platform for the measurement and analysis of project management competencies.  For more information, check out my product blog.

Early in the 2.0 development cycle we were using inproc session management.  I recommend inproc session management for development purpose only--if your web application needs to persist customer-critical data (such as assessment results) during runtime, you need to use something else.  We chose Microsoft SQL Server 2005 (MSSQL2K5).

You can read about how we implemented session state and some of the research I did here.

In this post, I introduced a very simple tool for peering into session state persisted in MSSQL2K5.  Since that post, the tool has evolved into as asset for debugging, profiling, and customer support.   See Figure 1, 2, and 3 below.  360° PMCA also uses the term session but it means something different from ASP.NET session.  A session in 360° PMCA is the assessment as it is configured for a specific customer for a time period (customer X may have three ongoing assessments and customer Y may have two and so on).  In Figure 1 you see a tree control to the left and a details panel to the right.  The tree control contains one root node (Sessions) and a child for each 360° PMCA assessment session currently with participants logged on.  Each child node contains N child nodes, one for each active ASP.NET session on the server.  If the root node is selected, the ASP.Net Session State Summary (Summary Panel) panel is displayed.  Lets talk about that a little bit. 

Figure 1


The Summary Panel displays the count of active sessions (these are sessions that have not expired yet, whether or not they represent active assessment sessions).  Below that is a tree control with a root node for each active session.  Each session node has N child nodes, one for each session item (a datum persisted in the binary property bags stored in SessionItemShort and SessionItemLong of the ASPStateTempSessions table--for more information, read this).  This version of the session monitor supports reading Boolean, Byte, SByte, Int16, UInt16, Int32, UInt32, Int64, UInt64, IntPtr, Char, Double, Single, and strings only. Implementing a reader for other types is both possible and potentially very valuable (360° PMCA doesn't store anything but strings and longs in state).

A child node for each session item name/value pair is created the first time a session item is created in the web application.  A node beneath the session item name houses the actual session item value.

You might have noticed in the screen shots that the toolstrip at the top houses an Interval text box.  This is the polling interval in milliseconds.  I happen to have it set at 1 (which might as well be zero, which indicates continous polling--I don't recommend doing polling for much of anything if there is a better way to do it, but for an internal tool it is okay).

As the session monitor polls, and session items' values change, an new node is created under the associated session item name node.  See Figure 3 for an example from an early version.  This gives you a journal of session item values as they change over time.  This can be handy for debugging.

Figure 2


The session monitor user interface is implemented on top two layers: a base layer that understands how to connect to a state database, read it, and report the data back up the call chain.  The second layer is an application-specific layer that knows about 360° PMCA session state and how to translate the session values into meaningful data for analysis.  This two layered approach means that the next time I need to monitor session state for a different applicaiton, I can take the base layer, add another "reader" layer on top and get started very quickly.

Figure 3 below shows data in the UI that is served up by the second layer.   The application-specific layer, again, knows how to translate state variables into meaningful data--in this case, I can see that we have 700+ sessions and selecting a specific session tells me who the assessment invitation came from and who it is for (the 360 model is a multi-rater methodology that incorporates many viewpoints regarding a project manager's competencies).

Figure 3


The first layer, SessionMonitor, is implemented in as a C# class.  It is very simple.  You construct it, hook up some events, and call BeginMonitor. When you are done, you call EndMonitor.  See Figure 4 class diagram of the SessionMonitor class.

The only thing tricky about this tool was figuring out how to read the the binary data out of the session state tables.  For a deep dive on the topic, download, install,and read the source code for the sample ASP.NET SQL Session State Provider.

See figure 5 for the key source code.

Hope this is helpful to somebody!






Figure 4


Figure 5

The byte[] bytes parameter expects the binary data from the session state record you are examing (byte[]) reader["SessionItemShort"] or byte[]) reader["SessionItemLong"])

        private static void GetSessionItemCollections(byte[] bytes,
                                                      out SessionStateItemCollection items,
                                                      out HttpStaticObjectsCollection objects)
            using (MemoryStream memoryStream = new MemoryStream(bytes))
                BinaryReader binaryReader = new BinaryReader(memoryStream);

                int timeOut = binaryReader.ReadInt32();
                bool hasItems = binaryReader.ReadBoolean();
                bool hasStaticObjects = binaryReader.ReadBoolean();

                if (hasItems)
                    items = SessionStateItemCollection.Deserialize(binaryReader);
                    items = null;
                if (hasStaticObjects)
                    objects = HttpStaticObjectsCollection.Deserialize(binaryReader);
                    objects = null;

The delegates for the events are as follows (this gives you a sense how the SessionMonitor reports data back to its callers):

Figure 6
    public delegate void OnNewItemEventHandler(object sender, string sessionId, string name, object item);

    public delegate void OnItemUpdatedEventHandler(object sender, string sessionId, string name, object value);

    public delegate void OnItemRemovedEventHandler(object sender, string sessionId, string name);

    public delegate void OnNewSessionEventHandler(object sender, string sessionId, DateTime created, DateTime expires, int timeOut);

    public delegate void OnSessionRemovedEventHandler(object sender, string sessionId);

No comments:


Content on this site is provided "AS IS" with no warranties and confers no rights. Additionally, all content on this site is my own personal opinion and does not represent my employer's view in any way.