IT TIP

Json.Net에서 PreserveReferencesHandling과 ReferenceLoopHandling의 차이점은 무엇입니까?

itqueen 2020. 12. 14. 21:27
반응형

Json.Net에서 PreserveReferencesHandling과 ReferenceLoopHandling의 차이점은 무엇입니까?


이 코드가있는 하나의 WebAPI 응용 프로그램 샘플을보고 있습니다.

json.SerializerSettings.PreserveReferencesHandling 
   = Newtonsoft.Json.PreserveReferencesHandling.Objects;

이 코딩 된 또 다른 :

json.SerializerSettings.ReferenceLoopHandling 
   = Newtonsoft.Json.ReferenceLoopHandling.Ignore;

각각이 선택된 이유도 설명하지 마십시오. 저는 WebAPI를 처음 접했기 때문에 차이점이 무엇이며 왜 다른 것을 사용해야 하는지를 간단한 용어로 설명하여 도움을 줄 수 있습니다.


이러한 설정은 예를 통해 가장 잘 설명 할 수 있습니다. 회사에서 직원의 계층 구조를 나타내려고한다고 가정 해 보겠습니다. 따라서 다음과 같은 간단한 클래스를 만듭니다.

class Employee
{
    public string Name { get; set; }
    public List<Employee> Subordinates { get; set; }
}

지금까지 Angela, Bob, Charles라는 세 명의 직원 만있는 작은 회사입니다. Angela는 보스이고 Bob과 Charles는 그녀의 부하입니다. 이 관계를 설명하는 데이터를 설정해 보겠습니다.

Employee angela = new Employee { Name = "Angela Anderson" };
Employee bob = new Employee { Name = "Bob Brown" };
Employee charles = new Employee { Name = "Charles Cooper" };

angela.Subordinates = new List<Employee> { bob, charles };

List<Employee> employees = new List<Employee> { angela, bob, charles };

직원 목록을 JSON으로 직렬화하면 ...

string json = JsonConvert.SerializeObject(employees, Formatting.Indented);
Console.WriteLine(json);

...이 출력을 얻습니다.

[
  {
    "Name": "Angela Anderson",
    "Subordinates": [
      {
        "Name": "Bob Brown",
        "Subordinates": null
      },
      {
        "Name": "Charles Cooper",
        "Subordinates": null
      }
    ]
  },
  {
    "Name": "Bob Brown",
    "Subordinates": null
  },
  {
    "Name": "Charles Cooper",
    "Subordinates": null
  }
]

여태까지는 그런대로 잘됐다. 그러나 Bob과 Charles에 대한 정보는 JSON에서 반복됩니다. 직원을 나타내는 개체는 기본 직원 목록과 Angela의 부하 직원 목록에서 모두 참조되기 때문입니다. 지금은 괜찮을 수도 있습니다.

이제 우리는 또한 각 직원의 부하 직원과 함께 각 직원의 상사를 추적하는 방법을 원한다고 가정합니다. 그래서 우리 EmployeeSupervisor속성 을 추가하기 위해 모델을 변경 합니다.

class Employee
{
    public string Name { get; set; }
    public Employee Supervisor { get; set; }
    public List<Employee> Subordinates { get; set; }
}

... 설정 코드에 몇 줄을 더 추가하여 Charles와 Bob이 Angela에게보고 함을 나타냅니다.

Employee angela = new Employee { Name = "Angela Anderson" };
Employee bob = new Employee { Name = "Bob Brown" };
Employee charles = new Employee { Name = "Charles Cooper" };

angela.Subordinates = new List<Employee> { bob, charles };
bob.Supervisor = angela;       // added this line
charles.Supervisor = angela;   // added this line

List<Employee> employees = new List<Employee> { angela, bob, charles };

하지만 이제 우리는 약간의 문제가 있습니다. 객체 그래프에는 참조 루프가 있기 때문에 (예 : angelareferences bobwhile bobreferences angela) JsonSerializationException직원 목록을 직렬화하려고 할 때 a 가 표시됩니다. 이 문제를 해결할 수있는 한 가지 방법은 다음과 같이 설정 ReferenceLoopHandling하는 Ignore것입니다.

JsonSerializerSettings settings = new JsonSerializerSettings
{
    ReferenceLoopHandling = ReferenceLoopHandling.Ignore,
    Formatting = Formatting.Indented
};

string json = JsonConvert.SerializeObject(employees, settings);

이 설정을 사용하면 다음 JSON을 얻습니다.

[
  {
    "Name": "Angela Anderson",
    "Supervisor": null,
    "Subordinates": [
      {
        "Name": "Bob Brown",
        "Subordinates": null
      },
      {
        "Name": "Charles Cooper",
        "Subordinates": null
      }
    ]
  },
  {
    "Name": "Bob Brown",
    "Supervisor": {
      "Name": "Angela Anderson",
      "Supervisor": null,
      "Subordinates": [
        {
          "Name": "Charles Cooper",
          "Subordinates": null
        }
      ]
    },
    "Subordinates": null
  },
  {
    "Name": "Charles Cooper",
    "Supervisor": {
      "Name": "Angela Anderson",
      "Supervisor": null,
      "Subordinates": [
        {
          "Name": "Bob Brown",
          "Subordinates": null
        }
      ]
    },
    "Subordinates": null
  }
]

If you examine the JSON, it should be clear what this setting does: any time the serializer encounters a reference back to an object it is already in the process of serializing, it simply skips that member. (This prevents the serializer from getting into an infinite loop.) You can see that in Angela's list of subordinates in the top part of the JSON, neither Bob nor Charles show a supervisor. In the bottom part of the JSON, Bob and Charles both show Angela as their supervisor, but notice her subordinates list at that point does not include both Bob and Charles.

While it is possible to work with this JSON and maybe even reconstruct the original object hierarchy from it with some work, it is clearly not optimal. We can eliminate the repeated information in the JSON while still preserving the object references by using the PreserveReferencesHandling setting instead:

JsonSerializerSettings settings = new JsonSerializerSettings
{
    PreserveReferencesHandling = PreserveReferencesHandling.Objects,
    Formatting = Formatting.Indented
};

string json = JsonConvert.SerializeObject(employees, settings);

Now we get the following JSON:

[
  {
    "$id": "1",
    "Name": "Angela Anderson",
    "Supervisor": null,
    "Subordinates": [
      {
        "$id": "2",
        "Name": "Bob Brown",
        "Supervisor": {
          "$ref": "1"
        },
        "Subordinates": null
      },
      {
        "$id": "3",
        "Name": "Charles Cooper",
        "Supervisor": {
          "$ref": "1"
        },
        "Subordinates": null
      }
    ]
  },
  {
    "$ref": "2"
  },
  {
    "$ref": "3"
  }
]

Notice that now each object has been assigned a sequential $id value in the JSON. The first time that an object appears, it is serialized in full, while subsequent references are replaced with a special $ref property that refers back to the original object with the corresponding $id. With this setting in place, the JSON is much more concise and can be deserialized back into the original object hierarchy with no additional work required, assuming you are using a library that understands the $id and $ref notation produced by Json.Net / Web API.

So why would you choose one setting or the other? It depends on your needs of course. If the JSON will be consumed by a client that does not understand the $id/$ref format, and it can tolerate having incomplete data in places, you would choose to use ReferenceLoopHandling.Ignore. If you're looking for more compact JSON and you will be using Json.Net or Web API (or another compatible library) to deserialize the data, then you would choose to use PreserveReferencesHandling.Objects. If your data is a directed acyclic graph with no duplicate references then you don't need either setting.

참고URL : https://stackoverflow.com/questions/23453977/what-is-the-difference-between-preservereferenceshandling-and-referenceloophandl

반응형