【问题标题】:Serialize object to JSON that already contains one JSON property将对象序列化为已包含一个 JSON 属性的 JSON
【发布时间】:2015-09-20 20:45:09
【问题描述】:

为了提高性能,我将较大操作的结果作为 JSON 缓存在一个表中 - 连同一个键列来确定要返回哪些行。所以数据看起来像这样:

Id   Json
---- ---------
1    {"property": "data", "...": "..."}
2    {"property": "data", "...": "..."}

因此,我检索到的对象具有属性 int .Id 和 string .Json。当返回这样一个带有 Id 的对象时,我首先需要反序列化 JSON - 以便正确地重新序列化它。如果我不先反序列化它,我会得到一个带引号的字符串,即我的返回对象看起来像这样

{
  "id": 1,
  "json": "{\"property\": \"data\", ...
}

相反,我需要:

{
  "id": 1,
  "json": {
      "property": "data", 
      ...
  }
}

有没有办法“告诉”Json.Net 序列化程序直接输出 .Json 属性而不进行序列化 - 同时序列化其他属性?

【问题讨论】:

  • 所以如果我理解你的输出是 {"id":1,"Json":{"data1":"value","data2":"value","data3":"value" }} 而你想要 {"id":1,"Json":"\"data1\":\"value\",\"data2\":\"value\",\"data3\":\"值\""}?
  • @VeNoMiS:查看更新后的问题
  • 我认为您需要为该类型编写自己的 JsonConverter。
  • 使用 2 个类(容器和项目)和具有 2 个道具(int id 和项目 json)的容器和带有道具的项目。 Item m = JsonConvert.DeserializeObject(row.json) 应该可以解决问题
  • 您确定它是有效的 JSON 吗?如果您不想让 Json.NET 转义它,则它必须是有效的。

标签: c# .net asp.net-web-api json.net


【解决方案1】:

假设你有这样的序列化结构:

public class Record
{
    [JsonProperty("id")]
    public int Id
    {
        get;
        set;
    }

    [JsonProperty("json")]
    [JsonConverter(typeof(SpecialJsonConverter))]
    public string Json
    {
        get;
        set;
    }
}

你使用这样的代码进行序列化:

    var data = new []
    { 
        new Record() { Id=1, Json = "{\"property\":\"data\"}" }, 
        new Record() { Id=2, Json = "{\"property\":\"data2\", \"property2\":[1, 2, 3]}" }
    };

    var serialized = JsonConvert.SerializeObject(data);
    Console.WriteLine(serialized);

您只需要为 Json 属性编写一个适当的转换器。幸运的是,JsonWriter 类中有一个方法 WriteToken 可以满足我们的需求:

public sealed class SpecialJsonConverter : JsonConverter
{
    public override bool CanConvert(Type objectType)
    {
        return true;
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        throw new NotImplementedException();
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        var reader = new JsonTextReader(new StringReader(value.ToString()));
        writer.WriteToken(reader);
    }
}

【讨论】:

  • 我想补充一点,您也可以在 WriteJson 中编写以下内容:writer.WriteToken(JsonToken.Raw, value);
  • writer.WriteRawValue((string)value); 如图所示here 会更简单。
【解决方案2】:

您可以创建一个JsonConverter 将字符串属性的原始值写入输出而不更改它。您负责确保字符串具有有效的 JSON,否则生成的输出也将不是有效的 JSON。

这是转换器的外观:

class RawJsonConverter : JsonConverter
{
    public override bool CanConvert(Type objectType)
    {
        return (objectType == typeof(string));
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        // write value directly to output; assumes string is already JSON
        writer.WriteRawValue((string)value);  
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        // convert parsed JSON back to string
        return JToken.Load(reader).ToString(Formatting.None);  
    }
}

要使用它,请使用 [JsonConverter] 属性标记您的 JSON 属性,如下所示:

class Foo
{
    ...
    [JsonConverter(typeof(RawJsonConverter))]
    public string YourJsonProperty { get; set; }
    ...
}

这是一个演示:https://dotnetfiddle.net/BsTLO8

【讨论】:

    【解决方案3】:

    基于answer by Alex 和 Shahin 的评论,我对转换器进行了一些改进,并且还实现了阅读器以另一种方式工作(从 JToken 解析回字符串属性):

    public sealed class RawDataJsonConverter : JsonConverter
    {
        public override bool CanConvert(Type objectType)
        {
            return objectType == typeof(string);
        }
    
        public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
        {
            var tokenReader = reader as JTokenReader;
            var data = tokenReader.CurrentToken.ToString(Formatting.None);
            return data;
        }
    
        public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
        {
            writer.WriteToken(JsonToken.Raw, value);
        }
    }
    

    【讨论】:

      猜你喜欢
      • 2015-07-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-08-25
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多