Self referencing loop in Json.Net JsonSerializer from custom JsonConverter (Web API)

前端 未结 7 1245
温柔的废话
温柔的废话 2020-12-16 09:28

The project is an Asp.Net Web API web service.

I have a type hierarchy that I need to be able to serialize to and from Json, so I have taken the code from this SO: H

7条回答
  •  死守一世寂寞
    2020-12-16 09:56

    I just came across this myself and I was pulling my hair out in frustration!

    To solve the issue, the following worked for me, but because I missed the CanWrite solution, it's a more complex workaround.

    • Create a copy of the existing class on which you're using your Converter and call it something different.
    • Remove the JsonConverter attribute on the copy.
    • Create a constructor on the new class which takes a parameter of the same type as the original class. Use the constructor to copy over any values which are required for later serialisation.
    • In your Converter's WriteJson method, convert the value into your dummy type, then serialise that type instead.

    For instance, this is similar to my original class:

    [JsonConverter(typeof(MyResponseConverter))]
    public class MyResponse
    {
        public ResponseBlog blog { get; set; }
        public Post[] posts { get; set; }
    }
    

    The copy looks like this:

    public class FakeMyResponse
    {
        public ResponseBlog blog { get; set; }
        public Post[] posts { get; set; }
    
        public FakeMyResponse(MyResponse response)
        {
            blog = response.blog;
            posts = response.posts;
        }
    }
    

    The WriteJson is:

    public override void WriteJson(JsonWriter writer, object value,
        JsonSerializer serializer)
    {
        if (CanConvert(value.GetType()))
        {
            FakeMyResponse response = new FakeMyResponse((MyResponse)value);
            serializer.Serialize(writer, response);
        }
    }
    

    Edit:

    The OP pointed out that using an Expando could be another possible solution. This works well, saving the bother of creating the new class, although DLR support requires Framework 4.0 or later. The approach is to create a new dynamic ExpandoObject and then initialise its properties in the WriteJson method directly to create the copy, e.g.:

    public override void WriteJson(JsonWriter writer, object value,
        JsonSerializer serializer)
    {
        if (CanConvert(value.GetType()))
        {
            var response = (MyResponse)value;
            dynamic fake = new System.Dynamic.ExpandoObject();
            fake.blog = response.blog;
            fake.posts = response.posts;
            serializer.Serialize(writer, fake);
        }
    }
    

提交回复
热议问题