我目前能够将我创建的对象存储到HttpContext.Current.Session
中,并且我遇到protobuf-net。有没有办法通过使用protobuf序列化来存储我的对象?
看起来protobuf希望将信息存储到Stream
中,所以我(可以吗?)将Stream
对象存储到用户会话中吗?或者我应该先将它从Stream
转换为另一种对象类型?如果是这样,转换序列化对象是否会绕过使用protobuf(cpu使用,内存使用)的最初目的?有人曾经这样做过吗?
我的目标是使用protobuf作为压缩层,将信息存储到用户会话中。这样做有更好的方法(更小的尺寸,更快的压缩,更容易维护,更小的实现开销),还是protobuf是这项任务的正确工具?
更新
我正在使用这个类对象
[Serializable]
public class DynamicMenuCache
{
public System.DateTime lastUpdated { get; set; }
public MenuList menu { get; set; }
}
这个类是我的MenuList类的包装器,它基本上是一个包含内置类型(字符串,整数)的列表。我已经创建了一个包装器来将时间戳与我的对象相关联。
如果我有会话缓存未命中(会话密钥为空或session.lastUpdated大于全局存储时间),我执行正常的数据库查找(MSSQL),创建MenuList
对象并存储它进入会议,就像这样
HttpContext.Current.Session.Add("DynamicMenu" + MenuType, new DynamicMenuCache()
{
lastUpdated = System.DateTime.Now,
menu = Menu
});
目前我们的会话存储在内存中,但我们将来可能会迁移到数据库会话存储区。
我们的会话使用非常繁重,因为我们会在其中存储大量大型对象(尽管我希望在将来的某个时间点清理我们在会话中存储的内容)。
例如,我们将每个用户的权限集存储到他们的会话存储中以避免数据库命中。有许多权限和权限存储结构当前存储在会话中。
此时我只是查看可用的选项,因为我希望将来能够更加智能和严格地使用会话缓存。
如果您还有其他需要,请告诉我。
答案 0 :(得分:4)
请注意,在这里使用protobuf-net 主要是只有在你想要在某个时候转移到持久状态提供者时才有意义。
首先,由于您目前正在使用内存(因此类型未被序列化,AFAIK),有关更改会话以使用任何类型的基于序列化的提供程序的注意事项:
在很多方面,我实际上根本不是标准会话状态模型的粉丝 - 这是在我讨论它与protobuf-net的关系之前!
protobuf-net最终是一个序列化层。标准会话状态实现的另一个特性是因为它最初是用BinaryFormatter
编写的,它假定对象可以在没有任何额外上下文的情况下反序列化。然而,protobuf-net(就像XmlSerializer
,DataContractSerializer
和JavaScriptSerializer
)没有绑定任何特定的类型系统 - 它采取的方法"你告诉我你是什么类型的希望我填充,我会担心数据"。这实际上是一个非常好的事情,因为我发现在发布新版本时被BinaryFormatter
杀死的网络服务器,因为有人拥有 audacity 触摸甚至轻微与持久化会话中存储的对象相关的其中一种类型。 BinaryFormatter
不喜欢这样; 尤其是如果你(喘气)重命名一个类型,或者( shock )从一个字段+属性到一个自动实现的属性。提示:这些是谷歌设计的protobuf要避免的问题。
然而!这确实意味着它不会非常方便地与标准会话状态模型一起使用。我之前已经实现了将类型名称编码到流中的系统(例如,我为protobuf-net编写了一个enyim / memcached转码器),但是......它并不漂亮。 IMO,更好的方法是将知道数据的负担转移给调用者。我的意思是,真的......调用者应该知道他们在任何给定密钥中期望的数据类型,对吗?
执行此操作的一种方法是存储byte[]
。几乎任何状态实现都可以处理BLOB。如果它无法处理,只需使用Convert.ToBase64String
/ Convert.FromBase64String
来存储string
- 任何不处理string
的实施都需要拍摄!要与流一起使用,您可以执行类似的操作(此处为伪代码):
public static T GetFromState<T>(string key) {
byte[] blob = {standard state provider get by key}
using(var ms = new MemoryStream(blob)) {
return Serializer.Deserialize<T>(ms);
}
}
(和类似的添加)
请注意,protobuf-net与BinaryFormatter
不同 - 他们对合理的内容有不同的期望,例如默认情况下 protobuf-net希望提前知道 数据的样子(即public object Value {get;set;}
会很痛苦),并且不会处理循环图(尽管有适当的条款来支持这两种情况)。一般来说,如果您可以使用XmlSerializer
或DataContractSerializer
等序列化数据,则可以使用protobuf-net轻松序列化; protobuf-net也支持其他方案,但没有公开保证序列化每个任意数据模型。根据DTO进行思考将使生活更轻松。在大多数情况下,这并不是所有的问题,因为大多数人都有合理的数据。有些人没有有合理的数据,我只想适当地设定期望!
就个人而言,正如我所说 - 尤其是当大型对象可以参与其中时,我根本不是内置会话状态模式的粉丝。我可能建议的是使用单独的每个密钥数据存储(意思是:每个用户每个密钥一个记录,而不是每个用户只有一个记录) - 可能仅适用于较大的对象,也许适用于所有内容。这可能是SQL Server,或类似redis / memcached。如果您使用期望使用会话状态的第三方控件(webforms等),这显然有点痛苦,但如果您在代码中手动使用状态,则实现起来非常简单。 FWIW,BookSleeve与redis相结合,可以很好地处理这类事情,并提供对基于byte[]
的存储的良好访问。从byte[]
开始,您可以反序列化对象,如上所示。
无论如何 - 我会在那里停下来,以防我离主题太远;随时回答任何问题,但执行摘要:
BinaryFormatter
byte[]