Session singleton causing cast exception

T

Tomcat

I've put together a class (based on the singleton pattern) for
accessing data in an ASP.Net session but am running into a very weird
problem. I've put together a small(ish) segment of code that
reproduces the problem (see below).

The singleton (CSession) provides two static methods; one for
providing a reference to the single session instance of the class
(creating and stuffing a new instance in the session object if it
doesn't exist), and one for explicitly clearing it. The constructor is
marked private so that CSession alone is able to create instances of
itself.

CSession has just one data member, an instance of a CUser class that
simply stores a string (the 'cached' status of the object) and an int
(a 'counter').

Therefore I can write the following code to use these objects:

// get a reference to the user object managed by the session singleton
CUser objUser = CSession.Instance().CurrentUser ;

// do something (anything) to objUser such as increment the counter
++objUser.Counter ;

// remove singleton from session completely
CSession.Clear() ;

Step 1: If I use the code above in an aspx page then each time the
page is accessed I get the expected behaviour (create singleton in
session, increment counter to intial value + 1, remove singleton from
session).

Step 2: If I then modify the code slightly by commenting out the
CSession.Clear() line and upload it; again, I get what I expected
(singleton is recreated, counter is incremented to initial value + 1,
when page is next loaded the singleton is retreieved and the counter
incremented to initial value + 2).

Step 3: If I uncomment that line again though I get an expection
thrown 'specified cast is not valid at CSession.Instance()' when I try
loading the page. It seems that the object stored in the session
object can no longer be cast to CSession.

I have to admit to being completely baffled by this one. My only real
thoughts were:

1) When I commented out CSession.Clear() the method was 'optimised'
out of the class since it wasn't called by any client code. Why though
would that only cause problems in Step 3 and not Step 2?

2) ASP wasn't able to serialise the objects properly; but I believe
this is only a problem if your session state is maintained out of
process and it isn't in this case. I have though tried adding the
[Serializable] attribute before the class declarations without
success.

I appreciate that this a bit of a long winded explanation so thanks
for reading this far; I couldn't think of a more succient way of
describing this. Code is included below for those that care.

Thanks,

Matt

testpage.aspx
=============

<%@ Page src="testpage.aspx.cs" inherits="TEST.Pages.CPage_Blank" %>
<html>
<body>
<asp:label id="lblBlank" runat="server" />
</body>
</html>

testpage.aspx.cs
================

using System ;
using System.Web ;
using System.Web.UI ;
using System.Web.UI.WebControls ;
using System.Web.UI.HtmlControls ;
using System.Text ;

namespace TEST.Global
{

[Serializable]
public class CUser
{
public CUser()
{
m_strStatus = "New Born Baby" ;
m_nCounter = 0 ;
}

public string Status
{
get { return m_strStatus ; }
set { m_strStatus = value ; }
}

public int Counter
{
get { return m_nCounter ; }
set { m_nCounter = value ; }
}

public string ToString()
{
StringBuilder sb = new StringBuilder(250) ;

sb.Append( "CUser;" ) ;
sb.Append( "Status = '" + Status + "';" ) ;
sb.Append( "Counter = " + Counter.ToString() + ";" ) ;

return sb.ToString() ;
}

private string m_strStatus ; //tmp
private int m_nCounter ; //tmp

} // class CUser

[Serializable]
public class CSession
{
// private constructor so only this class can create instances of
itself
private CSession()
{
m_objUser = new CUser() ;
}

static public CSession Instance()
{
CSession objSession ;

try
{
if ( null != HttpContext.Current.Session[SESSION_SINGLETON] )
{
objSession =
(CSession)HttpContext.Current.Session[SESSION_SINGLETON] ;
objSession.m_objUser.Status = "Retrieved Safely From ASP
Session" ;
}
else
{
objSession = new CSession() ;
objSession.m_objUser.Status = "New CSession Instance Created
and Added to ASP Session" ;
HttpContext.Current.Session[SESSION_SINGLETON] = objSession
;
}
}
catch (Exception E)
{
objSession = new CSession() ;
objSession.m_objUser.Status = "Error: (" + E.ToString() + ")
New CSession Instance Created and Added to ASP Session" ;
HttpContext.Current.Session[SESSION_SINGLETON] = objSession ;
}

return objSession ;
}

public static void Clear()
{
// remove session object so that space can be reclaimed
HttpContext.Current.Session.Remove(SESSION_SINGLETON) ;
}

public CUser CurrentUser
{
get { return m_objUser ; }
set { m_objUser = value ; }
}

// name that will be used as key for Session object
private /*static*/ const string SESSION_SINGLETON =
"SESSION_SINGLETON";

private CUser m_objUser ;

} // class CSession

} // namespace TEST.Global

namespace TEST.Pages
{

public class CPage_Blank : System.Web.UI.Page
{
protected Label lblBlank ;

protected void Page_Load(Object objSender, EventArgs eventArgs)
{
lblBlank.Text = "<p>Hello</p>" ;

testSingleton() ;
}

private void writeLn(string str) { lblBlank.Text += "<p>" + str +
"</p>" ; }
private void writeHd(string str) { lblBlank.Text += "<h2>" + str +
"</h2>" ; }

private void testSingleton()
{
writeHd( "Initial Access" ) ;
writeLn( TEST.Global.CSession.Instance().CurrentUser.ToString()
) ;

TEST.Global.CUser user =
TEST.Global.CSession.Instance().CurrentUser ;

writeHd( "'Cached' User Reference" ) ;
writeLn( user.ToString() ) ;

writeLn( "Increase CurrentUser.Counter by One ..." );
++user.Counter ;
writeLn( user.ToString() ) ;

writeLn( "Increase CurrentUser.Counter by One ..." );
++user.Counter ;
writeLn( user.ToString() ) ;

// Comment Following Line Out for Step 2
TEST.Global.CSession.Clear() ;
}

} // CPage_Blank

} // namespace TEST.Pages
 
A

Alvin Bruney [MVP]

Your post went unanswered. Have you resolved this issue?

--
Regards,
Alvin Bruney [ASP.NET MVP]
Got tidbits? Get it here...
http://tinyurl.com/3he3b
Tomcat said:
I've put together a class (based on the singleton pattern) for
accessing data in an ASP.Net session but am running into a very weird
problem. I've put together a small(ish) segment of code that
reproduces the problem (see below).

The singleton (CSession) provides two static methods; one for
providing a reference to the single session instance of the class
(creating and stuffing a new instance in the session object if it
doesn't exist), and one for explicitly clearing it. The constructor is
marked private so that CSession alone is able to create instances of
itself.

CSession has just one data member, an instance of a CUser class that
simply stores a string (the 'cached' status of the object) and an int
(a 'counter').

Therefore I can write the following code to use these objects:

// get a reference to the user object managed by the session singleton
CUser objUser = CSession.Instance().CurrentUser ;

// do something (anything) to objUser such as increment the counter
++objUser.Counter ;

// remove singleton from session completely
CSession.Clear() ;

Step 1: If I use the code above in an aspx page then each time the
page is accessed I get the expected behaviour (create singleton in
session, increment counter to intial value + 1, remove singleton from
session).

Step 2: If I then modify the code slightly by commenting out the
CSession.Clear() line and upload it; again, I get what I expected
(singleton is recreated, counter is incremented to initial value + 1,
when page is next loaded the singleton is retreieved and the counter
incremented to initial value + 2).

Step 3: If I uncomment that line again though I get an expection
thrown 'specified cast is not valid at CSession.Instance()' when I try
loading the page. It seems that the object stored in the session
object can no longer be cast to CSession.

I have to admit to being completely baffled by this one. My only real
thoughts were:

1) When I commented out CSession.Clear() the method was 'optimised'
out of the class since it wasn't called by any client code. Why though
would that only cause problems in Step 3 and not Step 2?

2) ASP wasn't able to serialise the objects properly; but I believe
this is only a problem if your session state is maintained out of
process and it isn't in this case. I have though tried adding the
[Serializable] attribute before the class declarations without
success.

I appreciate that this a bit of a long winded explanation so thanks
for reading this far; I couldn't think of a more succient way of
describing this. Code is included below for those that care.

Thanks,

Matt

testpage.aspx
=============

<%@ Page src="testpage.aspx.cs" inherits="TEST.Pages.CPage_Blank" %>
<html>
<body>
<asp:label id="lblBlank" runat="server" />
</body>
</html>

testpage.aspx.cs
================

using System ;
using System.Web ;
using System.Web.UI ;
using System.Web.UI.WebControls ;
using System.Web.UI.HtmlControls ;
using System.Text ;

namespace TEST.Global
{

[Serializable]
public class CUser
{
public CUser()
{
m_strStatus = "New Born Baby" ;
m_nCounter = 0 ;
}

public string Status
{
get { return m_strStatus ; }
set { m_strStatus = value ; }
}

public int Counter
{
get { return m_nCounter ; }
set { m_nCounter = value ; }
}

public string ToString()
{
StringBuilder sb = new StringBuilder(250) ;

sb.Append( "CUser;" ) ;
sb.Append( "Status = '" + Status + "';" ) ;
sb.Append( "Counter = " + Counter.ToString() + ";" ) ;

return sb.ToString() ;
}

private string m_strStatus ; //tmp
private int m_nCounter ; //tmp

} // class CUser

[Serializable]
public class CSession
{
// private constructor so only this class can create instances of
itself
private CSession()
{
m_objUser = new CUser() ;
}

static public CSession Instance()
{
CSession objSession ;

try
{
if ( null != HttpContext.Current.Session[SESSION_SINGLETON] )
{
objSession =
(CSession)HttpContext.Current.Session[SESSION_SINGLETON] ;
objSession.m_objUser.Status = "Retrieved Safely From ASP
Session" ;
}
else
{
objSession = new CSession() ;
objSession.m_objUser.Status = "New CSession Instance Created
and Added to ASP Session" ;
HttpContext.Current.Session[SESSION_SINGLETON] = objSession
;
}
}
catch (Exception E)
{
objSession = new CSession() ;
objSession.m_objUser.Status = "Error: (" + E.ToString() + ")
New CSession Instance Created and Added to ASP Session" ;
HttpContext.Current.Session[SESSION_SINGLETON] = objSession ;
}

return objSession ;
}

public static void Clear()
{
// remove session object so that space can be reclaimed
HttpContext.Current.Session.Remove(SESSION_SINGLETON) ;
}

public CUser CurrentUser
{
get { return m_objUser ; }
set { m_objUser = value ; }
}

// name that will be used as key for Session object
private /*static*/ const string SESSION_SINGLETON =
"SESSION_SINGLETON";

private CUser m_objUser ;

} // class CSession

} // namespace TEST.Global

namespace TEST.Pages
{

public class CPage_Blank : System.Web.UI.Page
{
protected Label lblBlank ;

protected void Page_Load(Object objSender, EventArgs eventArgs)
{
lblBlank.Text = "<p>Hello</p>" ;

testSingleton() ;
}

private void writeLn(string str) { lblBlank.Text += "<p>" + str +
"</p>" ; }
private void writeHd(string str) { lblBlank.Text += "<h2>" + str +
"</h2>" ; }

private void testSingleton()
{
writeHd( "Initial Access" ) ;
writeLn( TEST.Global.CSession.Instance().CurrentUser.ToString()
) ;

TEST.Global.CUser user =
TEST.Global.CSession.Instance().CurrentUser ;

writeHd( "'Cached' User Reference" ) ;
writeLn( user.ToString() ) ;

writeLn( "Increase CurrentUser.Counter by One ..." );
++user.Counter ;
writeLn( user.ToString() ) ;

writeLn( "Increase CurrentUser.Counter by One ..." );
++user.Counter ;
writeLn( user.ToString() ) ;

// Comment Following Line Out for Step 2
TEST.Global.CSession.Clear() ;
}

} // CPage_Blank

} // namespace TEST.Pages
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,770
Messages
2,569,584
Members
45,075
Latest member
MakersCBDBloodSupport

Latest Threads

Top