【问题标题】:How to convert session data to SessionStateStoreData type in custom session state provider如何在自定义会话状态提供程序中将会话数据转换为 SessionStateStoreData 类型
【发布时间】:2015-06-04 09:59:25
【问题描述】:

我在我的 Web 应用程序中使用 自定义会话提供程序,它继承了 SessionStateStoreProviderBase 和覆盖方法。用于从会话中获取数据的方法的返回类型为 SessionStateStoreData

目前二进制序列化被用于序列化和反序列化数据。我想使用 json 序列化 而不是二进制,但不确定如何将会话数据(json 序列化后的字符串类型)转换为 SessionStateStoreData 类型。 SessionStateStoreData 类型的构造函数使用 SessionStateItemCollection 类型的对象,该对象可以从 sessionstateitemcollection 的反序列化方法中获取,该方法只接受二进制流作为输入。

var ms = _serializedSessionData == null
            ? new MemoryStream()
            : new MemoryStream(_serializedSessionData);

        var sessionItems = new SessionStateItemCollection();

        if (ms.Length > 0)
        {
            var reader = new BinaryReader(ms);
            sessionItems = SessionStateItemCollection.Deserialize(reader);
        }

return new SessionStateStoreData(sessionItems,
          SessionStateUtility.GetSessionStaticObjects(context),
          _timeout);

我附上了用于二进制反序列化的代码。 json序列化对象如何做同样的事情?

【问题讨论】:

  • 您可以尝试将json 字符串转换为MemoryStream
  • 是的,但在这种情况下 sessionitems 将是 json 序列化字符串,而不是存储在 session 中的实际对象。
  • SessionStateItemCollection.Deserialize 只接受BinaryReader
  • 是的,这就是问题所在。我在问是否可以使用任何替代品。
  • 您真的需要SessionStateItemCollection,还是实现ISessionStateItemCollection 的集合就足够了? The former 有很多专门用于增量二进制反序列化的逻辑。

标签: c# asp.net json session serialization


【解决方案1】:

SessionStateItemCollection 非常接近Dictionary<string, object>,因此您可以将其序列化。但是,您需要考虑null 密钥的可能性。 SessionStateItemCollection 允许 null 键,但 Dictionary<string, object> 会在空键上抛出异常。

由于SessionStateItemCollection 中的值是无类型的,您还需要一个支持序列化任意类型的类型信息的 JSON 序列化程序。 Json.NET 可以做到这一点。 JavaScriptSerializer 也可以。 DataContractJsonSerializer 可能合适,因为您必须提前知道所有可能的类型并将它们作为已知类型传递给constructor

对于剩下的答案,我假设您选择了 Json.NET。

首先,定义如下中间类进行序列化:

public class StringDictionaryWrapper
{
    public StringDictionaryWrapper()
    {
        Items = new Dictionary<string, object>();
    }

    // Holds the value of the item with a null key, if any.
    [JsonProperty(ItemTypeNameHandling = TypeNameHandling.Auto, DefaultValueHandling = DefaultValueHandling.Ignore)]
    public object NullItem { get; set; }

    [JsonProperty(ItemTypeNameHandling = TypeNameHandling.Auto)]
    public Dictionary<string, object> Items { get; set; }
}

然后,要将SessionStateItemCollection 序列化为 json 字符串,请执行以下操作:

        var dict = new StringDictionaryWrapper { Items = sessionItems.Keys.OfType<string>().ToDictionary(key => key, key => sessionItems[key]), NullItem = sessionItems[null] };
        var json = JsonConvert.SerializeObject(dict, Formatting.Indented);

JSON 看起来像:

{
  "NullItem": 1123,
  "Items": {
    "foo": {
      "$type": "Question30640792.SomeClass, Tile",
      "SomeProperty": "foo2"
    },
    "TestClass": {
      "$type": "Question30640792.TestClass, Tile",
      "A": 101,
      "B": 102
    }
  }
}

要从 json 字符串反序列化,请执行以下操作:

        var sessionItems = new SessionStateItemCollection();

        var dict = JsonConvert.DeserializeObject<StringDictionaryWrapper>(json);
        if (dict != null && dict.NullItem != null)
            sessionItems[null] = dict.NullItem;
        if (dict != null && dict.Items != null)
            foreach (var pair in dict.Items)
                sessionItems[pair.Key] = pair.Value;

请注意,这将一次反序列化所有会话状态项的整个集合,而内置的二进制序列化使用on-demand deserialization for performance reasons。因此,您可能会看到性能下降。此外,由于Dictionary&lt;TKey, TValue&gt; 是无序的,会话项目可能不会以与它们最初相同的顺序返回。如果这是个问题,您可能需要为您的会话项目集合创建类似 custom proxy wrapper 的内容。

最后,在使用TypeNameHandling 时,请注意Newtonsoft docs 的注意事项:

当您的应用程序从外部源反序列化 JSON 时,应谨慎使用 TypeNameHandling。使用 None 以外的值反序列化时,应使用自定义 SerializationBinder 验证传入类型。

关于为什么这可能是必要的讨论,请参阅TypeNameHandling caution in Newtonsoft Json

【讨论】:

    猜你喜欢
    • 2011-06-09
    • 1970-01-01
    • 2012-08-23
    • 2013-07-21
    • 2015-03-10
    • 2016-04-09
    • 2013-08-26
    • 2014-08-06
    • 1970-01-01
    相关资源
    最近更新 更多