C#/ASP.NET - 在会话中存储泛型列表与在会话中存储单个变量



我已经看到许多用于 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 状态构建数据访问层的一些方法。

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

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

myObject.TheList.VariableIWant
VS
myObject.VariableIWant

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

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

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


问题

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

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

使用选项 1,很容易分辨出它在做什么。您正在尝试标准化类保存/检索会话数据的方式,而不是将其分散到各个地方。

选项 2 更加令人困惑。事实上,我已经看了几次,我无法弄清楚清单上发生了什么。为什么选项 2 需要列表,而选项 1 不需要?

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

选项 #1>选项 #2

两个原因:

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

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

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

最新更新