2011-06-06 71 views
2

我会尝试提供可以提供的信息,但我不完全确定哪些信息有助于理解此问题。序列化然后反序列化对象产生与原始对象不同的结果

我注意到我在代码上有一些奇怪的行为,我认为应该在功能上相同。我从Session中提取数据的速度比每次访问数据库都要快,但是每当我保存到Session时,我也会保存到数据库(我可以确认这是100%真实的)。

我发现,在某些情况下,我在从Session中提取数据时遇到奇怪的行为,但是在从数据库中提取相同数据时我没有遇到此问题。

//Good: 
string data = DashboardDatabaseRepository.Instance.GetWebLayoutData("PaneStates"); 

if (!string.IsNullOrEmpty(data)) 
{ 
    byte[] dataAsArray = System.Convert.FromBase64String(data); 
    MemoryStream stream = new MemoryStream(dataAsArray); 
    _paneStates = serializer.Deserialize(stream) as SerializableDictionary<string, RadPaneSetting>; 
} 

//Bad: 

if (!object.Equals(DashboardSessionRepository.Instance.GetSession("PaneStates"), null)) 
{ 
    _paneStates = DashboardSessionRepository.Instance.GetSession("PaneStates") as SerializableDictionary<string, RadPaneSetting>; 
} 

现在,我知道它是什么样子 - 我在做一些奇怪的我“的getSession”在幕后,但所有我做的是这样的:

public object GetSession(string index) 
{ 
    return HttpContext.Current.Session[index]; 
} 

public void SetSession(string index, object item) 
{ 
    HttpContext.Current.Session[index] = item; 
} 

现在,这里的事情变得非常奇怪。以下代码将上面的'错误'代码转换为'好'代码。

//WorkAround - Good 
get 
{ 
    SerializableDictionary<string, RadPaneSetting> _paneStates = new SerializableDictionary<string, RadPaneSetting>(); 

    if (!object.Equals(DashboardSessionRepository.Instance.GetSession("PaneStates"), null)) 
    { 
     _paneStates = DashboardSessionRepository.Instance.GetSession("PaneStates") as SerializableDictionary<string, RadPaneSetting>; 

     System.IO.MemoryStream memoryStream = new System.IO.MemoryStream(); 
     System.Xml.Serialization.XmlSerializer xmlSerializer = new System.Xml.Serialization.XmlSerializer(_paneStates.GetType()); 
     xmlSerializer.Serialize(memoryStream, _paneStates); 
     string data = System.Convert.ToBase64String(memoryStream.ToArray()); 

     if (!string.IsNullOrEmpty(data)) 
     { 
      XmlSerializer serializer = new XmlSerializer(_paneStates.GetType()); 
      byte[] dataAsArray = System.Convert.FromBase64String(data);// System.Text.Encoding.UTF8.GetBytes(data); 
      MemoryStream stream = new MemoryStream(dataAsArray); 

      _paneStates = serializer.Deserialize(stream) as SerializableDictionary<string, RadPaneSetting>; 
     } 
     else 
     { 
      XmlSerializer serializer = new XmlSerializer(_paneStates.GetType()); 

      string data = DashboardDatabaseRepository.Instance.GetWebLayoutData("PaneStates"); 

      if (!string.IsNullOrEmpty(data)) 
      { 
       byte[] dataAsArray = System.Convert.FromBase64String(data);// System.Text.Encoding.UTF8.GetBytes(data); 
       MemoryStream stream = new MemoryStream(dataAsArray); 
       _paneStates = serializer.Deserialize(stream) as SerializableDictionary<string, RadPaneSetting>; 
      } 

      DashboardSessionRepository.Instance.SetSession("PaneStates", _paneStates); 
     } 

    return _paneStates; 
} 

我很好奇通过序列化和反序列化从Session中检索到的对象可以发生什么样的清理?有什么显而易见的,我在这里失踪?

谢谢你的时间。

编辑:我相信这两个词典有相同的数据。我在S.O上查了字典相等比较器。并使用在那里提供的代码。注意调试器如何进入if语句,但截图的LHS上的对象看起来是平等的。为什么会发生这种情况?

http://i.stack.imgur.com/ojUPm.png

+0

有什么不同* *你的数据吗?唯一跳出来的是UTF8序列化。在你的文本中有什么东西在http上下文中得到不同的编码? – 2011-06-06 22:43:06

+0

我一直在试图找到一个比较两个字典的好方法。上面的代码受到很大打击,我无法通过查看日志记录来解析差异。给我一点点尝试,找到对象的实际差异(希望我找到他们) – 2011-06-06 22:46:03

回答

3

的问题是,你使用UTF-8编码倒退。当你认为你正在解码时你正在编码,而当你认为你正在编码时正在解码。

UTF-8编码不是用来将任何二进制数据表示为字符串,而是用来表示一个字符串为二进制数据。当您采取任何二进制数据并通过Encoding.UTF8.GetString发送时,您可能会破坏数据。它将适用于任何字符编码,这些编码恰好对应于编码为UTF-8的任何字符数据,但只要您得到的字节组合不能以UTF-8编码的数据存在,该方法就无法将其转换为字符。此外,即使您可以在不丢失数据的情况下将数据转换为字符串,也不一定会在再次对字符串进行编码时提供相同的二进制结果。

您应该改用base64编码。使用Convert.ToBase64String二进制数据转换成字符串表示,并Convert.FromBase64String得到二进制数据传回:

string data = Convert.ToBase64String(memoryStream.ToArray()); 

和:

byte[] dataAsArray = Convert.FromBase64String(data); 
+0

啊,很常见:http://marcgravell.blogspot.com/2010/03/binary-data-and-strings.html – 2011-06-06 23:06:16

+0

嗨。我打算重新打开它。我实施了你的解决方案,虽然我同意这样做最好,但这不是我的问题的根源。谢谢。 – 2011-06-06 23:14:03

+0

我确定问题在于在Session中存储整个对象时持久存储了对象上的附加信息,但在序列化/反序列化时并未保留。 – 2011-06-07 18:28:38