【问题标题】:C#/ASP.NET - Storing Generic List in Session VS Individual Variables in SessionC#/ASP.NET - 在会话中存储通用列表 VS 在会话中存储单个变量
【发布时间】:2017-10-07 02:06:28
【问题描述】:

我已经看到了许多 ASP.NET 会话状态的“包装”类,其中一些做了类似的事情:

强类型层(伪代码 #1)

public class MySession
{
    public int MyID
    {
        get
        {
            return Convert.ToInt32(HttpContext.Current.Session["MyID"]);
        }
        set
        {
            HttpContext.Current.Session["MyID"] = value;
        }
    }
    public string MyName
    {
        get
        {
            return (HttpContext.Current.Session["MyName"]).ToString();
        }
        set
        {
            HttpContext.Current.Session["MyName"] = value;
        }
    }
    ...

    public MySession()
    {
        // Could be static or instantiated depending on needs...
    }
    ...
}

///// USAGE IN OTHER CLASS /////

MySession currSession = new MySession();
currSession.MyID = 5;
currSession.MyName = "John Doe";

Console.WriteLine($"{currSession.MyName}'s ID = {currSession.MyID}");

然后我看到其他人这样做:

通用列表变体(伪代码 #2)

public class SessionVariables
{
    public int MyID
    {
        get;
        set
        {
            MyID = value;
            MySession.SaveVariables();
        }
    }
    public string MyName
    {
        get;
        set
        {
            MyName = value;
            MySession.SaveVariables();
        }
    }

    ...
}

public class MySession
{
    public static List<SessionVariables> Variables;

    // Might be private in real application environment
    public MySession() // Could be static or instantiated depending on needs...
    {

        if (HttpContext.Current.Session["MyVariables"] == null)
        {
            HttpContext.Current.Session["MyVariables"] = new List<SessionVariables>();
        }

        // Obviously more appropriate checking to do here, but for simplicity's sake...
        Variables = (List<SessionVariables>)HttpContext.Current.Session["MyVariables"]

    }

    public static void SaveVariables()
    {
        HttpContext.Current.Session["MyVariables"] = Variables;
    }
    ...
}

///// USAGE /////

public class MyPage
{
    public void MyMethod()
    {
        MySession currSession = new MySession(); // Create variables

        MySession.Variables.MyID = 5;
        MySession.Variables.MyName = "John Doe";
        Console.WriteLine($"{MySession.Variables.MyName}'s ID = {MySession.Variables.MyID}");
        ...
    }
}

想法

显然,这些示例都是伪代码样式(因此请忽略一般错误),但它们说明了为会话状态构建数据访问层的一些方法。

我做了一些与第一个变体类似的事情,尽管它具有更全面的数据类型映射/转换计划。我使用一个“普通”类来包装 Session,但它很容易是静态的,因为当调用它们的“get”时属性将从 Session 状态中提取,因此永远不会不同步,因为该类实际上不持有任何数据本身。

从第一印象来看,第二个对我来说似乎更“矫枉过正”,因为是的,您只将一个变量存储在 Session 状态中,但它通过强制代码引用列表而使其余代码混乱:

myObject.TheList.VariableIWant
VS
myObject.VariableIWant

我更喜欢后者(只是看起来更干净),尽管这可以很容易地隐藏在超类中,或者只是让局部变量直接引用列表:

new MySession(); // Create the variables
List<SessionVariables> mySession = MySession.Variables;

...虽然乍一看这对我来说有点脏。但是,我不知道使用列表进行存储实际上会给代码/性能带来多少好处,因为存储表示列表的对象应该占用与单独执行每个变量一样多的内存,至少这是我的想法。


问题

从长远来看,哪种做法更好/维护成本低?和/或哪个给网站带来更好的性能?

【问题讨论】:

  • 会话是邪恶的。最好的方法是不使用会话并建立无状态网站。这两个解决方案看起来不是线程安全的,我认为它们不会那么好。
  • @FilipCordas 好吧,是的(因此使用自定义类来包装它)......但有时你必须使用 Sessions / 自定义包装类。使用查询字符串可以(有时是)被认为是一种安全风险,因为您将有关服务器代码的知识暴露给最终用户,这很少是一个好主意。那么如何将特定信息从一页转移到下一页呢?即如果用户点击一个订单,你如何将订单号转移到订单详情页面?

标签: c# asp.net session model-view-controller


【解决方案1】:

选项 #1 是我看到的最常见的模式,我使用它。您可以通过使用常量而不是魔术字符串来改进它。会话有它们的问题,但制作一个完全无状态的应用程序也是如此。我还建议使用 HttpCache 而不是 Session——它不会消耗 AppPool 资源。但是,只要您使用像 SQL Server 这样的会话提供程序,就可以在网络场上使用会话。分布式缓存是另一回事。

【讨论】:

    【解决方案2】:

    使用选项 1,很容易判断它在做什么。您正在尝试标准化您的类如何保存/检索会话数据,而不是将其分散在各处。

    选项 2 更令人困惑。事实上,我已经看过好几次了,我不知道清单上发生了什么。为什么选项 2 需要列表而选项 1 不需要?

    对于您要执行的操作,选项 1 可以正常工作。常量不是一个坏主意,但在这种情况下,我可能会跳过它。该字符串的含义非常明显,其他类不需要复制它,因为它们正在通过这个来访问 Session。

    【讨论】:

      【解决方案3】:

      选项 #1 > 选项 #2

      两个原因:

      1. 您应该在使用完会话变量后立即删除它们,使用Session.Remove。否则,您的会话状态将越来越大,您的 Web 服务器将无法支持尽可能多的同时用户。但是如果你所有的变量都保存在一个大的会话变量中,这有点难以完成。

      2. 我会避免在会话中使用引用类型(例如任何类型的 List)。它会产生歧义:如果您的会话存储在进程中,则会话仅存储一个指针,您可以像普通引用类型一样change session variables by changing the objects that they reference。但是,如果您的会话超出 proc(例如使用状态服务器或 SQL 状态),那么您的对象将被序列化和冻结,如果您更改引用的对象,这些更改将不会反映在你的会话变量。这可能会产生各种只出现在您的上层环境中的错误(如果您的开发系统缺少状态服务器)并让您疯狂地尝试进行故障排除。

        您可能会为不可变引用类型设置例外,但您必须小心;仅仅因为一个对象是不可变的,并不意味着它所引用的对象也是不可变的。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2023-03-22
        • 2012-05-31
        相关资源
        最近更新 更多