2013-10-03 80 views
2

我已经阅读json.net上的文档相当好,并且我正在用尽想法。我有一种情况,我有孩子提及那里的父母。所以从属性Json.Net自定义序列化

public class ObjA 
{ 
    public int Id {get;set} 
    public string OtherStuff {get;set} 
    public ObjB MyChild {get;set} 
} 

public class ObjB 
{ 
    public int Id {get;set} 
    public string OtherStuff {get;set} 
    public ObjA MyParent {get;set} 
} 

这不会序列化。所以我可以做[JsonIgnore],但我更愿意做的是[JsonIdOnly]其中ObjB,而不是MyParent的序列化或跳过MyParent,完全显示MyParentId的123属性。所以

{OjbA:{ 
    Id:123, 
    OtherStuff:some other stuff, 
    MyChild:{ 
     Id:456, 
     OtherStuff:Some other stuff, 
     MyParentId:123, 
     } 
    } 
} 

我知道我可以写一个类型的自定义转换器。问题是我希望只有在指定时才会发生这种情况,否则我将无法序列化ObjA。换句话说,我需要这个才会发生,只有当我用一个属性装饰它。所以

public class ObjB 
{ 
    public int Id {get;set} 
    public string OtherStuff {get;set} 
    [JsonIdOnly] 
    public ObjA MyParent {get;set} 
} 

感谢, RAIF

回答

2

如果你不关心你的JSON中有一些额外的簿记信息,然后在JsonSerializerSettingsAll(或Objects)设置PreserveReferenceHandling选项,@Athari建议。这是使其工作的最简单方法。如果你这样做,你的JSON应该是这样的:

{ 
    "$id": "1", 
    "Id": 123, 
    "OtherStuff": "other stuff A", 
    "MyChild": { 
    "$id": "2", 
    "Id": 456, 
    "OtherStuff": "other stuff B", 
    "MyParent": { 
     "$ref": "1" 
    } 
    } 
} 

这就是说,有一种方法做你原来想要的东西,使用自定义JsonConverter。你可以做的是制作一个转换器,它将接受任何具有Id属性的对象。然后,对于那些您希望将其仅序列化为ID的地方,可以使用[JsonConverter]属性修饰这些属性。自定义转换器将用于这些情况,但不会以其他方式使用。以下是转换器的外观:

class IdOnlyConverter : JsonConverter 
{ 
    public override bool CanConvert(Type objectType) 
    { 
     return objectType.IsClass; 
    } 

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) 
    { 
     writer.WriteStartObject(); 
     writer.WritePropertyName("Id"); 
     writer.WriteValue(GetId(value)); 
     writer.WriteEndObject(); 
    } 

    private int GetId(object obj) 
    { 
     PropertyInfo prop = obj.GetType().GetProperty("Id", typeof(int)); 
     if (prop != null && prop.CanRead) 
     { 
      return (int)prop.GetValue(obj, null); 
     } 
     return 0; 
    } 

    public override bool CanRead 
    { 
     get { return false; } 
    } 

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

要使用转换器,您需要按照您的说明设置类。请注意0​​如何用属性修饰来告诉Json.Net使用该属性的自定义转换器。

public class ObjA 
{ 
    public int Id { get; set; } 
    public string OtherStuff { get; set; } 
    public ObjB MyChild { get; set; } 
} 

public class ObjB 
{ 
    public int Id { get; set; } 
    public string OtherStuff { get; set; } 
    [JsonConverter(typeof(IdOnlyConverter))] 
    public ObjA MyParent { get; set; } 
} 

序列化时,您将需要的JsonSerializerSettingsReferenceLoopHandling选项设置为Serialize告诉Json.Net如果检测到参考回路不是抛出一个错误,并继续反正序列化(因为我们的转换器将处理它)。

全部放在一起,这里是一些示例代码演示了正在运行的转换器:

class Program 
{ 
    static void Main(string[] args) 
    { 
     ObjA a = new ObjA(); 
     a.Id = 123; 
     a.OtherStuff = "other stuff A"; 

     ObjB b = new ObjB(); 
     b.Id = 456; 
     b.OtherStuff = "other stuff B"; 
     b.MyParent = a; 

     a.MyChild = b; 

     JsonSerializerSettings settings = new JsonSerializerSettings 
     { 
      ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Serialize, 
      Formatting = Newtonsoft.Json.Formatting.Indented 
     }; 

     string json = JsonConvert.SerializeObject(a, settings); 
     Console.WriteLine(json); 
    } 
} 

这里是上面的输出:

{ 
    "Id": 123, 
    "OtherStuff": "other stuff A", 
    "MyChild": { 
    "Id": 456, 
    "OtherStuff": "other stuff B", 
    "MyParent": { 
     "Id": 123 
    } 
    } 
} 
+0

哦,好的,是的,我创建了一个转换器,但不知道如何让他进入属性。这将工作正常。感谢你们两位。 – Raif

+0

嗨,所以一切都很好,除了我得到这个错误{“Message”:“发生错误”, “ExceptionMessage”:“'ObjectContent'1'类型未能序列化内容类型的响应主体'application/json; charset = utf-8'。“, ”ExceptionType“:”System.InvalidOperationException“, ”StackTrace“:null, ”InnerException“:{ ”Message“:”发生错误。 , “ExceptionMessage”:“错误创建GuidEntityToIdJsonConverter”, “ExceptionType”:“Newtonsoft.Json.JsonException”, – Raif

+0

哇抱歉缺乏在这个堆栈跟踪结束格式化 – Raif

0

您可以更改JsonSerializerSettings.PreserveReferencesHandlingPreserveReferencesHandling.ObjectsPreserveReferencesHandling.All(你可能还需要改变​​和各种JsonPropertyAttribute关于引用属性)。这将为对象添加$ref JSON属性,交叉链接将被保留。

您可以使用自定义IReferenceResolver修改$ref属性的文本。

但是,如果您需要更复杂的引用来解析(如您所建议的引用),而没有$ref属性,则必须编写一些代码。

+0

谢谢大家的响应。我没有看到这些属性,正在调查。不过,我很乐意编写一些代码来获得我想要的。我只是无法从customConverter和converterAttribute中弄明白。我现在正在阅读上面的道具(实际上我正要去吃午饭,但之后),目的是弄清楚如何编写自己的扩展。如果你碰巧知道正确的方向,那么知道这很好。再次感谢,raif – Raif

+0

真的很快,我去吃午饭它看起来像ReferenceLoopHandling是非常接近。如果我可以继承它,或者通过一些完美的机制扩展它。 – Raif

+0

如果你的JSON看起来并不重要,我建议坚持'$ ref'属性。我在[我的私人框架](https://github.com/Athari/Alba.Framework/tree/master/Alba.Framework.Serialization.Json)中实现了自定义引用,但是我担心它太复杂了一个很好的样本。它会像上面建议的那样建立链接,但它需要很多属性和一些自定义代码;没有文档。 :) – Athari

相关问题