我会尽力提供我能提供的信息,我不完全确定在理解这个问题时会有什么帮助。
我注意到我在代码上有一些奇怪的行为,我认为它应该在功能上相同。我从Session中提取数据,因为它比每次访问我们的数据库都快,但每当我保存到Session I时也保存到数据库(我可以确认这是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;
}
现在,这里的事情变得非常奇怪。以下代码将上面的“Bad”代码转换为“Good”代码。
//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上的对象看起来是相同的。为什么会这样?答案 0 :(得分: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);