ASP.NET 5(核心):如何在会话缓存(ISession)中存储对象?

ASP.NET 5 (Core): How to store objects in session-cache (ISession)?

我正在编写一个 ASP.NET 5 MVC 6(核心)应用程序。现在我到了需要在会话缓存中存储(设置和获取)对象的地步(ISession)。

如您所知,ISessionSet 方法需要一个 byte-arrayGet 方法 returns 一个。

在非核心应用程序中,我会使用 BinaryFormatter 来转换我的对象。但是我怎样才能在核心应用程序中做到这一点?

我会将对象序列化为 JSON 并使用 ISession 上的扩展方法将它们保存为 string

// Save
var key = "my-key";
var str = JsonConvert.SerializeObject(obj);
context.Session.SetString(key, str);

// Retrieve
var str = context.Session.GetString(key);
var obj = JsonConvert.DeserializeObject<MyType>(str);

ISession 上的扩展方法在 Microsoft.AspNet(Core).Http 命名空间中定义。

这是一个常青树 post 并且问题仍然很新鲜,即使 Microsoft 推荐序列化以将对象存储在会话中 - 这不是正确的解决方案,除非您的对象是只读的,我有一个解释所有场景的博客 here and i have even pointed out the issues in GitHub of Asp.Net Core in issue id 18159

问题概要在这里:

一个。序列化与对象不同,它确实有助于分布式服务器场景,但它带有一个 警告 微软没有强调 - 只有当对象是用来读取的,而不是用来写回的。

乙。如果您在会话中寻找读写对象,每次更改反序列化后从会话中读取的对象时 - 它需要通过调用序列化再次写回会话 - 仅此一项就会导致多种复杂性因为您将需要跟踪更改 - 或者在任何 属性 中的每次更改后继续写回会话。在对服务器的一次请求中,您将遇到多次写回对象直到发送回响应的场景。

摄氏度。对于会话中的读写对象,即使在单个服务器上它也会失败,因为用户的操作可以触发对服务器的多个快速请求并且系统不会经常发现自己处于对象正在被访问的情况由一个线程序列化或反序列化并被另一个线程编辑然后写回,结果是您最终将被线程覆盖对象状态 - 即使锁定也无济于事,因为该对象不是真实对象而是一个反序列化创建的临时对象。

D.序列化复杂对象存在问题 - 它不仅会影响性能,在某些情况下甚至可能会失败 - 特别是如果你有深层嵌套的对象,有时会引用自身。

解决方案的概要在这里,完整的实现和代码在博客link:

  1. 首先将其实现为缓存对象,在 IMemoryCache 中为每个唯一会话创建一个项目。

  2. 将缓存保持在滑动过期模式,以便每次读取它时都会恢复过期时间 - 从而只要会话处于活动状态,就会将对象保留在缓存中。

  3. 仅第二点是不够的,您需要实施心跳技术 - 从 javascript 开始每 T 减去 1 分钟左右触发对会话的调用。 (无论如何,我们过去常常这样做,甚至是为了让会话保持活动状态,直到用户在浏览器上工作,所以它不会有任何不同

其他建议

一个。创建一个名为 SessionManager 的对象 - 这样所有与会话读/写相关的代码都位于一个地方。

乙。不要为会话超时保持很高的值 - 如果您正在实施心跳技术,即使 3 分钟的会话超时也足够了。