【发布时间】:2010-05-12 19:07:31
【问题描述】:
我有一个 Web 应用程序,我想从数据库中提取用户设置并将它们存储起来以供全局访问。将数据存储在 Singleton 或 Session 对象中是否更有意义?两者有什么区别?
将数据存储为对象引用还是将其分解为值类型对象(整数和字符串)更好?
【问题讨论】:
标签: c# asp.net asp.net-mvc design-patterns
我有一个 Web 应用程序,我想从数据库中提取用户设置并将它们存储起来以供全局访问。将数据存储在 Singleton 或 Session 对象中是否更有意义?两者有什么区别?
将数据存储为对象引用还是将其分解为值类型对象(整数和字符串)更好?
【问题讨论】:
标签: c# asp.net asp.net-mvc design-patterns
会话。这就是它的用途。会话存储在全局缓存中(基本上是单例),由会话 ID 键入。这样,您只能获得感兴趣会话的数据。使用单例基本上会复制全局缓存,您必须重新发明机制以独立检索每个会话的数据。
继续并存储对象。让 Session 担心将其序列化为可以恢复的东西。但是,请注意您在 Session 中放入的内容。您不想在那里存储太多数据,否则会占用大量内存(假设内存缓存)。
【讨论】:
如果这些设置将用于站点的所有用户,请将它们放在单例或应用程序缓存中。如果它们特定于每个用户,请将它们放入会话中。
添加到应用程序或会话缓存时使用对象引用 - 我相信值类型将被装箱,因此它们看起来像缓存中的对象。如果你使用单例,它可以是任何一种方式。
【讨论】:
当然是会话对象。
单例存在于进程级别。这意味着,如果您有 20 个用户在任何给定时刻访问您的站点,那么他们使用的是同一个单例对象。如果您不经常进行 Web 开发,就很难习惯这个概念。
会话存在于用户级别。这意味着您可以按用户而不是按进程存储数据。
【讨论】:
Singleton 的一个很好的例子。任何适用于网站所有用户的轻量级键值对都可以存储在其中。这些键值对将在 Web 调用中保持可访问性。对于重量级或资源密集型对象,应考虑改用cache。
这是从一个旧文档中获取的,但它仍然非常有效并且很有效...我将把链接内容放在这里,特别是因为它是一个可能会消失的旧链接。 Taken from here.
背景
ASP.Net 中的 Session 对象可用于存储特定于站点的单个用户的信息。 Session 由键名索引,当以这种方式直接使用时,可能会导致大量单独的会话名称。另一种方法是创建一个单例对象来对相关项目进行分组并使用给定的键名存储该对象。 “单例”是一种常见的设计模式,它指定如何确保在任何时候都只存在一个类的单个实例。
单例会话对象的优点
单例会话对象的缺点
更难查看会话中单个项目的数量 ASP.Net Trace 结果不显示对象内的值 使用进程外会话状态存储时性能下降(影响序列化)
实施
第一个实现步骤是创建一个类文件,该文件表示应一起存储在单个对象中的项目的逻辑分组。以下是演示该技术的示例类:
public class singleton
{
//Name that will be used as key for Session object
private const string SESSION_SINGLETON = "SINGLETON";
//Variables to store the data (used to be individual
// session key/value pairs)
string lastName = "";
string firstName = "";
public string LastName
{
get
{
return lastName;
}
set
{
lastName = value;
}
}
public string FirstName
{
get
{
return firstName;
}
set
{
firstName = value;
}
}
//Private constructor so cannot create an instance
// without using the correct method. This is
// this is critical to properly implementing
// as a singleton object, objects of this
// class cannot be created from outside this
// class
private singleton()
{
}
// Create as a static method so this can be called using
// just the class name (no object instance is required).
// It simplifies other code because it will always return
// the single instance of this class, either newly created
// or from the session
public static singleton GetCurrentSingleton()
{
singleton oSingleton;
if (null == System.Web.HttpContext.Current.Session[SESSION_SINGLETON])
{
//No current session object exists, use private constructor to
// create an instance, place it into the session
oSingleton = new singleton();
System.Web.HttpContext.Current.Session[SESSION_SINGLETON] = oSingleton;
}
else
{
//Retrieve the already instance that was already created
oSingleton = (singleton)System.Web.HttpContext.Current.Session[SESSION_SINGLETON];
}
//Return the single instance of this class that was stored in the session
return oSingleton;
}
}
想要使用此对象的页面只需执行以下操作:
singleton oSingleton = singleton.GetCurrentSingleton();
oSingleton.FirstName = "Robert";
oSingleton.LastName = "Boedigheimer";
通常,这种技术会在给定的类中存储更多变量,或者将用于执行某个过程的一系列网页。将它用于网站上的进程的另一个优点是,可以通过简单地删除对单例对象的引用来清除会话变量所需的所有内存。该类可以实现客户端可以用来清除引用的方法,当类提供清除方法时,可以将其命名为 Dispose() 以遵循典型的 .Net 模式:
public static void Dispose()
{
//Cleanup this object so that GC can reclaim space
System.Web.HttpContext.Current.Session.Remove(SESSION_SINGLETON);
}
结论
使用存储在 Session 对象中的单例对象而不是使用单独的会话键来存储信息有很多优点。它对于在整个会话中都存在的对象(分组逻辑项、影响分析、智能感知等)非常有用,特别是对于实际上只需要在网站上一段时间直到用户完成特定操作的对象进程(当进程完成但会话将继续时更容易识别变量的滥用并节省资源)。
【讨论】:
有时我喜欢下面的方法。它解决了魔术字符串和未设置会话变量的问题。它还在会话级别而不是应用程序级别运行单例。
public static SessionHandler GetInstance()
{
if (HttpContext.Current.Session["SessionHandler"] == null)
{
HttpContext.Current.Session["SessionHandler"] = new SessionHandler();
}
return (SessionHandler)HttpContext.Current.Session["SessionHandler"];
}
然后将其用作普通的单例。放入你需要的变量。
【讨论】: