.NET Blog

Tony Cavaliere

 
My Favourite Albums
  And the Grappa wins.
E-mail me Send mail
Add to Technorati Favorites AddThis Feed Button

Subscribe to Cynot Why Not


Recent posts

Disclaimer

Hey unlike other bloggers I stand by what I say but just in case. The opinions expressed herein are my own except on Tuesday when the second card is not turned up otherwise it ain't worth squat.

© Copyright 2010

Session Serialization - But it works on my box!

Here's the situation you are developing an ASP.NET application and you need to maintain server side state. You start to use HttpSessionState and it's quite straight forward. Basically you add code like Session("foo") = obj where foo is the key and obj is the object you what to store in session state. Everything works fine, all unit and integration tests succeed and then you deploy to production and it no longer works. After hours of investigation you find out that the production environment is configured to use out of process session state. The sirens go off and you realize that you forgot to make one of the objects serializable. In process session state does not require that objects be serializable, whereas, out of process does.

Why not be proactive and come up with an approach that will detect this before it hits production. There are a number of approaches that you can use;

  1. Always use out of process session state. This would work but may not be practical.
  2. Add a FxCop rule to ensure all objects placed in session are serializable.
  3. Write a wrapper class that checks that objects placed into session state are serializable.

The last approach is the subject of this post. Listing 1 shows the code for the session wrapper.

Listing 1: Session Wrapper Class

'Access to a singleton of type SerializableSession.

Public Module MyGlobals

    Public Session As SerializableSession = Singleton(Of SerializableSession).Instance

End Module

 

'A simple class wrapper for session. I've only exposed Item (default property).

'Feel free to expose additional methods (e.g., Add)

Public Class SerializableSession

 

    Default Public Property Item(ByVal name As String) As Object

        Get

            Return HttpContext.Current.Session(name)

        End Get

        Set(ByVal value As Object)

            If IsSerializable(value) Then

                HttpContext.Current.Session(name) = value

            Else

                Throw New Exception(value.GetType.FullName + " is not serializable")

            End If

        End Set

    End Property

 

    'Helper function to determine whether the object passed in is serializable.

    'Right now only object that are classes or value types are supported.

    'If you plan to pass references to interfaces or enums then you may not

    'modify this function.

    Private Function IsSerializable(ByVal o As Object) As Boolean

 

        Dim t As Type = o.GetType

        Dim IsObjectSerializable As Boolean = False

 

        If t.IsClass Then

 

            'Check to see if ISerializable interface is implemented.

            For Each [interface] In t.GetInterfaces

                If [interface] Is GetType(System.Runtime.Serialization.ISerializable) Then

                    IsObjectSerializable = True

                    Exit For

                End If

            Next

 

            'Check to see if object is decorated with the Serializable attribute

            If Not IsObjectSerializable Then

                For Each [attribute] In t.GetCustomAttributes(True)

                    If [attribute].GetType Is GetType(System.SerializableAttribute) Then

                        IsObjectSerializable = True

                        Exit For

                    End If

                Next

            End If

 

        Else

            IsObjectSerializable = True

        End If

 

        Return IsObjectSerializable

 

    End Function

 

End Class

The above code makes use of the generic singleton from a previous post. The SerializableSession class only exposes a single property called Item. You can easily add to this class and expose additional methods that exist in the HttpSessionState class. The Item setter calls the IsSerializable helper function that checks that the object is a class and if so that the class implements ISerializable or is decorated with the Serializable attribute. If these conditions are meet then the function returns True. If the object does meet these criterion then False is returned and the setter throws an exception.

This code is by no means complete. What if an interface is passed to the setter of SerializableSession? How should it deal with it? I'll leave that to the reader of this post to figure out.

The Module MyGlobals provides a convenience variable that creates a singleton of type SerializableSession. Listing 2 shows how to make calls to this session wrapper class.

Listing 2: Using the Session Wrapper Class

Partial Class _Default

    Inherits System.Web.UI.Page

 

    Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) _

    Handles Me.Load

 

        MyGlobals.Session("foobar") = New Foobar()

        MyGlobals.Session("moobar") = New Moobar()

        MyGlobals.Session("int") = 5

 

        Response.Write(MyGlobals.Session("foobar").GetType.ToString + ":" + _

            CType(MyGlobals.Session("foobar"), Foobar).val + "</br>")

        Response.Write(MyGlobals.Session("moobar").GetType.ToString + ":" + _

            CType(MyGlobals.Session("moobar"), Moobar).val + "</br>")

        Response.Write(MyGlobals.Session("int").GetType.ToString + ":" + _

            CType(MyGlobals.Session("int"), Integer).ToString + "</br>")

 

    End Sub

 

End Class

 

'Simple test classes. Both Foobar and Moobar should work fine.

Public Class Foobar

    Implements System.Runtime.Serialization.ISerializable

    Public val As String = "Foobar-String"

    Public Sub GetObjectData(ByVal info As System.Runtime.Serialization.SerializationInfo, ByVal context As System.Runtime.Serialization.StreamingContext) Implements System.Runtime.Serialization.ISerializable.GetObjectData

    End Sub

End Class

 

<Serializable()> _

Public Class Moobar

    Public val As String = "Moobar-String"

End Class

 

'If you try to add this to session using SerializableSession a runtime exception will be

'thrown.

Public Class xFoobar

    Sub New()

    End Sub

    Public Sub foo()

    End Sub

End Class

Objects that are not serializable will be caught at runtime, regardless of which environment the code is running on. This is a step in the right direction but we can do better; how about generating compile time errors. I will need to give it some thought as how that might be implemented. Same bat channel, same bat time perhaps in a future post!

Guess the movie

I think the message to, uh, psychos, fanatics, murderers, nutcases all over the world is, uh, "do not mess with suburbanites". Because, uh, frankly we're just not gonna take it any more. Ya know, we're not gonna be content to look after our lawns and wax our cars, paint out houses. We're out to get them, Don, we are out to get them.

Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Categories: ASP.NET | Generics
Posted by CynotWhyNot on Friday, May 23, 2008 3:18 PM
Permalink | Comments (2) | Post RSSRSS comment feed

Singleton the Generic Way

I'm in the process of writing a session wrapper class. It's purpose is to ensure that all objects placed into session be serializable. When it is complete I will be sure to post the code on my blog.

It soon became apparent that this session wrapper needed to be implemented as a singleton. Why not make use of generics and create a generic singleton. The listing below is a VB.NET implementation of a singleton that can be used for any class.

Listing 1: Singleton using Generics

'Constraints ensuring that the type will be a class and has a constructor.

Public Class Singleton(Of T As {New, Class})

 

    'Property to return a single instance of the type

    Private Shared ReadOnly _instance As New T

    Public Shared ReadOnly Property Instance() As T

        Get

            Return _instance

        End Get

    End Property

 

    'Cannot directly instantiate the class

    Private Sub New()

    End Sub

 

End Class

With the exception of generics, this is a typical .NET implementation of a singleton. Note that the constraints ensure that only types that are classes and have a constructor can be used.

Listing 2 shows how to take a plain class and implement it as a singleton using the above code.

Listing 2: Making use of the Generic Singleton

Singleton(Of Foobar).Instance.foo()

Public Class Foobar

    Sub New()

    End Sub

    Public Sub foo()

    End Sub

End Class

In the code example above the class Foobar can be instantiated on it's own. If you would like to restrict how it is created (i.e., it can only be created in the context of the singleton) then package the singleton and the class Foobar into a seperate library and mark Foobar's constructor as Friend. 

Guess the movie

You guys give up yet? Or are you thirsty for more?

Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Categories: Generics | VB.NET
Posted by CynotWhyNot on Tuesday, May 20, 2008 5:03 PM
Permalink | Comments (19) | Post RSSRSS comment feed