Introduction
On all the previous ASP and ASP.NET web sites I have worked on I have thought how useful it would be to have some quick and "easy to use" view of Session State and the Cache without having to sit with the debugger and manually step through each one.
As soon as you get a few developers working on a site you face the possibility of session and/or cache abuse. By this I do not mean to suggest that anything malicious might be going on, simply that there is the potential for sloppy use of these facilities. For example, putting information into session state that really shouldn't be in there or multiple developers putting identical data into session state under separate keys.
Under these circumstances it would be useful to have one or more utilities to allow you to view the contents of session state and the cache.
In this article I will show how to create these quick, "easy to use" views of session state and cache. Along the way we will touch on the subjects of HttpHandlers, custom configuration sections and binary serialization.
The full source code and a test web site is available to download.
Extending a Good Idea
Both our session and the cache views are implemented in a similar way to the standard trace tool that comes with ASP.NET, trace.axd.
The ASP.NET trace functionality is available to use in you ASP.NET code through the TraceContext
class and the Page class’ Trace property. Information output to trace and a lot of other useful information such as an enumeration of session variables is rendered by the TraceHandler
class that deals with the processing of the virtual page Trace.axd. The MSDN Online documentation on trace is here ASP.NET Trace.
Our session and cache views are custom HttpHandler
s that are configured to process requests for the virtual pages of SessionView.axd and CacheView.axd
. These names are determined using local web.config setting and the choice of them is up to the developer. I have given my "pages" an axd extension simply for consistency with the already well-known trace.axd. The article Extending ASP.NET with HttpHandlers and HttpModules from http://www.devx.com/ does a great job of explaining how to create a custom HttpHandler
so I will not be covering that here.
The configuration xml to add the HttpHandler
s to the ASP.NET pipeline is:
<httpHandlers>
<add verb="*"
path="SessionView.axd"
type="Charteris.Web.HttpHandlers.SessionViewHandler,Charteris.Web.HttpHandlers" />
<add verb="*"
path="CacheView.axd"
type="Charteris.Web.HttpHandlers.CacheViewHandler,Charteris.Web.HttpHandlers" />
</httpHandlers>
If the HttpHandler
's assembly was located in the Global Assembly Cache (GAC) you would need to add further location information with the type attribute changing from
type="Charteris.Web.HttpHandlers.SessionViewHandler,
Charteris.Web.HttpHandlers"
to
type="Charteris.Web.HttpHandlers.SessionViewHandler,
Charteris.Web.HttpHandlers, Version=2.0.2000.0,
Culture=neutral,
PublicKeyToken=4edafd72b7cb8805"
This extra GAC information is available from Windows Explorer when you browse to the %WindowsDir%\Assembly directory.
For security reasons I have implemented a check to ensure only requests from the local box are processed. These are really only dev tools so this restriction is not really an issue. The RequestIsLocal
code is in the Common.cs class and simply checks if the request’s source IP address is the local loopback address of 127.0.0.1 or if it is the same as the server’s IP address.
internal static bool RequestIsLocal(HttpRequest request){
if(request.UserHostAddress == "127.0.0.1" ||
request.UserHostAddress == request.ServerVariables["LOCAL_ADDR"]){
return true;
}
else{
return false;
}
}
The views both have a similar configuration style with the ability to disable the view and to disable the link, which allows viewing of the actual data stored within the session state or cache item. This link can be seen in the SessionView.axd screenshot in the following section.
These configuration options are implemented using a custom config handler. Custom config handlers inherit from IConfigurationSectionHandler
and are used to process the config section that you set up in web.config. In the following piece of XML I have defined the config section and what handler will process it. Again the type attribute would need extra information if the config handler's assembly was in the GAC. The MSDN online docs for creating and processing custom config sections are very good and can be found here Creating New Configuration Sections.
As you may be aware Microsoft occasionally release best practice .NET code known as Application Blocks. There is a new block due for release this summer that deals with custom configuration, in .NET, using your own custom config files. If there is enough interest I will do an update to this article that uses the new Microsoft application block to handle the view's configuration needs.
SessionView.axd
The session state view enumerates all the items in Session State.
For each item it will render a row containing the item’s key in the session state collection and its type name.
If the Session State mode being used means that the items are serialized into the session state then it will also display an approximation of the storage space the object is taking up. When Session State is running InProc (In Process) the actual objects that form the content are not stored in the collection, only reference to the objects. The figures for the size taken up by these objects "in" session state would be misleading under these circumstances. Therefore there is no "Object Size" column when running in this mode. When Session State is running out of process, either using a StateServer machine or a SQL Server database, the objects are serialized into Session State.
The value that is displayed in the "Object Size" column is the byte size of a stream that is used as the destination of a binary serialization. This code to perform the serialization for most objects is shown below:
MemoryStream m;
m = Common.BinarySerialize(sessionItem);
double size = Convert.ToDouble(m.Length) / Convert.ToDouble(1000) + " KB";
internal static MemoryStream BinarySerialize(object objectToSerialize) {
MemoryStream m = new MemoryStream();
BinaryFormatter b = new BinaryFormatter();
b.Serialize(m, objectToSerialize);
return m;
}
Originally I was the above technique, for all types stored in Session and Cache, to get my calculations for approximate "Object Size". However after some discussion with one of the Microsft devs in the US I now know that ASP.NET uses an internal, optimized, serialization technique for some of the standard types. This technique is internal to the System.Web assmebly and is subject to change in future versions. I have imitated their approach and have listed below all the types that are currebtly being serialized in this fashion. This set of types is correct for the 1.1 version of the framework. Less types were serialised in this way in version 1.0.
- String
- Int16
- Int32
- Int64
- Boolean
- DateTime
- Decimal
- Byte
- Char
- Double
- SByte
- UInt16
- UInt32
- UInt64
- Timespan
- Guid
- IntPtr
- UIntPtr
- Object
If the item’s type can be understood by the XmlSerializer
class then the “View Data” cell will display a link to allow viewing of the contents of the item. This facility can be disabled by setting the config attribute showViewDataLink
to false. I use the XmlSeriliazer to get a renderable view of the data. This means that there are extraneous XML tags at the top and bottom of the data when viewed.
CacheView.axd
In a similar fashion to the session state view, this enumerates the contents of the cache.
Again for every cache item, it will render a row containing the item’s key in the cache collection and its type name. As the cache is always run in process, the items are object references and therefore there is no “Object Size” column for the cache view.
Again like the session view, if it is not disabled by the config setting showViewDataLink
and the item’s type is understood by the XmlSerializer
, the “View Data” cell will display a link to allow viewing of the contents of the item.
Points of Interest
One gotcha that I found with developing an HttpHandler
that wants to use session state was that by default you can’t. If you want your HttpHandler
to have access to session state you need to implement the IRequiresSessionState
interface.
History
OK, After speaking to one of the Microsoft guys in the US there is a serious flaw in my thinking regarding calculating an approximate size for items in session state. ASP.NET "uses an optimized internal formatter for basic types such as int, string, bool, etc". Therefore me basing my calculation on the BinaryFormatter is wrong. I have updated the article saying that my use of the BinaryFormatter
gives only a very rough approximation.
- 31 May 2003 - updated downloads
- 6 June 2003 - Amended Text
The article now takes into consideration that ASP.NET uses an internal optimized serialization technique for the many of the base types.
I have also fixed a bug where some or all parts of the data would not appear in the browser. This was fixed by HTML encoding the output using HttpServerUtility.HtmlEncode
.
- 10 Jan 2007 - Updated source file to include missing project