ASP.NET SessionState模式使用protobuf-net进行SQLServer序列化

时间:2011-02-12 05:52:11

标签: asp.net session session-state protocol-buffers protobuf-net

问题背景

我一直在考虑如何优化SQL服务器中会话的状态外存储,以及我遇到的一些会话:

  • 在不需要会话的页面上禁用会话状态。此外,在未写入会话的页面上使用只读。
  • 在ASP.NET 4.0中使用gzip压缩选项。
  • 尽量将会话中存储的数据量保持在最低限度。

现在,我在会话中存储了一个对象(一个名为SessionObject的类)。好消息是,它是完全可序列化的。

使用protobuf-net优化

  

我认为可能是优化会话存储的一种好方法是使用协议缓冲区(protobuf-net)序列化/反序列化而不是标准的BinaryFormatter。我知道我的所有对象都可以继承ISerializable,但我不想创建DTO,或者使用序列化/反序列化逻辑来混乱我的Domain层。

     

使用带有会话状态SQL服务器模式的protobuf-net的任何建议都会很棒!

1 个答案:

答案 0 :(得分:5)

如果现有会话状态代码使用BinaryFormatter,那么您可以通过实施BinaryFormatter 来使protobuf-net充当ISerializable的内部代理,从而作弊仅限您的根对象

[ProtoContract]
class SessionObject : ISerializable {
    public SessionObject() { }
    protected SessionObject(SerializationInfo info, StreamingContext context) {
        Serializer.Merge(info, this);
    }
    void ISerializable.GetObjectData(SerializationInfo info, StreamingContext context) {
        Serializer.Serialize(info, this);
    }

    [ProtoMember(1)]
    public string Foo { get; set; }
    ...
}

注意:

  • 只有root对象需要这样做;任何封装的对象将由protobuf-net
  • 自动处理
  • 它仍会为最外层对象提供类型元数据,但不多
  • 你需要相应地修饰成员(和封装类型)(这最好是每个成员明确地完成;有一个隐含的“自己搞定”模式,但如果添加新成员则这很脆弱)
  • 这将打破现有状态;改变序列化机制从根本上说是一个突破性的变化

如果您想从 root 对象中删除类型元数据,则必须实现自己的状态提供程序(我认为MSDN上有一个示例);

  • 优势:产量较小
  • 优点:无需在根对象上实现ISerializable
  • 缺点:您需要维护自己的状态提供者; p

(上述所有其他要点仍然适用)

另请注意,protobuf-net的有效性将取决于您存储的数据。它应该更小,但是如果你有很多非常大的字符串,它将不会太多更小,因为protobuf仍然使用UTF-8作为字符串。

如果你有很多字符串,你可以考虑另外使用gzip - 我为我上一个试过gzip的雇主写了一个状态提供者,并且存储了最小的(原始或gzip) - 显然有一些检查,例如:

  • 如果它小于[某个值]
  • ,请不要gzip 如果gzip超过原来的,
  • 会提前缩短gzip压缩

以上可以非常愉快地与protobuf-net一起使用组合 - 如果你正在编写状态提供者 ,你可以删除ISerializable等,以获得最佳性能。

最后一个选项,如果你真的想要,我将向[ProtoContract(..., CompressionMode = ...)]添加“压缩模式”属性;其中:

  • 仅适用于ISerializable用法(由于技术原因,更改主要布局没有意义,但这种情况会没问题)
  • 在上述序列化/反序列化过程中自动应用gzip [也许与我上面提到的相同检查]
  • 意味着您不需要添加自己的状态提供程序

然而,这是我只想申请“v2”的东西(我只是在v1中对bugfix非常野蛮,所以我可以保持理智)。

如果有兴趣,请告诉我。