c#stateserver维护机器之间的会话

时间:2009-11-30 19:38:25

标签: c# asp.net session-state

我确信我已经犯了一些我无法看到的痛苦明显的错误。我希望你们中的一个能让我直截了当。

我的会话管理工作正常,但如果一台机器上的用户输入数据,则在另一台机器上启动会话的用户也将从第一台机器上检索会话信息。不太好。 :(

我这样打电话给我的会议:

UserInfo userinfo = UserInfo.Session;

我的会话mgt类使用:

static UserInfo userInfo;

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

我读取和写入这样的数据。我意识到我可以序列化整个类,但是每次调用类时序列化和反序列化整个类似乎要花费更多的开销,而不是只抓取我需要的一两个项目。

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); }
    }

感谢您的帮助

2 个答案:

答案 0 :(得分:1)

这是因为您将用户信息存储在静态字段中。静态实例在所有请求之间共享,并且在应用程序的整个生命周期中都存在。

换句话说,所有用户都将从UserInfo.Session获得相同的UserInfo实例。

要解决此问题,您可以:

  • 将整个班级序列化为会话。我不知道你有哪些其他属性,但我猜它不会有太大的开销。
  • 为每个请求创建一个UserInfo实例,以便用户始终从新实例中读取,然后新实例将从Session刷新其值。

答案 1 :(得分:1)

1)您正在为UserInfo使用静态,这意味着此类的单个实例在进入Web服务器的所有请求之间共享。

2)您不仅要在会话中存储值(在用户之间不共享),还要在实例变量中存储,在这种情况下,将在用户之间共享。

所以_latitude的价值就是这个问题。一个简单的解决方案就是:

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

更好,更可测试的版本是:

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; }
    }
}

在第二个实例中,在请求中,您只需构造HttpSessionStateWrapper的新实例(使用当前Session)并将其传递给UserInfo实例。测试时,您可以传入一个模拟包装器。

无论如何,UserInfo实例不应在会话之间共享,它应该直接从Session写入和读取。不要试图通过保留会话值的本地版本来过早地优化事物。你没有节省任何时间,而你只是打开了自己的bug。