繁体   English   中英

在asp.net会话中存储不同的数据类型

[英]Storing different datatypes in the asp.net session

与同事聊天后,我很想知道是否有人进行过任何研究/测试,以了解在asp.net会话中最有效和推荐的数据存储方式。

我最近偶然发现了一个问题: 如何从ASP.NET中的任何类访问会话变量? 并开始使用该技术(创建我自己的会话类使我具有智能感知的优势,并避免了从会话中检索数据时需要显式强制转换)。

但是,已经建议将对象中的数据序列化为字符串然后存储...在检索时将其反序列化,这可能不是很有效。

例如...如果我想加载用户的当前权限并将其存储在会话中, 我的会话对象中可能有一个属性定义为List<int> user_permissions然后在每个页面上都可以设置if (session_class.user_permissions.contains(7))

另外,我可以将字符串直接存储在会话中,例如: HttpContext.Current.Session["user_permissions"] = "[1][4][8][12]"然后在每一页上我都可以检查HttpContext.Current.Session["user_permissions"].contains("[7]")

哪个选项更有效并且可以量化?

第一件事是确定什么ASP.NET可以开箱即用地进行序列化。 由于可以使用ASP.NET参考源,因此我们可以将状态序列化深入到此类: AltSerialization

它显示了以下本机支持的类型:

String
Int32
Boolean
DateTime
Decimal
Byte
Char
Single
Double
SByte
Int16
Int64
UInt16
UInt32
UInt64
TimeSpan
Guid
IntPtr
UIntPtr
Null // not really a type :-)

对于所有其他类型,系统使用BinaryFormatter ,它是一个公共.NET类。 BinaryFormatter非常易于使用,默认情况下它知道许多类,因此您可以进行简单的基准测试,比较BinaryFormatter将产生的结果与“手动”产生的结果。

通常,您将始终能够击败BinaryFormatter的性能,因为您可以更好地了解数据,但这意味着您必须编写其他序列化/反序列化代码。 您还可以创建自定义类并实现ISerializable

最后一点,如果您查看AltSerialization源代码,将会看到以下内容:

internal static void WriteValueToStream(Object value, BinaryWriter writer)
{
    if (known type) { ... }
    else
    {
        ...
        var formatter = new BinaryFormatter();
        if (SessionStateUtility.SerializationSurrogateSelector != null)
        {
            formatter.SurrogateSelector = SessionStateUtility.SerializationSurrogateSelector;
        }

        formatter.Serialize(writer.BaseStream, value);
    }
}

这意味着您可以在全局位置实现全局挂钩以处理特定类型,这对于工程设计或进行基准测试很有用(可以启用或禁用它)。 它可能比创建可序列化的自定义类更好。

假设您仅在单台计算机上托管(因此不需要将会话状态序列化到通用存储库),则可以使用通用MemoryCache将会话数据托管在内存中,并以唯一的会话ID作为关键字。

public class SessionData
{
    private static readonly MemoryCache Cache = new MemoryCache("SessionData");
    private static readonly CacheItemPolicy Policy = new CacheItemPolicy {SlidingExpiration = new TimeSpan(0, 30, 0)};

    public static SessionData Get(string sessionId)
    {
        if (Cache.Contains(sessionId))
            return Cache[sessionId] as SessionData;

        var item = new SessionData {SessionId = sessionId};
        Cache.Add(sessionId, item, Policy);
        return item;
    }

    public string SessionId { get; set; }
    public string Foo { get; set; }
    public int Bar { get; set; }
}

使用示例:

var item = SessionData.Get(this.Session.SessionID);
item.Foo = "Hello";
item.Bar = 123;

会话数据以30分钟的滑动到期时间保存在内存中-每次访问时,都会重置30分钟的超时时间。 这样,您就不会因为会话过期而导致内存膨胀。 让它与您当前的实现相反,看看它如何堆叠。

我在您的帖子中发现了两个问题。

1.在asp.net会话中存储不同的数据类型

您可能知道,有三种将Session保留在ASP.NET中的模式,如下所示: InProcStateServerSqlServer

InProc模式下,您可以为会话的值设置任何对象而无需序列化,因为会话和Web在同一进程中运行。

但是以其他方式,如果会话的值不是结构,则必须对其进行序列化。 SateServerSqlServer在独立的进程上运行(可能在独立的服务器上),因此,在设置会话时,会话的值将被序列化并保留在另一个进程上。

2.哪个选项会更有效,是否可以在List.contains()String.contains()进行量化?

如果您的情况下没有大量数据,那么它们并没有太大的区别。每个都有使用循环。 如果你想获得良好的有效的contains ,你可以尝试HashSet

问题实际上是方法的性能有多重要,而拥有可维护和可读的代码库又有多重要呢?

这也将对您用来序列化和反序列化数据的框架有所不同,可能值得对其进行一些初步的速度测试。 如果您可以在一秒钟内处理四方请求,那可能就可以了。

您的问题明确询问“哪个选项会更有效并且有可能量化?” 是。 绝对。 只需启动一个StopWatch (请参阅System.Diagnostics我相信是这样),然后使用一些测试数据多次调用该方法,然后检查秒表的时间即可。

ps您的问题表明有关此Session班级到底需要如何表现的讨论...根据我的经验,在Web应用程序中,(反)序列化并不是真正的主要问题。 是数据库瓶颈和其他长时间运行的进程使服务器运行缓慢。 如果由于参数“服务器已经很慢,所以这只是额外的问题”而被问到此问题,然后告诉他们解决其他问题,这就像在2时责怪稻草折断骆驼的背吨的砖头确实做到了。 只是预感:P

我认为我们已经提出了确定存储对象(尤其是使用自定义类包装器技术, 如何从ASP.NET中的任何类访问会话变量? )并不是最好的方法,这似乎是一个有效的理由。 据我们了解,这会将类的所有属性(字段)存储在内存中,即使那些是空的。

public class my_session {
 public int iUserID;
 public string sUserName;
 public List<int> lsUSerPermissions;
 public List<TestStatus> lsTestStatuses;
 public int iSomethingElse;
 public bool bSomething;
}

即使我们不会为所有会话填充/设置所有属性,但每个会话都将包含所有属性(并消耗关联的内存)。 最初,我虽然有点奇怪,但现在我明白了它的道理,因此,如果/当您设置每个属性时,内存可用,并且不必销毁该对象并在其他地方重新创建。

如果直接分配,则只需为需要存储的属性创建会话变量。

因此,既然我们已经决定将它们单独存储;

Session["iUserID"] = 1;
Session["sUserName"] = "Lee";

我们如何处理“必须”存储的对象? 似乎每个对象都需要单独查看。 string sUserPermissions = "[ViewUser][CreateUser][EditUser]"占用更少的内存,然后List<string> lsUserPermissions = new List<string>() { "[ViewUser]", "[CreateUser]", "[EditUser]" } ,是否需要序列化/反序列化更快?

仍然需要大量的研究。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM