使用包含“/”的字符串序列化对象时出现问题
Problem when serializing objects with strings that contain "/"
我正在使用 DataContractJsonSerializer
来序列化一个对象,为此我正在使用以下函数:
public static string Serialize<T>(T obj)
{
string returnVal = "";
try
{
DataContractJsonSerializer serializer = new DataContractJsonSerializer(obj.GetType());
using (MemoryStream ms = new MemoryStream())
{
serializer.WriteObject(ms, obj);
returnVal = Encoding.UTF8.GetString(ms.ToArray());
}
}
catch (Exception /*exception*/)
{
returnVal = "";
//log error
}
return returnVal;
}
现在,这个功能工作得很好...除了以下情况(我不确定是否要改变它,因为我不知道它会怎样影响我的其余代码)。
不好用的情况
假设我有 obj(参数)一个对象,例如:
[DataContract()]
public class theObject
{
[DataMember()]
public string image;
}
其中image
保存了一个BMP文件的Base64值。
这是一个很大的值,但例如它的开头为:"Qk1W/QAAAAAAADYAAAAoAAAAawAAAMgAAAABABgAAAAAACD9AADEDgAAxA4AAAAAAAAAAAAA////////////////////////////////////7+/...."
所以你看到它包含很多/
s。
因此,当我将此对象传递给 Serialize
时,它会在 ms 中 WriteObject
然后将其放入一个数组,最终将转到 returnVal
.
现在让我们检查一下returnVal
。它采用 JSON 格式(正确),当您将其可视化为 JSON 时,它将显示:
image:"Qk1W/QAAAAAAADYAAAAoAAAAawAAAMgAAAABABgAAAAAACD9AADEDgAAxA4AAAAAAAAAAAAA////////////////////////////////////7+/...."
但是!当您将其可视化为文本时,它会显示:
"image":"Qk1W\/QAAAAAAADYAAAAoAAAAawAAAMgAAAABABgAAAAAACD9AADEDgAAxA4AAAAAAAAAAAAA\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/7+\/..."
你看到了吗?它在每个 /
之前插入了 \
并且它有很大的不同。
所以我的问题是:
- 为什么可视化为 JSON 和可视化为文本显示不同的东西?
- 如何在序列化后获得正确的值(没有
/
s)
编辑:
虽然可以说\/
和/
是一样的,但是结果却不是。稍后使用 JSON 将它扔到 Web Api 使用
byte[] bytes = Encoding.UTF8.GetBytes(json);
ByteArrayContent byteContent = new ByteArrayContent(bytes);
byteContent.Headers.ContentType = new MediaTypeWithQualityHeaderValue(content);
添加了 \
的版本导致 bytes
有 115442 字节,而仅使用 /
的版本导致 bytes
有 86535 字节。因此结果大不相同。
那么,如果不添加 \
s,我怎样才能得到结果呢?
DataContractJsonSerializer
的标准行为是转义字符串中的 /
个字符,使它们成为 JSON 中的 \/
。当 JSON 被反序列化回一个对象时,\/
转义序列将变回 /
因此没有数据丢失或损坏。 (试试看。)但是它确实会导致更大的 JSON 大小(以字节为单位)。如果这真的是您担心的问题,您可以采取一些措施来解决它:
方法一
序列化后,您可以立即使用 string.Replace()
删除所有直接出现在斜线之前的反斜线。您可以通过更改此行在 Serialize
方法中正确执行此操作:
returnVal = Encoding.UTF8.GetString(ms.ToArray());
对此:
returnVal = Encoding.UTF8.GetString(ms.ToArray()).Replace("\/", "/");
因为/
在JSON中没有特殊意义,实际上没有必要用\
转义它们,尽管这样做是允许的。 (参见第 5 页的 JSON specification.) DataContractJsonSerializer
will still deserialize the JSON just fine even when slashes are not escaped. (Try it yourself and see. I'd make a fiddle for this, but .NET Fiddle 不支持 DataContractJsonSerializer
)。
方法二(推荐)
切换到更好的 JSON 序列化程序,例如 Json.Net which does not escape the slashes in the first place. You can simplify your code and replace your entire Serialize
method with JsonConvert.SerializeObject()
Fiddle: https://dotnetfiddle.net/MQKXSD
我正在使用 DataContractJsonSerializer
来序列化一个对象,为此我正在使用以下函数:
public static string Serialize<T>(T obj)
{
string returnVal = "";
try
{
DataContractJsonSerializer serializer = new DataContractJsonSerializer(obj.GetType());
using (MemoryStream ms = new MemoryStream())
{
serializer.WriteObject(ms, obj);
returnVal = Encoding.UTF8.GetString(ms.ToArray());
}
}
catch (Exception /*exception*/)
{
returnVal = "";
//log error
}
return returnVal;
}
现在,这个功能工作得很好...除了以下情况(我不确定是否要改变它,因为我不知道它会怎样影响我的其余代码)。
不好用的情况
假设我有 obj(参数)一个对象,例如:
[DataContract()]
public class theObject
{
[DataMember()]
public string image;
}
其中image
保存了一个BMP文件的Base64值。
这是一个很大的值,但例如它的开头为:"Qk1W/QAAAAAAADYAAAAoAAAAawAAAMgAAAABABgAAAAAACD9AADEDgAAxA4AAAAAAAAAAAAA////////////////////////////////////7+/...."
所以你看到它包含很多/
s。
因此,当我将此对象传递给 Serialize
时,它会在 ms 中 WriteObject
然后将其放入一个数组,最终将转到 returnVal
.
现在让我们检查一下returnVal
。它采用 JSON 格式(正确),当您将其可视化为 JSON 时,它将显示:
image:"Qk1W/QAAAAAAADYAAAAoAAAAawAAAMgAAAABABgAAAAAACD9AADEDgAAxA4AAAAAAAAAAAAA////////////////////////////////////7+/...."
但是!当您将其可视化为文本时,它会显示:
"image":"Qk1W\/QAAAAAAADYAAAAoAAAAawAAAMgAAAABABgAAAAAACD9AADEDgAAxA4AAAAAAAAAAAAA\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/7+\/..."
你看到了吗?它在每个 /
之前插入了 \
并且它有很大的不同。
所以我的问题是:
- 为什么可视化为 JSON 和可视化为文本显示不同的东西?
- 如何在序列化后获得正确的值(没有
/
s)
编辑:
虽然可以说\/
和/
是一样的,但是结果却不是。稍后使用 JSON 将它扔到 Web Api 使用
byte[] bytes = Encoding.UTF8.GetBytes(json);
ByteArrayContent byteContent = new ByteArrayContent(bytes);
byteContent.Headers.ContentType = new MediaTypeWithQualityHeaderValue(content);
添加了 \
的版本导致 bytes
有 115442 字节,而仅使用 /
的版本导致 bytes
有 86535 字节。因此结果大不相同。
那么,如果不添加 \
s,我怎样才能得到结果呢?
DataContractJsonSerializer
的标准行为是转义字符串中的 /
个字符,使它们成为 JSON 中的 \/
。当 JSON 被反序列化回一个对象时,\/
转义序列将变回 /
因此没有数据丢失或损坏。 (试试看。)但是它确实会导致更大的 JSON 大小(以字节为单位)。如果这真的是您担心的问题,您可以采取一些措施来解决它:
方法一
序列化后,您可以立即使用 string.Replace()
删除所有直接出现在斜线之前的反斜线。您可以通过更改此行在 Serialize
方法中正确执行此操作:
returnVal = Encoding.UTF8.GetString(ms.ToArray());
对此:
returnVal = Encoding.UTF8.GetString(ms.ToArray()).Replace("\/", "/");
因为/
在JSON中没有特殊意义,实际上没有必要用\
转义它们,尽管这样做是允许的。 (参见第 5 页的 JSON specification.) DataContractJsonSerializer
will still deserialize the JSON just fine even when slashes are not escaped. (Try it yourself and see. I'd make a fiddle for this, but .NET Fiddle 不支持 DataContractJsonSerializer
)。
方法二(推荐)
切换到更好的 JSON 序列化程序,例如 Json.Net which does not escape the slashes in the first place. You can simplify your code and replace your entire Serialize
method with JsonConvert.SerializeObject()
Fiddle: https://dotnetfiddle.net/MQKXSD