A while ago I blogged about a pattern useful to ensure that just a single instance of a class was created and used during a unique request-response pair. That seemed to make sense, since using the HttpContext.Items property prevents a single pipeline from instantiating that class more than once.
At the time I didn't realize that actually one could need a little more granularity and may incur in some issues when that instance needs logically to be bound to a single page instead of a single request-response. One might be wondering where's the difference, since usually during a single request just a single page is executed. That's true most of the times unless you use a subtle method of the HttpServerUtility class called Transfer.
When that method is called, usually via the Server property of the Page class, the execution of the current page is interrupted and the control is passed to the new page specified as input parameter, which executes its whole life cycle from the beginning.
In this case both the pages share the same HttpContext, and if in the singleton-per-request instance of the class you got a reference to the currently executing page (that's what I needed to do in the HeadScriptManager), when you transfer the control to the new page your singleton instance still keeps a reference to the old page.
This seems enough to introduce a sub pattern of the singleton-per-request which might be called singleton-per-page. The only problem is to find a place where to store information which is exclusive to a single page and not shared between pages, even if they are executed in the scope of the same context.
The Page class features a property called Items, an instance of the HybridDictionary class, and that's where we'll store the singleton instance. Here's a sample code to implement the Singleton-per-Page pattern:
public class SingletonPerPage
{
public static SingletonPerPage Current
{
get
{
Page currentPage = HttpContext.Current.Handler as Page;
if(currentPage == null)
throw new NullReferenceException("The page is null");
return (currentPage.Items["SingletonPerPage"] ??
(currentPage.Items["SingletonPerPage"] =
new SingletonPerPage())) as SingletonPerPage;
}
}
}
From a mere performance point of view this seems a slightly better solution compared to the singleton-per-request, since the Items properties of the HttpContext and Page classes make use of different bags for storing data. As I said, the Page class uses HybridDictionary, a dictionary which internally makes use of the lightweight ListDictionary class until the number of items stored reaches 9, when it switches over to a HashTable; HttpContext instead makes directly use of a HashTable. What's essential here is to be aware of the scope of the stuff you place there.
