猿问

取消转义后如何转义嵌入的 JSON

使用 Json.NET 进行序列化时,我需要在反序列化时之前未转义后转义嵌入的 JSON。这意味着我根据这篇文章对 JSON 进行了转义。


这是我的 JSON:


{  

   "Message":null,

   "Error":false,

   "VData":{  

      "RNumber":null,

      "BRNumber":"Session1"

   },

   "onlineFields":{  

      "CCode":"Web",

      "MNumber":"15478655",

      "Product":"100",

      "JsonFile":"      {  

         \"evaluation\":{  

            \"number\":[  

               {  

                  \"@paraID\":\"1000\",

                  \"@Value\":\"\",

                  \"@label\":\"We are america\"

               },

               {  

                  \"@paraID\":\"2000\",

                  \"@Value\":\"100\",

                  \"@label\":\"We are japan\"

               },

               {  

                  \"@paraID\":\"3000\",

                  \"@Value\":\"1000\",

                  \"@label\":\"We are UK\"

               },

               {  

                  \"@paraID\":\"4000\",

                  \"@Value\":\"\",

                  \"@label\":\"We are China\"

               }

            ]

         }

      } "     

   }

}

转义后,我将上述 JSON 绑定到我的模型类。它工作正常。将 JSON 绑定到我使用以下代码的模型。


private static void showJSON(string testJson){


    Response response = JsonConvert.DeserializeObject<Response>(testJson);


    var dropdowns = response.OnlineFields.JsonFile;


    string json = JsonConvert.SerializeObject(dropdowns, Newtonsoft.Json.Formatting.Indented);


    Console.WriteLine(json);

}

将 JSON 绑定到模型后,有一些逻辑可以将值设置为 JSON 并返回未转义的 JSON。这意味着它也返回 unescaped JsonFile,我再次需要上述 JSON 格式(转义嵌入JsonFile)发送到客户端 API。


这是未转义的 JSON 格式,我需要将其转换为上面的转义 JSON(转义嵌入JsonFile)


{  

   "Message":null,

   "Error":false,

   "VData":{  

      "RNumber":null,

      "BRNumber":"Session1"

   },


之前我问过一个问题,如何将这种嵌入的JSON直接反序列化为c#类,但是那里的答案并没有解释如何以相同的格式重新序列化。我需要将上一个问题的答案扩展到写作。


天涯尽头无女友
浏览 271回答 1
1回答

胡说叔叔

您可以EmbeddedLiteralConverter<T>从此答案扩展到如何在 JSON 对象中转换转义的 JSON 字符串?通过覆盖JsonConverter.WriteJson()并执行嵌套序列化,然后编写结果字符串文字,如下所示:public class EmbeddedLiteralConverter<T> : JsonConverter{&nbsp; &nbsp; public override bool CanConvert(Type objectType)&nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; return typeof(T).IsAssignableFrom(objectType);&nbsp; &nbsp; }&nbsp; &nbsp; public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)&nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; using (new PushValue<bool>(true, () => Disabled, (canWrite) => Disabled = canWrite))&nbsp; &nbsp; &nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; using (var sw = new StringWriter(writer.Culture))&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // Copy relevant settings&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; using (var nestedWriter = new JsonTextWriter(sw)&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; DateFormatHandling = writer.DateFormatHandling,&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; DateFormatString = writer.DateFormatString,&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; DateTimeZoneHandling = writer.DateTimeZoneHandling,&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; StringEscapeHandling = writer.StringEscapeHandling,&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; FloatFormatHandling = writer.FloatFormatHandling,&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Culture = writer.Culture,&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // Remove if you don't want the escaped \r\n characters in the embedded JSON literal:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Formatting = writer.Formatting,&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; })&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; serializer.Serialize(nestedWriter, value);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; writer.WriteValue(sw.ToString());&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; }&nbsp; &nbsp; [ThreadStatic]&nbsp; &nbsp; static bool disabled;&nbsp; &nbsp; // Disables the converter in a thread-safe manner.&nbsp; &nbsp; bool Disabled { get { return disabled; } set { disabled = value; } }&nbsp; &nbsp; public override bool CanWrite { get { return !Disabled; } }&nbsp; &nbsp; public override bool CanRead { get { return !Disabled; } }&nbsp; &nbsp;&nbsp;&nbsp; &nbsp; public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)&nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; if (reader.TokenType == JsonToken.Null)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return null;&nbsp; &nbsp; &nbsp; &nbsp; var contract = serializer.ContractResolver.ResolveContract(objectType);&nbsp; &nbsp; &nbsp; &nbsp; if (contract is JsonPrimitiveContract)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; throw new JsonSerializationException("Invalid type: " + objectType);&nbsp; &nbsp; &nbsp; &nbsp; if (existingValue == null)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; existingValue = contract.DefaultCreator();&nbsp; &nbsp; &nbsp; &nbsp; if (reader.TokenType == JsonToken.String)&nbsp; &nbsp; &nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; var json = (string)JToken.Load(reader);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; using (var subReader = new JsonTextReader(new StringReader(json)))&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // By populating a pre-allocated instance we avoid an infinite recursion in EmbeddedLiteralConverter<T>.ReadJson()&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // Re-use the existing serializer to preserve settings.&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; serializer.Populate(subReader, existingValue);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; else&nbsp; &nbsp; &nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; serializer.Populate(reader, existingValue);&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; return existingValue;&nbsp; &nbsp; }}struct PushValue<T> : IDisposable{&nbsp; &nbsp; Action<T> setValue;&nbsp; &nbsp; T oldValue;&nbsp; &nbsp; public PushValue(T value, Func<T> getValue, Action<T> setValue)&nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; if (getValue == null || setValue == null)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; throw new ArgumentNullException();&nbsp; &nbsp; &nbsp; &nbsp; this.setValue = setValue;&nbsp; &nbsp; &nbsp; &nbsp; this.oldValue = getValue();&nbsp; &nbsp; &nbsp; &nbsp; setValue(value);&nbsp; &nbsp; }&nbsp; &nbsp; #region IDisposable Members&nbsp; &nbsp; // By using a disposable struct we avoid the overhead of allocating and freeing an instance of a finalizable class.&nbsp; &nbsp; public void Dispose()&nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; if (setValue != null)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; setValue(oldValue);&nbsp; &nbsp; }&nbsp; &nbsp; #endregion}然后,JsonSerializerSettings.Converters在反序列化和序列化时添加转换器:var settings = new JsonSerializerSettings{&nbsp; &nbsp; Converters = { new EmbeddedLiteralConverter<JsonFile>() },};var response = JsonConvert.DeserializeObject<Response>(testJson, settings);var json2 = JsonConvert.SerializeObject(response, Formatting.Indented, settings);或者,您可以使用如下方式将转换器直接应用于您的模型JsonConverterAttribute:public class OnlineFields{&nbsp; &nbsp; public string CCode { get; set; }&nbsp; &nbsp; public string MNumber { get; set; }&nbsp; &nbsp; public string Product { get; set; }&nbsp; &nbsp;&nbsp;&nbsp; &nbsp; [JsonConverter(typeof(EmbeddedLiteralConverter<JsonFile>))]&nbsp; &nbsp; public JsonFile JsonFile { get; set; }}笔记:严格来说,您的输入 JSON格式不正确。属性的字符串值JsonFile包含未转义的回车符:&nbsp;"JsonFile":"&nbsp; &nbsp; &nbsp; {&nbsp;&nbsp;&nbsp; &nbsp; \"evaluation\":{&nbsp;&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;\"number\":[&nbsp;&nbsp;根据最初的 JSON 提议以及JSON RFC 7159 Page 8,必须对此类控制字符进行转义:&nbsp;"{\r\n&nbsp; \"evaluation\": {\r\n&nbsp; &nbsp; \"number\": ..."&nbsp;要确认这一点,您可以将您的初始 JSON 上传到https://jsonformatter.curiousconcept.com/,它会报告以下错误:无效的 JSON (RFC 4627):错误:发现无效字符。[代码 18,结构 39]事实证明,Json.NET 会毫无怨言地读取这种无效的 JSON,但只会通过正确转义嵌套 JSON 文字中的回车和换行符来编写格式良好的 JSON。因此,您重新序列化的 JSON 看起来与初始 JSON 不同。但是,它将是格式良好的,并且应该可以被任何 JSON 解析器使用。为了防止堆栈溢出异常时序列化,EmbeddedLiteralConverter<T>.WriteJson()禁用自身通过使用该技术从递归调用时此答案到JSON.Net使用时抛出StackOverflowException [JsonConvert()]。工作示例 .Net fiddle在这里。
随时随地看视频慕课网APP
我要回答