【问题标题】:Problem when serializing objects with strings that contain "/"使用包含“/”的字符串序列化对象时出现问题
【发布时间】:2018-10-25 03:04:23
【问题描述】:

我正在使用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 时,它将在毫秒内WriteObject,然后将其放入一个数组中,最终将转到returnVal

现在让我们检查returnVal。它是 JSON 格式(正确),当您将其可视化为 JSON 时,它会显示给您:

image:"Qk1W/QAAAAAAADYAAAAoAAAAawAAAMgAAAABABgAAAAAACD9AADEDgAAxA4AAAAAAAAAAAAA////////////////////////////////////7+/...."

但是!当您将其可视化为文本时,它会向您显示:

"image":"Qk1W\/QAAAAAAADYAAAAoAAAAawAAAMgAAAABABgAAAAAACD9AADEDgAAxA4AAAAAAAAAAAAA\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/7+\/..."

你看到了吗?它在每个/ 之前插入了\,这会产生很大的不同。

所以我的问题是:

  1. 为什么将其可视化为 JSON 并将其可视化为 Text 会显示不同的内容?
  2. 序列化后如何获得正确的值(没有/s)

编辑:

虽然可以说\// 是一样的,但结果却不是。稍后使用此 JSON 将其扔到使用

的 Web Api
byte[] bytes = Encoding.UTF8.GetBytes(json);

ByteArrayContent byteContent = new ByteArrayContent(bytes);                    
byteContent.Headers.ContentType = new MediaTypeWithQualityHeaderValue(content);

添加了\ 的版本产生了一个bytes 115442 字节,而仅使用/ 的版本产生了86535 字节的bytes。因此结果大相径庭。

那么如果没有添加\s,我怎样才能得到结果呢?

【问题讨论】:

  • 你为什么用DataContractJsonSerializer而不是Json.NET?微软推荐后者,除非有一些真正情有可原的情况。
  • 2. incorrect 什么都没有。您只想显示 json without 转义字符。有在线格式化程序可以执行此操作,但我不确定这是否是您所追求的 (freeformatter.com/json-escape.html)
  • 根据json.org//可以转义为\/,因此当你在JSON中看到\/时,这与字符/相同。
  • 是的,理论上它们是相同的,但结果却大不相同。 (见我的编辑)
  • 编辑后:json 是带有 JSON 序列化的字符串?然后当然有不同的长度(更多字符,更大长度)。当您反序列化该值时,该值应该相同。不幸的是你没有写你使用什么 JSON 序列化器(我不能帮助你,因为我不知道任何 JSON 序列化器的细节)

标签: c# json serialization datacontractjsonserializer


【解决方案1】:

DataContractJsonSerializer 的标准行为是转义字符串中的 / 字符,以便它们在 JSON 中变为 \/。当 JSON 反序列化回对象时,\/ 转义序列将转回/,因此不会丢失或损坏数据。 (试试看。)但是它确实会导致更大的 JSON 大小(以字节为单位)。如果这确实是您关心的问题,您可以采取一些措施来解决它:

方法 1

在序列化之后,您可以立即使用string.Replace() 删除所有直接出现在斜杠之前的反斜杠。您可以在 Serialize 方法中通过更改此行来执行此操作:

returnVal = Encoding.UTF8.GetString(ms.ToArray());

到这里:

returnVal = Encoding.UTF8.GetString(ms.ToArray()).Replace("\\/", "/");

因为/ 在 JSON 中没有特殊含义,实际上没有必要用\ 转义它们,尽管这样做是允许的。 (参见JSON specification 的第 5 页。)DataContractJsonSerializer 仍然可以很好地反序列化 JSON,即使斜杠没有被转义。 (你自己试试看。我会为此做一个小提琴,但.NET Fiddle 不支持DataContractJsonSerializer)。

方法 2(推荐)

切换到更好的 JSON 序列化程序,例如 Json.Net,它首先不会转义斜杠。您可以简化代码并将整个 Serialize 方法替换为 JsonConvert.SerializeObject()

小提琴:https://dotnetfiddle.net/MQKXSD

【讨论】:

    猜你喜欢
    • 2012-05-16
    • 1970-01-01
    • 1970-01-01
    • 2011-04-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多