Strongly Typed Session Variables in ASP.NET MVC

This post was originally going to be a comment on Jarret@Work's blog post about "Using Extension Methods for Session Values", but I decided to make a full blog post out of it.  Jarret employed extension methods such Bar()/SetBar() and Foo()/SetFoo() to have strongly-typed session data.  While his method certainly works, I've taken a different approach that I think is a bit more flexible and reads better.

Like Jarret, I maintain a "SessionKeys" class – there is no easier way to ask for trouble than using a magic string buried across 4 or 5 web pages.  But I expose my session data in a base class that all controllers in my application derive from.  Here's a sample from my post on unit testing ASP.NET MVC controllers:

public abstract class BaseController : Controller
{
    protected SpeakerInfo SpeakerInfo
    {
        get
        {
            var info = Session[SessionKeys.SpeakerInfoKey] as SpeakerInfo;
            if( info == null)
            {
                info = new SpeakerInfo();
            }
 
            return info;
        }
        set
        {
            Session[SessionKeys.SpeakerInfoKey] = value;
        }
    }
}

Now all of my controllers inherit from BaseController and they can easily access the data stored in the Session by utilizing the SpeakerInfo property.  I like this over Jarret's implementation for two reasons:

  1. Properties make the code more readable than get/set methods (in my opinion).
  2. I can change where/how SpeakerInfo is stored without affecting the rest of my code (perhaps to use a database instead of Session).

To be fair, #2 is also possible with Jarret's implementation.  He can change the code in his get/set methods.  But his code would still read "Session.Bar()" and "Session.SetBar()" when (if the implementation was changed to use a database), it wouldn't really be using the Session.

Technorati Tags:
Published Tuesday, September 22, 2009 11:46 AM by PSteele
Filed under: ,

Comments

# Twitter Trackbacks for Strongly Typed Session Variables in ASP.NET MVC - Patrick Steele's .NET Blog [asp.net] on Topsy.com

Pingback from  Twitter Trackbacks for                 Strongly Typed Session Variables in ASP.NET MVC - Patrick Steele's .NET Blog         [asp.net]        on Topsy.com

# re: Strongly Typed Session Variables in ASP.NET MVC

1. These SessionKeys classes are a bad idea because they break encapsulation. Outside of the extension method/property which gets/sets the value to the persistence mechanism (session in this case), the key value should not be used. Since it should only be used in one (two in the case of having both a getter and setter) place, it should not be available any other places.

2. With the implementation you have suggested, you require violating OCP whenever you need to add another session variable. At least with Jarret's implementation the methods can be each placed into their own extension method class.

3. Jarret's implementation suffers from having the caller know too much (ie. where the object is persisted), while yours involves an ever-growing God object with essentially global variables (from the point of view of any individual action). Much better than either would be to define "contexts". Within any context you would group any properties which logically go together:

public class SpeakerContext {

   const string infokey = "SpeakerContext.SpeakerInfo";

   public virtual SpeakerInfo SpeakerInfo {

       get {

           var info = HttpContext.Current.Session[infokey] as SpeakerInfo;

           if(info == null) {

               info = new SpeakerInfo();

               HttpContext.Current.Session[infokey]=info;

           }

           return info;

       }

       set {

           HttpContext.Current.Session[infokey]=info;

       }

   }

   //include other speaker related properties here

}

I would then register these contexts in my container and then make them dependencies of my controller. This way I can replace them as I instantiate my controller within my unit tests (I would also be writing them different than this example to make them testable themselves without requiring a current httpcontext).

Tuesday, September 22, 2009 4:17 PM by Bill

# Reflective Perspective - Chris Alcock » The Morning Brew #439

Pingback from  Reflective Perspective - Chris Alcock  » The Morning Brew #439

Wednesday, September 23, 2009 3:28 AM by Reflective Perspective - Chris Alcock » The Morning Brew #439

# re: Strongly Typed Session Variables in ASP.NET MVC

Why can't we just have extension properties and be done with it? Some things, like session, are begging to be dynamic. I didn't like the parens in my own post (which you've fixed - methods should be methods, properties should be properties), and I didn't like putting on another wrapper (my previous post) for strong typing (MVC already wraps HttpSessionState with a new HttpSessionStateWrapper from the Abstractions library).

Wednesday, September 23, 2009 6:14 AM by Jarrett

# re: Strongly Typed Session Variables in ASP.NET MVC

Hi Patrich, why not going on step further and declare a strongly typed session object like shown here: weblogs.asp.net/.../strongly-typed-session-in-asp-net.aspx

Best regards, Denny

Wednesday, September 23, 2009 6:31 AM by Denny

# re: Strongly Typed Session Variables in ASP.NET MVC

Thanks for the article, very nice code...

Wednesday, September 23, 2009 2:27 PM by Alex

# re: Strongly Typed Session Variables in ASP.NET MVC

I have two code snippets I created to do just that. While I don't have it attached to a base class, I put it into a global static class as a static property.

I avoid having a class that has the keys as properties since it's only maintained through the property. While I could expand the code to use such a concept, I think it would just clutter the code further and cause confusion for later developers. Instead there's one place and one place only to work with the current session for the site.

For Reference Types

<?xml version="1.0"?>

<CodeSnippets xmlns="schemas.microsoft.com/.../CodeSnippet">

 <CodeSnippet Format="1.0.0">

   <Header>

     <SnippetTypes>

       <SnippetType>Expansion</SnippetType>

     </SnippetTypes>

     <Title>Session Property: Reference types</Title>

     <Author>Jeff Klawiter</Author>

     <Description> Creates a Static property to wrap a session variable.

     </Description>

     <HelpUrl>

     </HelpUrl>

     <Shortcut>propsession</Shortcut>

   </Header>

   <Snippet>

     <Declarations>

       <Literal Editable="true">

         <ID>Property</ID>

         <ToolTip>The name of the Property</ToolTip>

         <Default>Name</Default>

         <Function>

         </Function>

       </Literal>

       <Object Editable="true">

         <ID>type</ID>

         <ToolTip>The type of the property</ToolTip>

         <Default>string</Default>

         <Function>

         </Function>

         <Type>

         </Type>

       </Object>

       <Literal Editable="true">

         <ID>value</ID>

         <ToolTip>value</ToolTip>

         <Default>new $type$()</Default>

         <Function>

         </Function>

       </Literal>

     </Declarations>

     <Code Language="csharp"><![CDATA[public static $type$ $Property$

 {

 get

 {

     $type$ obj = HttpContext.Current.Session["$Property$"] as $type$;

     if (obj == null)

     {

         $Property$ = $value$;

         return $Property$;

     }

     return obj;

 }

 set

 {

 HttpContext.Current.Session["$Property$"] = value;

 }

 }

 $end$]]></Code>

   </Snippet>

 </CodeSnippet>

</CodeSnippets>

And for Value Types

<?xml version="1.0"?>

<CodeSnippets xmlns="schemas.microsoft.com/.../CodeSnippet">

 <CodeSnippet Format="1.0.0">

   <Header>

     <SnippetTypes>

       <SnippetType>Expansion</SnippetType>

     </SnippetTypes>

     <Title>Session Property: Valuetypes</Title>

     <Author>Jeff Klawiter</Author>

     <Description>

       Creates a Static property to wrap value type session variable

     </Description>

     <HelpUrl>

     </HelpUrl>

     <Shortcut>propsessionval</Shortcut>

   </Header>

   <Snippet>

     <Declarations>

       <Literal Editable="true">

         <ID>Property</ID>

         <ToolTip>The name of the Property</ToolTip>

         <Default>Name</Default>

         <Function>

         </Function>

       </Literal>

       <Object Editable="true">

         <ID>type</ID>

         <ToolTip>The type of the property</ToolTip>

         <Default>string</Default>

         <Function>

         </Function>

         <Type>

         </Type>

       </Object>

       <Literal Editable="true">

         <ID>value</ID>

         <ToolTip>value</ToolTip>

         <Default>Default Value</Default>

         <Function>

         </Function>

       </Literal>

     </Declarations>

     <Code Language="csharp">

     <![CDATA[public static $type$ $Property$

 {

 get

 {

     if (HttpContext.Current.Session["$Property$"] == null)

     {

         $Property$ = $value$;

         return $Property$;

     }

     return ($type$)HttpContext.Current.Session["$Property$"];

 }

 set

 {

 HttpContext.Current.Session["$Property$"] = value;

 }

 }

 $end$]]></Code>

   </Snippet>

 </CodeSnippet>

</CodeSnippets>

Wednesday, September 23, 2009 2:34 PM by Jeff Klawiter

# re: Strongly Typed Session Variables in ASP.NET MVC

There is open source project to enhance Session object with extensions methods to pass and retrieve strongly typed objects.

I would suggest to use it. It looks like:

IFoo foo = Session.Get<Foo>();

or with special key:

IFoo foo = Session.Get<Foo>(key);

Wednesday, September 23, 2009 5:28 PM by dario-g

# re: Strongly Typed Session Variables in ASP.NET MVC

Thanks Patrick,

This will help us

Thursday, September 24, 2009 2:43 AM by vkdwivedi

# Strongly Typed Session Variables in ASP.NET MVC

You are voted (great) - Trackback from WebDevVote.com

Thursday, September 24, 2009 5:31 AM by WebDevVote.com

# re: Strongly Typed Session Variables in ASP.NET MVC

Bill,

I love your idea of the SpeakerContext object that is injected via an IOC container!  This also removes the one big thing I do NOT like about my implementation is that it relies on inheritance.

Perhaps an ISpeakerContext interface that I can mock during testing, and then create a SessionSpeakerContext implementation for production (which can be easily swapped out later by a different implementation without changing any code).

Off to code...

Thursday, September 24, 2009 11:00 AM by PSteele

# re: Strongly Typed Session Variables in ASP.NET MVC

Denny/Jeff Klawiter/dario-g,

All of those rely too much on knowing the location of where the data is stored.  I prefer to abstract that.

Thursday, September 24, 2009 11:34 AM by PSteele

# Link utili della settimana

Descrizione di Unity , il framework di Inversion of Control e Dipendency Injection sviluppato dal team

Friday, September 25, 2009 8:28 AM by Maurizio Tammacco's blog

# Extension Properties

A couple of weeks ago, a post I made about Strongly Typed Session Variables in ASP.NET led to some interesting

Wednesday, October 07, 2009 12:41 PM by Patrick Steele's .NET Blog

# Extension Properties

A couple of weeks ago, a post I made about Strongly Typed Session Variables in ASP.NET led to some interesting

Wednesday, October 07, 2009 1:00 PM by Patrick Steele

# Extension Properties | I love .NET!

Pingback from  Extension Properties | I love .NET!

Wednesday, October 07, 2009 3:18 PM by Extension Properties | I love .NET!

# Link utili della settimana #1

Descrizione di Unity , il framework di Inversion of Control e Dipendency Injection sviluppato dal team

Monday, October 12, 2009 4:52 AM by Maurizio Tammacco's blog

# re: Strongly Typed Session Variables in ASP.NET MVC

Instead of:

 var info = Session[SessionKeys.SpeakerInfoKey] as SpeakerInfo;

 if(info == null)

 {

   info = new SpeakerInfo();

 }

 return info;

Try:

 return Session[SessionKeys.SpeakerInfoKey] as SpeakerInfo

   ?? new SpeakerInfo();

:-)

Tuesday, October 13, 2009 7:52 AM by Luke Breuer