C# protobuf-net:如何在用户会话中存储
我目前能够将我创建的对象存储到C# protobuf-net:如何在用户会话中存储,c#,.net,caching,protobuf-net,C#,.net,Caching,Protobuf Net,我目前能够将我创建的对象存储到HttpContext.Current.Session中,我遇到过。有没有办法通过protobuf序列化来存储我的对象 protobuf似乎想将信息存储到流中,那么我(可以吗?)是否应该将流对象存储到用户会话中?或者我应该首先将它从流转换为另一个对象类型吗?如果是这样,转换序列化对象是否会绕过使用protobuf(cpu使用率、内存使用率)的最初目的?以前有人这样做过吗 我的目标是使用protobuf作为压缩层,将信息存储到用户会话中。是否有更好的方法(更小的尺寸、
HttpContext.Current.Session
中,我遇到过。有没有办法通过protobuf序列化来存储我的对象
protobuf似乎想将信息存储到流中
,那么我(可以吗?)是否应该将流
对象存储到用户会话中?或者我应该首先将它从流
转换为另一个对象类型吗?如果是这样,转换序列化对象是否会绕过使用protobuf(cpu使用率、内存使用率)的最初目的?以前有人这样做过吗
我的目标是使用protobuf作为压缩层,将信息存储到用户会话中。是否有更好的方法(更小的尺寸、更快的压缩、更容易维护、更小的实现开销)来完成此任务,或者protobuf是完成此任务的正确工具
更新 我正在使用这个类对象
[Serializable]
public class DynamicMenuCache
{
public System.DateTime lastUpdated { get; set; }
public MenuList menu { get; set; }
}
这个类是MenuList类的包装器,它(基本上)是一个包含内置类型(字符串、int)的列表列表。我已经创建了包装器来将时间戳与我的对象关联起来
如果会话缓存未命中(会话密钥为null或session.lastUpdated大于全局存储的时间),我将执行常规数据库查找(MSSQL),创建MenuList
对象,并将其存储到会话中,如下所示
HttpContext.Current.Session.Add("DynamicMenu" + MenuType, new DynamicMenuCache()
{
lastUpdated = System.DateTime.Now,
menu = Menu
});
目前我们的会话存储在内存中,但将来可能会转移到DB会话存储
我们的会话使用量相当大,因为我们在其中存储了大量大型对象(尽管我希望在将来的某个时候清理会话中存储的内容)
例如,我们将每个用户的权限集存储到他们的会话存储中,以避免数据库命中。当前有许多权限和权限存储结构被存储到会话中
此时,我只是查看可用的选项,因为我希望将来更智能、更严格地使用会话缓存
如果您还需要什么,请告诉我。请注意,这里使用protobuf net主要是在您希望在某个时候迁移到持久状态提供程序时才有意义 首先,由于您目前正在内存中使用(因此类型不是序列化的,AFAIK),关于将会话更改为使用任何类型的基于序列化的提供程序的注意事项如下:
- 提供程序必须可以序列化这些类型(听起来很明显,但如果有循环图等,这会产生特别的影响)
- 因为数据是序列化的,所以语义不同;每次都会得到一个副本,这意味着在请求过程中所做的任何更改都会丢失—只要您确保再次显式地重新存储数据,并且可以避免一些线程问题—这是双刃剑
- 内置状态机制通常以单个操作的形式检索会话-如果(如您所述)有一些大对象在其中,这可能是一个问题;与protobuf net无关,但有一次我被叫去调查一台正在消亡的服务器,结果是一个多MB的对象,它正在杀死系统,因为每一个请求(即使不使用该数据块的请求)都会导致这个巨大的对象通过网络传输(双向)
BinaryFormatter
编写的,因此它假定对象可以反序列化,而无需任何额外的上下文。然而,protobuf net(就像XmlSerializer
,DataContractSerializer
和JavaScriptSerializer
)并没有绑定到任何特定的类型系统-它采用的方法是“你告诉我你想填充什么类型,我会担心数据”。这实际上是一件非常好的事情,正如我在发布新版本时看到的那样,web服务器在发布新版本时被BinaryFormatter杀死了,因为有些人甚至胆敢碰一碰与持久会话中存储的对象相关的类型BinaryFormatter
不喜欢这样;特别是当您(喘息)重命名类型,或(震惊)将某个字段+属性转换为自动实现的属性时。提示:谷歌设计protobuf就是为了避免这些问题
然而!这确实意味着与标准会话状态模型一起使用并不十分方便。我以前实现过将类型名编码到流中的系统(例如,我为protobuf net编写了一个enyim/memcached转码器),但是。。。它不漂亮。在我看来,更好的方法是将知道数据是什么的负担转移给调用者。我是说,真的。。。调用者应该知道他们在任何给定键中期望的数据类型,对吗
一种方法是存储一个字节[]
。几乎任何状态实现都可以处理BLOB。如果它不能处理,只需使用Convert.ToBase64String
/Convert.FromBase64String
来存储字符串
-任何不处理字符串的实现都需要射击!要与流一起使用,可以执行以下操作(此处为伪代码):
publicstatict GetFromState(字符串键){
byte[]blob={标准状态提供程序按键获取}
使用(var ms=新内存流(blob)){
返回序列化程序。反序列化(ms);
}
}
(与添加类似)
请注意,protobuf net与BinaryFormatter不同-它们对合理的内容有不同的期望,例如默认情况下protobuf net期望知道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);
}
}