编程语言
首页 > 编程语言> > C#-protobuf-net:如何在用户会话中存储

C#-protobuf-net:如何在用户会话中存储

作者:互联网

我目前能够将我创建的对象存储到HttpContext.Current.Session中,并且遇到protobuf-net.是否可以通过使用protobuf序列化对象来存储对象?

似乎protobuf希望将信息存储到Stream中,所以我(可以吗?)应该将Stream对象存储到users会话中吗?还是应该先将其从Stream转换为另一种对象类型?如果是这样,转换序列化的对象是否会违反使用protobuf的原始目的(CPU使用率,内存使用率)?有人做过吗?

我的目标是使用protobuf作为将信息存储到用户会话中的压缩层.是否有更好的方法(较小的尺寸,更快的压缩,更易于维护,更小的实现开销),还是protobuf是完成此任务的正确工具?

更新资料

我正在使用此类对象

[Serializable]
public class DynamicMenuCache
{
    public System.DateTime lastUpdated { get; set; }
    public MenuList menu { get; set; }
}

此类是我的MenuList类的包装,(基本上)是一个包含内置类型(字符串,整数)的列表列表.我创建了包装器,将时间戳记与我的对象相关联.

如果我有一个会话高速缓存未命中(会话密钥为null或session.lastUpdated大于全局存储的时间),则执行常规的数据库查找(MSSQL),创建MenuList对象,然后将其存储到会话中,如下所示

HttpContext.Current.Session.Add("DynamicMenu" + MenuType, new DynamicMenuCache()
{
    lastUpdated = System.DateTime.Now,
    menu = Menu
});

当前,我们的会话存储在内存中,但是将来我们可能会转移到数据库会话存储中.

我们在会话中的使用非常繁琐,因为我们将很多大对象存储到其中(尽管我希望在将来的某个时间清理在会话中存储的内容).

例如,我们将每个用户的权限集存储到其会话存储区中,以避免数据库命中.当前有很多权限和权限存储结构存储到会话中.

在这一点上,我只是查看可用的选项,因为我希望将来可以更智能,更严格地使用会话缓存.

如果您还有其他需要,请告诉我.

解决方法:

请注意,此处的protobuf-net仅在您打算迁移到持久化状态提供程序时才有意义.

首先,由于您当前正在使用内存(因此类型不会被序列化,即AFAIK),因此,有关更改会话以使用任何类型的基于序列化的提供程序的一些说明:

>类型必须由提供者可序列化(听起来很明显,但是如果您有圆形图等,这会产生特别的影响)
>因为数据是序列化的,所以语义是不同的;您每次都会得到一个副本,这意味着您在请求期间所做的任何更改都会丢失-只要您确保再次明确地重新存储数据即可,这很好,并且可以避免一些线程问题-双刃
>内置状态机制通常将会话作为单个操作来检索-如果(如您所述)其中有一些大对象,则可能会出现问题;与protobuf-net无关,但是我曾经被要求调查一台即将死机的服务器,该服务器原来是处于杀死系统状态的多MB对象,因为每个请求(甚至是那些不使用该数据的请求)都导致这个巨大的物体要通过网络(双向)运输

在许多方面,我实际上根本不是标准会话状态模型的忠实拥护者-而且这还早于我谈到它与protobuf-net的关系之前!

protobuf-net最终是一个序列化层.标准会话状态实现的另一个功能是,因为它最初是用BinaryFormatter编写的,因此它假定可以在没有任何额外上下文的情况下反序列化对象.但是,protobuf-net(就像XmlSerializer,DataContractSerializer和JavaScriptSerializer一样)不与任何特定类型的系统绑定-它采用的方法是“您告诉我要填充的类型,我会担心数据”.这实际上是一件非常好的事,因为我看到发布新版本时Web服务器被BinaryFormatter杀死了,因为有人敢于稍微触摸碰巧与持久化会话中存储的对象有关的一种类型. BinaryFormatter不喜欢那样.尤其是当您(gasp)重命名类型,或(震惊)将字段属性从自动属性变为自动实现.提示:这些是Google设计protobuf可以避免的问题.

然而!这确实意味着与标准会话状态模型一起使用不是很方便.我已经实现了将类型名称编码到流中的系统(例如,我为protobuf-net编写了一个enyim / memcached转码器),但是…并不是很漂亮. IMO,更好的方法是将知道数据是什么的负担转移给调用方.我的意思是,真的……呼叫者应该知道他们在任何给定密钥中期望的数据类型,对吗?

一种方法是存储一个byte [].几乎任何状态实现都可以处理BLOB.如果无法处理,则只需使用Convert.ToBase64String / Convert.FromBase64String来存储字符串-任何不处理字符串的实现都需要射击!要与流一起使用,您可以执行类似操作(此处为伪代码):

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希望事先知道数据的样子(即公共对象Value {get; set;}将会很痛苦),并且不处理圆形图(尽管有规定可以支持这两种情况).作为一般经验法则:如果可以使用XmlSerializer或DataContractSerializer之类的数据来序列化数据,则可以使用protobuf-net轻松进行序列化; protobuf-net也支持其他方案,但是没有公开保证可以序列化每个任意数据模型.根据DTO进行思考将使生活更轻松.在大多数情况下,这根本不是问题,因为大多数人都有合理的数据.有些人没有合理的数据,我只想适当地设定期望值!

但是,就我个人而言,就像我说的那样-特别是当涉及大对象时,我根本不喜欢内置的会话状态模式.我可能建议使用的是单独的每个键数据存储(意味着:每个键每个用户一个记录,而不是每个用户仅一个记录)-可能只适用于较大的对象,可能适用于所有对象.这可能是SQL Server,或类似redis / memcached的东西.如果您正在使用希望使用会话状态的第三方控件(Web窗体等),这显然会有些痛苦,但是如果您在代码中手动使用状态,则实现起来非常简单. FWIW,BookSleeve与redis耦合,可很好地用于此类事情,并提供对基于byte []的存储的良好访问.从byte []中可以反序列化对象,如上所示.

无论如何-如果我走得太远,我会停在那里.随时回答任何问题,但执行摘要:

> protobuf-net可以阻止您可能在BinaryFormatter上看到的许多版本控制问题
>,但不一定是直接1:1交换,因为protobuf-net不会对“类型”信息进行编码(内置会话机制期望)
>可以使其正常工作,最常见的是使用byte []
>,但如果要存储大对象,则可能存在与会话状态想要工作方式相关的其他问题(与protobuf-net无关)
>特别是对于较大的对象,我建议您使用自己的机制(即非会话状态);键值存储系统(redis,memcached,AppFabric缓存)可以很好地完成此任务

标签:caching,protobuf-net,c,net
来源: https://codeday.me/bug/20191101/1987246.html