Who ordered the scrambled brains?

Fast your mind on this!

Immutable Singleton Per HTTP Request!

Update: This doesn’t work gracefully. I worked on this a little more and tried using it, made some semantic improvements, but I don’t think C#/.NET supports what I’m trying to do. If I could just find a way to convert a given type, including generic types, into a unique string representation, it could be nice. Calling object’s ToString doesn’t serialize type parameters of generics. =( I guess if you’re willing to have only one instance per generic family, this would work gracefully. But that’s a major concession to me. Getting around this by deriving types from generic instances is not graceful either.

I know it’s been a while, so I figured I’d break the silence with an entry that I’m sure will enthrall all of you:  how to create an immutable singleton per request in ASP.NET!  Whoo!  And if you make it to the end, I reveal some juicy gossip and deep dark secrets about myself.

The singleton pattern, of course, refers to a class of which only one object instantiation can exist within a running program (i.e. an application domain in the .NET framework).  See the Wikipedia article for details.  To create a singelton whose instantiability is bounded by an ASP.NET request rather than the CLR application domain, you basically leverage the Items collection in HttpContext.  See this for details.  That’s all fine, good, spiffy, and all that, but what about when you want the singleton to be immutable?  That is, you want the members to be initialized when the singleton is instantiated, and you want to enforce immutability on them thereafter.  What do you do?

Well, at first I thought about the readonly member modifier, which allows write access to the member from the constructor only.  Unfortunately, singleton construction is handled within the singleton instance accessor.  This lazy-loading doesn’t support parameterized construction.  In other words, how would you get the initialization data into the accessor so it can provide it to the constructor?  You can’t.

Next, I considered using an “isInitialized” static boolean member, which would be initialized to false, and would flip once the member variables were initialized.  But this seemed to be too much of a compromise, because I would be breaking the required “immutability” semantics since initialization obviously requires mutability.  I wanted to stick with initialization occurring at instantiation.

So I thought about it more and decided that the instantation did not need to occur implicitly in the accessor.  Instead, the accessor would return either the instance if it exists, or null. A static Initialize() method, which would accept initialization data, would then handle the instantiation.  If Initialize() had already been called, an exception would be thrown.  Ka-boom!

Before I present my reference implementation, I should note that the instance variables need to be immutable themselves.  In the .NET framework, value types and some reference types (e.g. strings) are immutable, but most reference types are not.  So if your singleton composes reference types, you need to design them to be immutable themselves (and then you pass the already-constructed reference type variable into Initialize()).  See this for details.

(I’ve generalized my reference implementation, for added Wow factor.  WOW!  This makes it really easy to create a write-protected singleton of any class. The generalization clunkily requires that the type parameter expose a string property to differentiate itself in the HttpContext.)

And now the code you’ve all been waiting for:

using System;
using System.Collections.Generic;
using System.Text;
using System.Web;

namespace ScrambledBrains.Nuggets
{
   // immutable modification of singleton-per-request pattern
   public class ImmutableRequestSingleton<ImmutableType> where ImmutableType : IIdentifiable, new()
   {
      protected static string _identifier = ”ImmutableRequestSingleton<“;
      private ImmutableRequestSingleton() { }
      public static void Initialize(ImmutableType immutableReferenceMember)
      {
         if (HttpContext.Current.Items[_identifier + (new ImmutableType()).TypeIdentity] == null// then ImmutableRequestSingleton is uninitialized
         {
            HttpContext.Current.Items[_identifier + new ImmutableType().TypeIdentity] = new ImmutableRequestSingleton<ImmutableType>();
            ((ImmutableRequestSingleton<ImmutableType>)(HttpContext.Current.Items[_identifier + new ImmutableType().TypeIdentity]))._immutableReferenceMember = immutableReferenceMember;
         }
         else
            throw new Exception(_identifier + new ImmutableType().TypeIdentity + ”> already initialized.“);
      }
      public static ImmutableRequestSingleton<ImmutableType> Current
      {
         get
         {
            if (HttpContext.Current.Items[_identifier + new ImmutableType().TypeIdentity] == null)
               return (ImmutableRequestSingleton<ImmutableType>)null// throw new Exception(”ImmutableRequestSingleton not initialized.”);
            else
               return (ImmutableRequestSingleton<ImmutableType>)HttpContext.Current.Items[_identifier + new ImmutableType().TypeIdentity];
         }
      }
      // note: readonly modifier is not used, but writing is controlled conditionally within Initialize()
      private ImmutableType _immutableReferenceMember;
      public ImmutableType ImmutableReferenceMember
      {
         get { return _immutableReferenceMember; }
      }
   }
   public interface IIdentifiable
   {
      string TypeIdentity { get; }
   }
}

Open in new window. Btw, I’m using Windows Live Writer Beta with the Syntax Highligher plugin (available in a bundle here), though I did have to go through and throw in a bunch of &nbsp;’s to fix the wrapping in the scrollable div..

My use for such a pattern is to address cross-cutting security requirements, specifically making consumer credentials available as part of the “background environment” to all objects at all layers of a web service I’m working on, rather than having to pass that information around from adapter to business to resource layers.

As for that gossip and those secrets about myself: just kidding.  But here’s an insane video clip and associated music video.  Insane insane insane.  And how great are the blank stares on the faces of the audience members in the music video?

Follow me on Twitter for the latest updates, and make sure to check out my community opinion social networking project, Blocvox.



3 Comments

Commenting options at bottom.
Natalie said:

Let me tell you….nothing is more cute than you understanding most of the words to Holeeday.

 
Matt said:

You are not my twin. But you have my twin’s name. Both of his names, in fact. And you’re a C# developer like me. Maybe you’re my evil twin. Or maybe you’re the good twin, and my real twin is the evil twin. If you’re around 5′9″ with short dark hair and glasses, my brother may have to destroy you, Highlander style, screaming, “There can only be one!” You may want to invest in a katana sword.

Mike McG said:

This is indeed strange. After thinking about it for over a week, I have realized there can be only one explanation: You are schizophrenic and an alternate personality of yours (one that is a PHP developer) created this website and has been posting as the evil twin you never had.

Occam’s Razor, as they say.

But because you have uncovered this secret, as your evil twin I must now kill you. Or at least burn all your C# books. PHP forever!!

Just kidding about all that. Greetings fellow member of the McGranahan clan. I hold out hope that one day, McGranahan’s across the world will come together and retake our homeland, Braveheart-style. You are welcome to join me, when that day comes. Until then, I advise you to get a gym membership and buff yourself up, or enroll in some martial arts classes; for make easier glorious crush of our enemies.

 
 

XHTML: You can use these tags: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <code> <em> <i> <strike> <strong>

Comments are subject to moderation.

Commenting Options

Notify me of followup comments via-email

| Comment feed for this page | Trackback URL

1