|
This is a great idea. However we store session state in SQL Server and I get this error message:
Server Error in '/DataTest' Application.
--------------------------------------------------------------------------------
Unable to serialize the session state. Please note that non-serializable objects or MarshalByRef objects are not permitted when session state mode is 'StateServer' or 'SQLServer'.
Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.
Exception Details: System.Web.HttpException: Unable to serialize the session state. Please note that non-serializable objects or MarshalByRef objects are not permitted when session state mode is 'StateServer' or 'SQLServer'.
Any thoughts on how to do this using SQL Server?
Thanks.
|
|
|
|
|
Hi Mike
I havent tried this with SQL server storing state as yet. Have you tried marking the SessionSink Class, methods and accessor Modifiers with the [Serailizable] attribute?
namespace MySessionSink
{
[Serializable]
public class SessionSink
{
private string user;
private string pwd;
[Serializable]
public string GetSetPassword
{
get
{
return this.pwd;
}
set
{
this.pwd = value;
}
}
[Serializable]
public string GetSetUserName
{
get
{
return this.user;
}
set
{
this.user = value;
}
}
}
}
Simon Segal
|
|
|
|
|
Simon,
Good point, I am going to try this and I'll get back to you. I like using SQL Server for session state because of all of the products it has the best fail over characteristics.
|
|
|
|
|
Worked like a charm. Interesting idea. Thanks.
|
|
|
|
|
hi simon
i liked ur idead of keeping a stand alone class for session state,and instanciating it inside the globa.asax file.
now when i try to set the values for the propertys inside the SessionSink class from another class in the application,i get a error like session state not available to the context,why i am getting this error?is there something i am doing wrong.
or there is something more i have to do?
let me know
thanks
asd
|
|
|
|
|
Are you referencing and 'using' (c#) or 'imports' (vb) the System.Web library? Can you email me the line of code that makes it fallover?
Simon Segal
|
|
|
|
|
Hi. I use this very idea in a few asp.net projects.
Your implementation could be improved on though. Here are a few ideas.
1) Property names don't need to have a GetSet prefix. It clutters the code and is a throw back to the days when we didn't have properties as an integral part of the language. The feature is there, use it...
2) The class would be more usable if it encapsulated the session object fully, rather than you just storing the object in session.
E.g.
public class SessionSink
{
public static string Username
{
get
{
return (string)Session["Username"];
}
set
{
Session["Username"] = value;
}
}
}
This way you can access the username property like this.
string strUsername = SessionSink.Username;
Rather than your old way
string strUsername = ((SessionSink)Session["SessionSink"]).GetSetUsername;
This also does away with the need to populate the session object in the session-start event...
Hope this gives you some more ideas.
Pete
Insert Sig. Here!
|
|
|
|
|
I was gonna say the same Almost exactly the same. Great minds think alike. Just one point of concern though, where are you referencing Session from? My idea was based on a instance class, then I though about it, and said to myself 6 of the one, halh a dozen from the other, and decided not to say anything.
I rated this article 2 by mistake. It deserves more. I wanted to get to the second page... - vjedlicka 3:33 25 Nov '02
|
|
|
|
|
leppie wrote:
where are you referencing Session from?
You'd need something like:
using System.Web;
using System.Web.SessionState;
public class SessionSink
{
protected static HttpSessionState Session
{
get
{
HttpContext context = HttpContext.Current;
return (null == context) ? null : context.Session;
}
}
...
}
"These people looked deep within my soul and assigned me a number based on the order in which I joined." - Homer
|
|
|
|
|
Indeed, just looked at my one...I just directly use
HttpContext.Current.Session["BLAH"]
Pete
Insert Sig. Here!
|
|
|
|
|
Thanks Pete
You make two good points. In response to the first point on the GetSet convention, yes I agree that it's old hat and that is exactly why I used it in this example to make the code more accessible to a wider reading audience (it's not part of my prefered coding convention, but perhaps I should not have implicitly condoned it's practice by using it in the artilce). As far as further encapsulating of the Session object goes, your implementation is a excellent one (identical to one posted here previously by Scott Juranek) and one I have also used previously, however I have chosen to use the one I demonstrated most recently for two reasons, firstly I dont need to keep a hanlde on the object or secondly, continually instantiate it ad nauseaum.
Thanks for your input.
Regards,
Simon
Simon Segal
|
|
|
|
|
Simon Segal wrote:
I dont need to keep a hanlde on the object or secondly, continually instantiate it ad nauseaum.
You dont need to do either of those things...It uses static member functions. To use these you do not need to instanciate an instance of the class. Just use the class name.
E.g.
SessionSink.Username
SessionSink.Password
SessionSink.KitchenSink.NoOfTaps
etc etc etc.
Pete
Insert Sig. Here!
|
|
|
|
|
Yes of course! Good point - I stand corrected. It's obvious I guess that you would use a static implementation of the public member functions
Simon Segal
|
|
|
|
|
My team is considering using the SQLServer mode for
state/session management. How do we 'mine' the
data that's persisted in the tables?
|
|
|
|
|
You dont toch the data your self at all. We use the StateServer mode and it is completly transparent to us. You just use Session as you normally would. The only diference is that, behind the scenes, ASP.Net will hold the data in a SQL table rather than in memory.
Pete
Insert Sig. Here!
|
|
|
|
|
I was referring to old session data that is stored in the
tables ASPStateTempSessions and ASPStateTempApplications.
Looking at those data during runtime is quite easy (Session["xxx]).
How do you access the stored session values offline for
data mining? We changed the scheduled job that purges the
tables so that it wouldn't do so frequently.
|
|
|
|
|
Oh right. I see what you want now. It seems you're on the right track. Whats wrong with your current approach?
The stuff in session is generally just Serialized data from memory. Not sure how you'd go about actually working with the data though. Why do you need to do this?
Pete
Pete
Insert Sig. Here!
|
|
|
|
|
We want to mine old session data. Our application
will store a dataset object in the session. We want
to observe user behavior (it's an insurance application)
in the future. We want to view the data *OFFLINE*.
The question is:
How do you extract old session data when SQL Server is being
used as the state server?
|
|
|
|
|
I too have used this idea many times in various projects and after reading the email thread I have only one comment I would like to add. Aside from the style and usability improvements already correctly stated, the usage proposed by Simon is certainly not flawed, unless someone can point out any adverse behaviour that may result from using this particular implementation. Hence the reference to it being a "flawed implementation" is unnecessary and way too strong a comment. I would like to continue to encourage new contributors because I am learning quite a lot from this site. Well done Simon, nice article first up. Pete this was not an attack on you personally but I think the subject title was a little heavy handed, and I do agree with your improvements. Out of curosity can anyone find any possible unwanted adverse behaviour from doing it this way?
Richard Satur
rsatur@optusnet.com.au
|
|
|
|
|
Ok, maybe flawed was the wrong word to use.
Anyway, one such problem would be if session was lost, because of an error that was caught in Application_Error etc. Then, the code here
int intlocID = ((SessionSink)(Session["SessionSink"])).GetSetSiteLocationId;
would fall over because the object is not in session anymore.
If the class was written as shown above, you could write code to cater for these occurances.
E.g.
public class SessionSink
{
public static int SiteLocationId
{
get
{
if(Session["SiteLocationId"] == null)
{
Session["SiteLocationId"] = 0;
}
return (string)Session["SiteLocationId"];
}
set
{
Session["SiteLocationId"] = value;
}
}
}
So, thats why it was slightly flawed, it didn't take into account that his object might not be in session at all.
Pete
Insert Sig. Here!
|
|
|
|
|
Your suggested test:
if(Session["SiteLocationId"] == null) will not tell you if the entire wrappers contents are no longer in session, only that the member "SiteLocationId" is null. Likelyhood is that the entire wrapper is null however it's far from bullet proof. You would have to test every member of the wrapper to be sure that the entire wrapper is no longer usable and then perhaps enforce whatever recovery strategy you have decided to implement.
At any rate the original code posted is still not flawed using Richards definition and your assertion that this line of code:
int intlocID = ((SessionSink)(Session["SessionSink"])).GetSetSiteLocationId;
would break it is incorrect if you consider the code below.
try<br />
{<br />
int intlocID = ((SessionSink) (Session"SessionSink"])).GetSetSiteLocationId;<br />
}<br />
catch(NullReferenceException ex)<br />
{<br />
}
Simon
|
|
|
|
|
Hey, come on. You're changing the rules now.
This :
try
{
int intlocID = ((SessionSink) (Session"SessionSink"])).GetSetSiteLocationId;
}
catch(NullReferenceException ex)
{
}
Is NOT this
private void someMethod()
{
((SessionSink)(Session["SessionSink"])).GetSetSiteLocationId = 1;
}
Sure you can argue that you'll have caught the exception somewhere, that’s fine. You just should have put it in the original article if you're going to resort to using it as defence later.
Besides, in my code the Session Wrapper doesn't do exactly what yours does. Mine is called State and it holds objects references for me. E.g. instead of having each property of an object in a separate session var, I just have 1 session var per object. All the static State properties do is ensure that the object is in an initialised state before it is returned to the caller. If it cannot initialise the object state because of the nature of the object it notifes the caller with an exception.
Lets just agree to disagree, ok. You can write your verbose version and put try/catch blocks around each every chunk of code that uses it.
I'll use my type-safe, succinct version that handles all that itself and only lets you know about occurrences that it can't deal with transparently.
Pete
Insert Sig. Here!
|
|
|
|
|
Pete
The "rules" according to who? Let me draw your attention to the fact that for the sake of brevity I did not include any error trapping code (nor the entire implementation) in my example nor was it my intention to ever do so (and I assume you have read enough articles to notice that many authors do not include it for the same reason). Simple examples that outline a concept are presented generally on the understanding that the reader will accept the implicit issues that come with what has been presented, many if not most programming publications rely on this technique. Therefore it is not a "defence" as you put it rather a response which did not take into account your so-called rules.
Also let me make it clear that I am fan of the implementation that you are advocating and credit for it should go to Scott Juranek as he was the one who posted it here. My implementation was designed around the need for it to be treated and behave as a distinct object in it's own right (it is tightly coupled with the app that uses it) rather than act as a conduit that "holds objects references for me" as you state in your last message.
As far as verbosity goes, your assertion that "If it cannot initialise the object state because of the nature of the object it notifes the caller with an exception." is no less verbose. The code you previously provided (below) appears to throw an exception that presumably you will have to catch somewhere?
public class SessionSink
{
public static int SiteLocationId
{
get
{
if(Session["SiteLocationId"] == null)
{
Session["SiteLocationId"] = 0;
}
return (string)Session["SiteLocationId"];
}
set
{
Session["SiteLocationId"] = value;
}
}
}
Hence your code also requires that you "put try/catch blocks around each every chunk of code that uses it."
Try
{
int x = SessionSink.SiteLocationId;
}
catch(Exception PetesExceptionAbove)
{
etc
}
So which is it? Reset to 0 or throw exception? Reset to zero doesn't appear to be that useful. I need to drill further down to know if the session object is still useful to me or if I should bow out gracefully. My implementation has business rules (remember it's tightly coupled) defined within it and if the object in state is now null, it's time to bow out.
Simon
|
|
|
|
|
The point is you don't HAVE TO throw an exception. There are very few places in State where I throw an exception, or let one be thrown because State can deal with it. The places I do throw them can either be handled at the place of the call if neccessary or just let Application_Error handle it. This is acceptable because when state has lost its information and cannot get it back itself, its generally going to kill the app anyway.
Look, I dont want a slanging match over this. Your wrote a good article, I was just pointing out some improvements. Theres no need to get offended. I have already stated that flawed was not the correct word to use. Maybe, unevolved, but not flawed.
By the way, I didn't get the idea for State from codeproject at all. Can't remember where, but its definitly on other sites too.
Pete
Insert Sig. Here!
|
|
|
|
|
Great Idea. Does anyone have any ideas on seperating the object from dependancy on the session, so that the object can standalone by itself. Ie, being able to be used in a web envirnment as well as a client app.
|
|
|
|