views:

230

answers:

2

Hi, I am sure that I have made some painfully obvious blunder(s) that I just cannot see. I am hoping one of you can set me straight.

I my session management is working perfectly except that if a user on one machine enters data, a user who starts a session on another machine will also retreive the session information from the first. Not so good. :(

I call my sessions like this:

UserInfo userinfo = UserInfo.Session;

My session mgt class uses this:

static UserInfo userInfo;

static public UserInfo Session
{
    get
    {
        if (userInfo == null)
        {
            userInfo = new UserInfo();
            userInfo.ResetSessionTime();
        }
        return userInfo;
    }
}

I read and write the data like this. I realize that I could serialize the entire class, but it seems like a lot more overhead to serialize and deserialize an entire class each time the class is called as opposed to just grabbing the one or two items I need.

Decimal _latitude;
private String SessionValue(String sKey, String sValue, String sNewValue)
    {
        String sRetVal = "";
        if (sNewValue == null)//not wanting to update anything
        {
            if (sValue == null)//there is no existing value
            {
                sRetVal = (String)System.Web.HttpContext.Current.Session[sKey];
            }
            else
            {
                sRetVal = sValue;
            }
        }
        else
        {
            System.Web.HttpContext.Current.Session[sKey] = sNewValue;
            sRetVal = sNewValue;
        }
        return sRetVal;
    }



    public Decimal Latitude
    {
        get { return SessionValue("Latitude", _latitude); }
        set { _latitude = SessionValue("Latitude", _latitude, value); }
    }

Thanks for your help

+1  A: 

This happens because you store your user info in a static field. Static instances are shared between all requests, and lives the entire lifetime of your application.

In other words, all your users will get the same UserInfo instance from UserInfo.Session.

To fix this you could:

  • Serialize the whole class into session. I don't know which other properties you have, but I would guess it would not be too much of an overhead.
  • Create an instance of UserInfo per request, so that the user always reads from a new instance, which in turn will refresh it's values from Session.
driis
+1  A: 

1) You're using statics for your UserInfo, which means that a single instance of this class is shared among all requests coming to your web server.

2) You're not only storing values in the session (which isn't shared among users) but also in an instance variable, which in this case WILL be shared among users.

So the value of _latitude is causing you this issue. A simple solution is this:

public class Userinfo
{
    public Decimal Latitude
    {
        get { return System.Web.HttpContext.Current.Session["Latitude"]; }
        set { System.Web.HttpContext.Current.Session["Latitude"] = value; }
    }
}

A better, more testable version would be:

public class UserInfo
{
    private HttpSessionStateWrapper _session;
    public UserInfo(HttpSessionStateWrapper session)
    ( 
       // throw if null etc
       _session = session;
    )

    public Decimal Latitude
    {
        get { return _session["Latitude"]; }
        set { _session["Latitude"] = value; }
    }
}

In the second instance, within a request you just construct a new instance of the HttpSessionStateWrapper (using the current Session) and pass it to the UserInfo instance. When you test, you can just pass in a mock Wrapper.

No matter what, the UserInfo instance shouldn't be shared among sessions and it should write and read directly from the Session. Don't try to prematurely optimize things by keeping local versions of your session values. You aren't saving any time and you're just opening yourself up to bugs.

Will
Thank you, this works perfectly. Thanks also for taking the time to include examples.
Praesagus
You might also look into using either the StateServer or SqlServer session state. If this value is required to live for the life of the users time online, then you might find app pool recycling will cause strange errors for the usrs.
Bruce Chapman