Posts Tagged ‘session’

Storing LINQ Objects in SQL-Based Session State

// January 30th, 2008 // 3 Comments » // LINQ

Scott Hanselman recently posted about various options you have for session storage while using ASP.Net. In the comments of his post I brough up an issue I recently encountered at work (where we use SQL Server session state):

LINQ-To-Sql generated objects are not marked [Serializable] and cannot be stored in out-of-process session storage.

To get around this I have whipped up the following helper class which will serialize LINQ-To-Sql objects if you set the DataContext's Serializable property to "Unidirectional".

Note: The following class does not current work for storing List<X> where X is a LINQ-To-Sql object. I'll be working to resolve that sometime later this week.

   1: using System;
   2: using System.IO;
   3: using System.Runtime.Serialization;
   4: using System.Text;
   5: using System.Xml;
   6: using System.Web;
   7: 
   8: namespace SquaredRoot.Helper
   9: {
  10:   public class SessionHelper
  11:   {
  12: 
  13:     private SessionHelper(){}
  14: 
  15:         public static T Get<T>( string key ) where T : class
  16:         {
  17: 
  18:             object o = HttpContext.Current.Session[key];
  19:             if( o == null )
  20:                 return default( T );
  21: 
  22:             if( o.GetType() == typeof( string ) && typeof( T ) != typeof( string ) )
  23:             {
  24:                 string s = o as string;
  25:                 Stream stream = new MemoryStream( Encoding.Unicode.GetBytes(s) );
  26:                 XmlDictionaryReader xml = XmlDictionaryReader.CreateTextReader( stream, new XmlDictionaryReaderQuotas() );
  27:                 DataContractSerializer dcs = new DataContractSerializer( typeof( T ) );
  28:                 T t = (T)dcs.ReadObject( xml, true );
  29:                 xml.Close();
  30:                 return t;
  31:             }
  32:             else
  33:                 return o as T;
  34: 
  35:         }
  36: 
  37:         private static bool HasClassAttribute( object o, Type attribute, bool inherit )
  38:         {
  39:             return ( o.GetType().GetCustomAttributes( attribute, inherit ).Length > 0 );
  40:         }
  41: 
  42:         public static void Set( string key, object item )
  43:         {
  44: 
  45:             object value = item;
  46:             if( HasClassAttribute( item, typeof(DataContractAttribute), false )
  47:         && !HasClassAttribute( item, typeof(SerializableAttribute), false ) )
  48:             {
  49:                 DataContractSerializer dcs = new DataContractSerializer(item.GetType());
  50:                 StringBuilder sb = new StringBuilder();
  51:                 XmlWriter writer = XmlWriter.Create(sb);
  52:                 dcs.WriteObject( writer, item );
  53:                 writer.Close();
  54:                 value = sb.ToString();
  55:             }
  56: 
  57:             if( HttpContext.Current.Session[key] == null )
  58:         HttpContext.Current.Session.Add( key, value );
  59:             else
  60:         HttpContext.Current.Session[key] = value;
  61: 
  62:         }
  63: 
  64:     }
  65: }
Kick It on DotNetKicks.comShout It on DotNetShoutOuts.com

MVC: ViewData vs. TempData

// December 20th, 2007 // 5 Comments » // MVC

NOTE:
This article was written for the December CTP release of the MVC framework. Unfortunately, it does not entirely apply to the Preview 2 release or subsequent releases.

A commenter (oVan) recently left a comment on one of my posts with a suggestion to redirect to a different URL rather than display a different view. He cautioned that if I do so to make certain I use store data in the TempData dictionary rather than ViewData. I had not yet heard of the TempData dictionary, so I set off into Reflector to find out what exactly it is.

Initially it appeared that TempData was simply a Dictionary<string,object> stored in session. This is close to the truth, but not the whole truth. In fact the internal declaration of TempData's storage device is:

Pair<Dictionary<string, object>, HashSet<string>>

 

Why such a complicated declaration? Further digging revealed that the second element of the pair (the HashSet) is used as a kind of key synchronization device. When an item is added to the internal storage, the key is placed in the HashSet. At some point that I have been unable to determine, the key is removed from the HashSet. Then when the TempData object is built again, the discrepancy is noticed and the Dictionary entry that has a key not contained in the HashSet is removed from the Dictionary.

The end result is that any data stored in TempData will be around for the life the current request and the next request only, or until the item is removed explicitly. This is useful when you want to pass data to another view that you will be redirecting to, rather than rendering to.

    1 [ControllerAction]

    2 public void Index()

    3 {

    4     TempData["text"] = "lorem ipsum";

    5     RedirectToAction( "Test1" );

    6     //RenderView("Index");

    7 }

    8 

    9 [ControllerAction]

   10 public void Test1()

   11 {

   12     string text = TempData["text"] as string;

   13     RenderView("Test1");

   14 }

   15 

   16 [ControllerAction]

   17 public void Test2()

   18 {

   19     string text = TempData["text"] as string;

   20     RenderView("Test2");

   21 }

 

In the code above if you navigate to the Index page, you are automatically redirected to the Test1 action's URL. The Test1 action then executes and is able to access the data stored for it in TempData. If you then navigate to the Test2 action, that action is unable to retrieve the data previously stored in TempData.

To retrieve data from TempData inside of a view, do the following:

<% =ViewContext.TempData["text"] %>

 

One suggestion for an improvement in the next CTP would be to have all data available in TempData copied over to ViewData at the beginning of a request (after the old TempData has been cleared). This would allow us to simply say:

<% =ViewData["text"] %>

 

Otherwise the view has to be very aware of the controller and how it plans to pass data into the view. Currently I cannot have a view that supports being passed data both ways without doing the following:

<% =ViewContext.TempData["text"] ?? ViewData["text"] %>

Kick It on DotNetKicks.comShout It on DotNetShoutOuts.com