System.Text.Json에서 JSON 문서 개체 모델을 사용하는 방법
이 문서에서는 JSON 페이로드의 데이터에 임의로 액세스하기 위해 JSON DOM(문서 개체 모델)을 사용하는 방법을 보여 줍니다.
JSON DOM 선택
DOM을 사용하는 것은 다음의 경우 JsonSerializer를 사용한 역직렬화의 대안입니다.
- 역직렬화할 형식이 없습니다.
- 수신한 JSON에는 고정된 스키마가 없으며 포함된 내용을 확인하려면 검사해야 합니다.
System.Text.Json
은 JSON DOM을 빌드하는 두 가지 방법을 다음과 같이 제공합니다.
JsonDocument는
Utf8JsonReader
를 사용하여 읽기 전용 DOM을 빌드하는 기능을 제공합니다. 페이로드를 구성하는 JSON 요소는 JsonElement 형식을 통해 액세스할 수 있습니다.JsonElement
형식은 JSON 텍스트를 일반적인 .NET 형식으로 변환하는 API와 함께 배열 및 개체 열거자를 제공합니다.JsonDocument
는 RootElement 속성을 노출합니다. 자세한 내용은 이 문서의 뒷부분에서 JsonDocument 사용을 참조하세요.System.Text.Json.Nodes 네임스페이스에서 파생되는 클래스와 JsonNode는 변경 가능한 DOM을 만드는 기능을 제공합니다. 페이로드를 구성하는 JSON 요소는 JsonNode, JsonObject, JsonArray, JsonValue 및 JsonElement 형식을 통해 액세스할 수 있습니다. 자세한 내용은 이 문서의 뒷부분에서
JsonNode
사용을 참조하세요.
JsonDocument
와 JsonNode
중에서 하나를 선택할 때 다음 요소를 고려합니다.
JsonNode
DOM을 만든 후에 변경할 수 있습니다.JsonDocument
DOM은 변경할 수 없습니다.JsonDocument
DOM은 데이터에 더 빠르게 액세스할 수 있도록 합니다.
JsonNode
사용
다음 예제에서는 JsonNode를 사용하는 방법과 System.Text.Json.Nodes 네임스페이스의 다른 형식을 사용하여 다음을 수행하는 방법을 보여줍니다.
- JSON 문자열에서 DOM 만들기
- DOM에서 JSON을 작성합니다.
- DOM에서 값, 개체 또는 배열을 가져옵니다.
using System.Text.Json;
using System.Text.Json.Nodes;
namespace JsonNodeFromStringExample;
public class Program
{
public static void Main()
{
string jsonString = """
{
"Date": "2019-08-01T00:00:00",
"Temperature": 25,
"Summary": "Hot",
"DatesAvailable": [
"2019-08-01T00:00:00",
"2019-08-02T00:00:00"
],
"TemperatureRanges": {
"Cold": {
"High": 20,
"Low": -10
},
"Hot": {
"High": 60,
"Low": 20
}
}
}
""";
// Create a JsonNode DOM from a JSON string.
JsonNode forecastNode = JsonNode.Parse(jsonString)!;
// Write JSON from a JsonNode
var options = new JsonSerializerOptions { WriteIndented = true };
Console.WriteLine(forecastNode!.ToJsonString(options));
// output:
//{
// "Date": "2019-08-01T00:00:00",
// "Temperature": 25,
// "Summary": "Hot",
// "DatesAvailable": [
// "2019-08-01T00:00:00",
// "2019-08-02T00:00:00"
// ],
// "TemperatureRanges": {
// "Cold": {
// "High": 20,
// "Low": -10
// },
// "Hot": {
// "High": 60,
// "Low": 20
// }
// }
//}
// Get value from a JsonNode.
JsonNode temperatureNode = forecastNode!["Temperature"]!;
Console.WriteLine($"Type={temperatureNode.GetType()}");
Console.WriteLine($"JSON={temperatureNode.ToJsonString()}");
//output:
//Type = System.Text.Json.Nodes.JsonValue`1[System.Text.Json.JsonElement]
//JSON = 25
// Get a typed value from a JsonNode.
int temperatureInt = (int)forecastNode!["Temperature"]!;
Console.WriteLine($"Value={temperatureInt}");
//output:
//Value=25
// Get a typed value from a JsonNode by using GetValue<T>.
temperatureInt = forecastNode!["Temperature"]!.GetValue<int>();
Console.WriteLine($"TemperatureInt={temperatureInt}");
//output:
//Value=25
// Get a JSON object from a JsonNode.
JsonNode temperatureRanges = forecastNode!["TemperatureRanges"]!;
Console.WriteLine($"Type={temperatureRanges.GetType()}");
Console.WriteLine($"JSON={temperatureRanges.ToJsonString()}");
//output:
//Type = System.Text.Json.Nodes.JsonObject
//JSON = { "Cold":{ "High":20,"Low":-10},"Hot":{ "High":60,"Low":20} }
// Get a JSON array from a JsonNode.
JsonNode datesAvailable = forecastNode!["DatesAvailable"]!;
Console.WriteLine($"Type={datesAvailable.GetType()}");
Console.WriteLine($"JSON={datesAvailable.ToJsonString()}");
//output:
//datesAvailable Type = System.Text.Json.Nodes.JsonArray
//datesAvailable JSON =["2019-08-01T00:00:00", "2019-08-02T00:00:00"]
// Get an array element value from a JsonArray.
JsonNode firstDateAvailable = datesAvailable[0]!;
Console.WriteLine($"Type={firstDateAvailable.GetType()}");
Console.WriteLine($"JSON={firstDateAvailable.ToJsonString()}");
//output:
//Type = System.Text.Json.Nodes.JsonValue`1[System.Text.Json.JsonElement]
//JSON = "2019-08-01T00:00:00"
// Get a typed value by chaining references.
int coldHighTemperature = (int)forecastNode["TemperatureRanges"]!["Cold"]!["High"]!;
Console.WriteLine($"TemperatureRanges.Cold.High={coldHighTemperature}");
//output:
//TemperatureRanges.Cold.High = 20
// Parse a JSON array
var datesNode = JsonNode.Parse(@"[""2019-08-01T00:00:00"",""2019-08-02T00:00:00""]");
JsonNode firstDate = datesNode![0]!.GetValue<DateTime>();
Console.WriteLine($"firstDate={ firstDate}");
//output:
//firstDate = "2019-08-01T00:00:00"
}
}
개체 이니셜라이저를 사용하여 JsonNode DOM 만들기 및 변경
아래 예제는 다음과 같은 작업의 방법을 보여 줍니다.
- 개체 이니셜라이저를 사용하여 DOM을 만듭니다.
- DOM을 변경합니다.
using System.Text.Json;
using System.Text.Json.Nodes;
namespace JsonNodeFromObjectExample;
public class Program
{
public static void Main()
{
// Create a new JsonObject using object initializers.
var forecastObject = new JsonObject
{
["Date"] = new DateTime(2019, 8, 1),
["Temperature"] = 25,
["Summary"] = "Hot",
["DatesAvailable"] = new JsonArray(
new DateTime(2019, 8, 1), new DateTime(2019, 8, 2)),
["TemperatureRanges"] = new JsonObject
{
["Cold"] = new JsonObject
{
["High"] = 20,
["Low"] = -10
}
},
["SummaryWords"] = new JsonArray("Cool", "Windy", "Humid")
};
// Add an object.
forecastObject!["TemperatureRanges"]!["Hot"] =
new JsonObject { ["High"] = 60, ["Low"] = 20 };
// Remove a property.
forecastObject.Remove("SummaryWords");
// Change the value of a property.
forecastObject["Date"] = new DateTime(2019, 8, 3);
var options = new JsonSerializerOptions { WriteIndented = true };
Console.WriteLine(forecastObject.ToJsonString(options));
//output:
//{
// "Date": "2019-08-03T00:00:00",
// "Temperature": 25,
// "Summary": "Hot",
// "DatesAvailable": [
// "2019-08-01T00:00:00",
// "2019-08-02T00:00:00"
// ],
// "TemperatureRanges": {
// "Cold": {
// "High": 20,
// "Low": -10
// },
// "Hot": {
// "High": 60,
// "Low": 20
// }
// }
//}
}
}
JSON 페이로드의 하위 섹션 역직렬화
다음 예제에서는 JsonNode를 사용하여 JSON 트리의 하위 섹션으로 이동하고 해당 하위 섹션에서 단일 값, 사용자 지정 형식 또는 배열을 역직렬화하는 방법을 보여줍니다.
using System.Text.Json;
using System.Text.Json.Nodes;
namespace JsonNodePOCOExample;
public class TemperatureRanges : Dictionary<string, HighLowTemps>
{
}
public class HighLowTemps
{
public int High { get; set; }
public int Low { get; set; }
}
public class Program
{
public static DateTime[]? DatesAvailable { get; set; }
public static void Main()
{
string jsonString = """
{
"Date": "2019-08-01T00:00:00",
"Temperature": 25,
"Summary": "Hot",
"DatesAvailable": [
"2019-08-01T00:00:00",
"2019-08-02T00:00:00"
],
"TemperatureRanges": {
"Cold": {
"High": 20,
"Low": -10
},
"Hot": {
"High": 60,
"Low": 20
}
}
}
""";
// Parse all of the JSON.
JsonNode forecastNode = JsonNode.Parse(jsonString)!;
// Get a single value
int hotHigh = forecastNode["TemperatureRanges"]!["Hot"]!["High"]!.GetValue<int>();
Console.WriteLine($"Hot.High={hotHigh}");
// output:
//Hot.High=60
// Get a subsection and deserialize it into a custom type.
JsonObject temperatureRangesObject = forecastNode!["TemperatureRanges"]!.AsObject();
using var stream = new MemoryStream();
using var writer = new Utf8JsonWriter(stream);
temperatureRangesObject.WriteTo(writer);
writer.Flush();
TemperatureRanges? temperatureRanges =
JsonSerializer.Deserialize<TemperatureRanges>(stream.ToArray());
Console.WriteLine($"Cold.Low={temperatureRanges!["Cold"].Low}, Hot.High={temperatureRanges["Hot"].High}");
// output:
//Cold.Low=-10, Hot.High=60
// Get a subsection and deserialize it into an array.
JsonArray datesAvailable = forecastNode!["DatesAvailable"]!.AsArray()!;
Console.WriteLine($"DatesAvailable[0]={datesAvailable[0]}");
// output:
//DatesAvailable[0]=8/1/2019 12:00:00 AM
}
}
JsonNode 평균 등급 예제
다음 예제에서는 정수 값이 있는 JSON 배열을 선택하고 평균 값을 계산합니다.
using System.Text.Json.Nodes;
namespace JsonNodeAverageGradeExample;
public class Program
{
public static void Main()
{
string jsonString = """
{
"Class Name": "Science",
"Teacher\u0027s Name": "Jane",
"Semester": "2019-01-01",
"Students": [
{
"Name": "John",
"Grade": 94.3
},
{
"Name": "James",
"Grade": 81.0
},
{
"Name": "Julia",
"Grade": 91.9
},
{
"Name": "Jessica",
"Grade": 72.4
},
{
"Name": "Johnathan"
}
],
"Final": true
}
""";
double sum = 0;
JsonNode document = JsonNode.Parse(jsonString)!;
JsonNode root = document.Root;
JsonArray studentsArray = root["Students"]!.AsArray();
int count = studentsArray.Count;
foreach (JsonNode? student in studentsArray)
{
if (student?["Grade"] is JsonNode gradeNode)
{
sum += (double)gradeNode;
}
else
{
sum += 70;
}
}
double average = sum / count;
Console.WriteLine($"Average grade : {average}");
}
}
// output:
//Average grade : 81.92
위의 코드는
Grade
속성이 있는Students
배열의 개체에 대한 평균 등급을 계산합니다.- 등급이 없는 학생에게 기본 등급 70을 할당합니다.
JsonArray
의Count
속성에서 학생 수를 가져옵니다.
JsonNode
(JsonSerializerOptions
사용)
JsonSerializer
를 사용하여 JsonNode
인스턴스를 직렬화하고 역직렬화할 수 있습니다. 그러나 JsonSerializerOptions
를 사용하는 오버로드를 사용하는 경우 옵션 인스턴스는 사용자 지정 변환기를 가져오는 데만 사용됩니다. 옵션 인스턴스의 나머지 기능은 사용되지 않습니다. 예를 들어 JsonSerializerOptions.DefaultIgnoreCondition을 WhenWritingNull로 설정하고 JsonSerializerOptions
를 사용하는 오버로드를 사용하여 JsonSerializer
를 호출하는 경우 null 속성은 무시되지 않습니다.
JsonSerializerOptions
매개 변수를 사용하는 JsonNode
메서드인 WriteTo(Utf8JsonWriter, JsonSerializerOptions) 및 ToJsonString(JsonSerializerOptions)에도 동일한 제한 사항이 적용됩니다. 이러한 API는 사용자 지정 변환기를 가져오는 데만 JsonSerializerOptions
를 사용합니다.
다음 예제에서는 JsonSerializerOptions
매개 변수를 사용하고 JsonNode
인스턴스를 직렬화하는 메서드를 사용한 결과를 보여줍니다.
using System.Text;
using System.Text.Json;
using System.Text.Json.Nodes;
using System.Text.Json.Serialization;
namespace JsonNodeWithJsonSerializerOptions;
public class Program
{
public static void Main()
{
Person person = new() { Name = "Nancy" };
// Default serialization - Address property included with null token.
// Output: {"Name":"Nancy","Address":null}
string personJsonWithNull = JsonSerializer.Serialize(person);
Console.WriteLine(personJsonWithNull);
// Serialize and ignore null properties - null Address property is omitted
// Output: {"Name":"Nancy"}
JsonSerializerOptions options = new()
{
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull
};
string personJsonWithoutNull = JsonSerializer.Serialize(person, options);
Console.WriteLine(personJsonWithoutNull);
// Ignore null properties doesn't work when serializing JsonNode instance
// by using JsonSerializer.
// Output: {"Name":"Nancy","Address":null}
JsonNode? personJsonNode = JsonSerializer.Deserialize<JsonNode>(personJsonWithNull);
personJsonWithNull = JsonSerializer.Serialize(personJsonNode, options);
Console.WriteLine(personJsonWithNull);
// Ignore null properties doesn't work when serializing JsonNode instance
// by using JsonNode.ToJsonString method.
// Output: {"Name":"Nancy","Address":null}
personJsonWithNull = personJsonNode!.ToJsonString(options);
Console.WriteLine(personJsonWithNull);
// Ignore null properties doesn't work when serializing JsonNode instance
// by using JsonNode.WriteTo method.
// Output: {"Name":"Nancy","Address":null}
using var stream = new MemoryStream();
using var writer = new Utf8JsonWriter(stream);
personJsonNode!.WriteTo(writer, options);
writer.Flush();
personJsonWithNull = Encoding.UTF8.GetString(stream.ToArray());
Console.WriteLine(personJsonWithNull);
}
}
public class Person
{
public string? Name { get; set; }
public string? Address { get; set; }
}
사용자 지정 변환기 이외에 JsonSerializerOptions
의 기능이 필요한 경우 JsonNode
대신 강력한 형식의 대상(예: 이 예제의 Person
클래스)과 함께 JsonSerializer
를 사용합니다.
속성 순서 조작
JsonObject 는 페이로드의 JsonNode요소 중 하나이며 변경 가능한 JSON 개체를 나타냅니다. 형식은 각 항목이 개체의 속성인 형식으로 IDictionary<string, JsonNode>
모델링되더라도 암시적 속성 순서를 캡슐화합니다. 그러나 특정 인덱스에서 항목을 삽입하고 RemoveAt(Int32) 제거할 수 있도록 하여 정렬된 사전과 같은 Insert(Int32, String, JsonNode) API에서 형식을 효과적으로 모델링합니다. 이러한 API를 사용하면 속성 순서에 직접적인 영향을 줄 수 있는 개체 인스턴스를 수정할 수 있습니다.
다음 코드는 개체의 시작 부분에 특정 속성을 추가하거나 이동하는 예제를 보여줍니다.
var schema = (JsonObject)JsonSerializerOptions.Default.GetJsonSchemaAsNode(typeof(MyPoco));
JsonNode? idValue;
switch (schema.IndexOf("$id"))
{
// $id property missing.
case < 0:
idValue = (JsonNode)"https://example.com/schema";
schema.Insert(0, "$id", idValue);
break;
// $id property already at the start of the object.
case 0:
break;
// $id exists but not at the start of the object.
case int index:
idValue = schema[index];
schema.RemoveAt(index);
schema.Insert(0, "$id", idValue);
break;
}
JsonNodes 비교
하위 요소를 포함하여 두 JsonNode
개체를 같음으로 비교하려면 이 메서드를 JsonNode.DeepEquals(JsonNode, JsonNode) 사용합니다.
JsonDocument
사용
다음 예제에서는 JsonDocument 클래스를 사용하여 JSON 문자열의 데이터에 임의로 액세스하는 방법을 보여줍니다.
double sum = 0;
int count = 0;
using (JsonDocument document = JsonDocument.Parse(jsonString))
{
JsonElement root = document.RootElement;
JsonElement studentsElement = root.GetProperty("Students");
foreach (JsonElement student in studentsElement.EnumerateArray())
{
if (student.TryGetProperty("Grade", out JsonElement gradeElement))
{
sum += gradeElement.GetDouble();
}
else
{
sum += 70;
}
count++;
}
}
double average = sum / count;
Console.WriteLine($"Average grade : {average}");
Dim sum As Double = 0
Dim count As Integer = 0
Using document As JsonDocument = JsonDocument.Parse(jsonString)
Dim root As JsonElement = document.RootElement
Dim studentsElement As JsonElement = root.GetProperty("Students")
For Each student As JsonElement In studentsElement.EnumerateArray()
Dim gradeElement As JsonElement = Nothing
If student.TryGetProperty("Grade", gradeElement) Then
sum += gradeElement.GetDouble()
Else
sum += 70
End If
count += 1
Next
End Using
Dim average As Double = sum / count
Console.WriteLine($"Average grade : {average}")
위의 코드는
- 분석할 JSON은
jsonString
이라는 문자열에 있다고 가정합니다. Grade
속성이 있는Students
배열의 개체에 대한 평균 등급을 계산합니다.- 등급이 없는 학생에게 기본 등급 70을 할당합니다.
JsonDocument
가IDisposable
을 구현하기 때문에using
문에JsonDocument
인스턴스를 만듭니다.JsonDocument
인스턴스가 삭제되면 모든JsonElement
인스턴스에 대한 액세스 권한도 잃게 됩니다.JsonElement
인스턴스에 대한 액세스를 유지하려면 이 인스턴스의 복사본을 만든 후 부모JsonDocument
인스턴스를 삭제하세요. 복사본을 만들려면 JsonElement.Clone을 호출합니다. 자세한 내용은 JsonDocument is IDisposable을 참조하세요.
앞의 예제 코드는 각 반복을 사용하여 count
변수를 증가시켜 학생 수를 계산합니다. 다음 예제처럼 GetArrayLength를 호출하는 방법도 있습니다.
double sum = 0;
int count = 0;
using (JsonDocument document = JsonDocument.Parse(jsonString))
{
JsonElement root = document.RootElement;
JsonElement studentsElement = root.GetProperty("Students");
count = studentsElement.GetArrayLength();
foreach (JsonElement student in studentsElement.EnumerateArray())
{
if (student.TryGetProperty("Grade", out JsonElement gradeElement))
{
sum += gradeElement.GetDouble();
}
else
{
sum += 70;
}
}
}
double average = sum / count;
Console.WriteLine($"Average grade : {average}");
Dim sum As Double = 0
Dim count As Integer = 0
Using document As JsonDocument = JsonDocument.Parse(jsonString)
Dim root As JsonElement = document.RootElement
Dim studentsElement As JsonElement = root.GetProperty("Students")
count = studentsElement.GetArrayLength()
For Each student As JsonElement In studentsElement.EnumerateArray()
Dim gradeElement As JsonElement = Nothing
If student.TryGetProperty("Grade", gradeElement) Then
sum += gradeElement.GetDouble()
Else
sum += 70
End If
Next
End Using
Dim average As Double = sum / count
Console.WriteLine($"Average grade : {average}")
다음은 이 코드가 처리하는 JSON 예제입니다.
{
"Class Name": "Science",
"Teacher\u0027s Name": "Jane",
"Semester": "2019-01-01",
"Students": [
{
"Name": "John",
"Grade": 94.3
},
{
"Name": "James",
"Grade": 81.0
},
{
"Name": "Julia",
"Grade": 91.9
},
{
"Name": "Jessica",
"Grade": 72.4
},
{
"Name": "Johnathan"
}
],
"Final": true
}
JsonDocument
대신 JsonNode
를 사용하는 유사한 예제는 JsonNode 평균 등급 예제를 참조하세요.
하위 요소의 JsonDocument 및 JsonElement를 검색하는 방법
JsonElement
에서 검색하려면 속성을 순차적으로 검색해야 하므로 검색 속도가 비교적 느립니다(예: TryGetProperty
를 사용하는 경우). System.Text.Json은 조회 시간이 아닌 초기 구문 분석 시간을 최소화하도록 설계되었습니다. 따라서 JsonDocument
개체를 검색할 때 성능을 최적화하려면 다음 방법을 사용하세요.
- 자체적으로 인덱싱 또는 루프를 수행하지 말고 기본 제공 열거자(EnumerateArray 및 EnumerateObject)를 사용합니다.
RootElement
를 사용하여 전체JsonDocument
의 모든 속성을 순차적으로 검색하지 마세요. 그 대신, 알려진 JSON 데이터 구조체를 기반으로 중첩된 JSON 개체를 검색합니다. 예를 들어 앞의 코드 예제에서는Grade
속성을 찾는 모든JsonElement
개체를 검색하는 대신Student
개체를 반복하고 각각에 대한Grade
값을 가져오면Student
개체에서Grade
속성을 찾습니다. 후자의 검색을 수행하면 동일한 데이터에 대해 불필요한 전달 과정이 발생합니다.
JsonElements 비교
하위 요소를 포함하여 두 JsonElement
개체를 같음으로 비교하려면 이 메서드를 JsonElement.DeepEquals(JsonElement, JsonElement) 사용합니다.
JsonElement left = JsonDocument.Parse("10e-3").RootElement;
JsonElement right = JsonDocument.Parse("0.01").RootElement;
bool equal = JsonElement.DeepEquals(left, right);
Console.WriteLine(equal); // True.
JsonDocument
를 사용하여 JSON 작성
다음 예제에서는 JsonDocument에서 JSON을 쓰는 방법을 보여줍니다.
string jsonString = File.ReadAllText(inputFileName);
var writerOptions = new JsonWriterOptions
{
Indented = true
};
var documentOptions = new JsonDocumentOptions
{
CommentHandling = JsonCommentHandling.Skip
};
using FileStream fs = File.Create(outputFileName);
using var writer = new Utf8JsonWriter(fs, options: writerOptions);
using JsonDocument document = JsonDocument.Parse(jsonString, documentOptions);
JsonElement root = document.RootElement;
if (root.ValueKind == JsonValueKind.Object)
{
writer.WriteStartObject();
}
else
{
return;
}
foreach (JsonProperty property in root.EnumerateObject())
{
property.WriteTo(writer);
}
writer.WriteEndObject();
writer.Flush();
Dim jsonString As String = File.ReadAllText(inputFileName)
Dim writerOptions As JsonWriterOptions = New JsonWriterOptions With {
.Indented = True
}
Dim documentOptions As JsonDocumentOptions = New JsonDocumentOptions With {
.CommentHandling = JsonCommentHandling.Skip
}
Dim fs As FileStream = File.Create(outputFileName)
Dim writer As Utf8JsonWriter = New Utf8JsonWriter(fs, options:=writerOptions)
Dim document As JsonDocument = JsonDocument.Parse(jsonString, documentOptions)
Dim root As JsonElement = document.RootElement
If root.ValueKind = JsonValueKind.[Object] Then
writer.WriteStartObject()
Else
Return
End If
For Each [property] As JsonProperty In root.EnumerateObject()
[property].WriteTo(writer)
Next
writer.WriteEndObject()
writer.Flush()
위의 코드는
- JSON 파일을 읽고,
JsonDocument
에 데이터를 로드하고, 서식 있는(보기 좋게 출력된) JSON을 파일에 씁니다. - JsonDocumentOptions를 사용하여 입력 JSON의 주석을 허용하지만 무시하도록 지정합니다.
- 완료되면 writer에서 Flush를 호출합니다. 삭제될 때 writer가 자동으로 플러시하도록 설정하는 방법도 있습니다.
다음은 예제 코드에서 처리할 JSON 입력의 예입니다.
{"Class Name": "Science","Teacher's Name": "Jane","Semester": "2019-01-01","Students": [{"Name": "John","Grade": 94.3},{"Name": "James","Grade": 81.0},{"Name": "Julia","Grade": 91.9},{"Name": "Jessica","Grade": 72.4},{"Name": "Johnathan"}],"Final": true}
결과는 다음과 같이 보기 좋게 출력된 JSON 출력입니다.
{
"Class Name": "Science",
"Teacher\u0027s Name": "Jane",
"Semester": "2019-01-01",
"Students": [
{
"Name": "John",
"Grade": 94.3
},
{
"Name": "James",
"Grade": 81.0
},
{
"Name": "Julia",
"Grade": 91.9
},
{
"Name": "Jessica",
"Grade": 72.4
},
{
"Name": "Johnathan"
}
],
"Final": true
}
JsonDocument는 IDisposable
JsonDocument
는 데이터의 메모리 내 보기를 풀링된 버퍼에 빌드합니다. 따라서 JsonDocument
형식은 IDisposable
을 구현하며 using
블록 내에서 사용해야 합니다.
수명 소유권 및 폐기 책임을 호출자에 양도하려는 경우에만 API에서 JsonDocument
를 반환하세요. 대부분의 시나리오에서는 이렇게 할 필요가 없습니다. 호출자가 전체 JSON 문서를 사용해야 하는 경우 JsonElement인 RootElement의 Clone을 반환하세요. 호출자가 JSON 문서 내의 특정 요소를 사용해야 하는 경우 해당 JsonElement의 Clone을 반환하세요. Clone
을 만들지 않고 RootElement
또는 하위 요소를 직접 반환하면 해당 소유권을 가진 JsonDocument
가 폐기된 후에 반환되는 JsonElement
에 호출자가 액세스할 수 없습니다.
다음은 Clone
을 만들어야 하는 예제입니다.
public JsonElement LookAndLoad(JsonElement source)
{
string json = File.ReadAllText(source.GetProperty("fileName").GetString());
using (JsonDocument doc = JsonDocument.Parse(json))
{
return doc.RootElement.Clone();
}
}
위의 코드에는 fileName
속성을 포함하는 JsonElement
가 필요합니다. 위의 코드는 JSON 파일을 열고 JsonDocument
를 만듭니다. 이 메서드는 호출자가 전체 문서를 사용하려 한다고 가정하고 RootElement
의 Clone
을 반환합니다.
JsonElement
를 수신하고 하위 요소를 반환하는 경우에는 하위 요소의 Clone
을 반환할 필요가 없습니다. 호출자는 전달된 JsonElement
가 속한 JsonDocument
를 활성 상태로 유지해야 합니다. 예를 들어:
public JsonElement ReturnFileName(JsonElement source)
{
return source.GetProperty("fileName");
}
JsonDocument
(JsonSerializerOptions
사용)
JsonSerializer
를 사용하여 JsonDocument
인스턴스를 직렬화하고 역직렬화할 수 있습니다. 그러나 JsonSerializer
를 사용하여 JsonDocument
인스턴스를 읽고 쓰기 위한 구현은 JsonDocument.ParseValue(Utf8JsonReader) 및 JsonDocument.WriteTo(Utf8JsonWriter)에 대한 래퍼입니다. 이 래퍼는 Utf8JsonReader
또는 Utf8JsonWriter
에 JsonSerializerOptions
(직렬 변환기 기능)를 전달하지 않습니다. 예를 들어 JsonSerializerOptions.DefaultIgnoreCondition을 WhenWritingNull로 설정하고 JsonSerializerOptions
를 사용하는 오버로드를 사용하여 JsonSerializer
를 호출하는 경우 null 속성은 무시되지 않습니다.
다음 예제에서는 JsonSerializerOptions
매개 변수를 사용하고 JsonDocument
인스턴스를 직렬화하는 메서드를 사용한 결과를 보여줍니다.
using System.Text.Json;
using System.Text.Json.Serialization;
namespace JsonDocumentWithJsonSerializerOptions;
public class Program
{
public static void Main()
{
Person person = new() { Name = "Nancy" };
// Default serialization - Address property included with null token.
// Output: {"Name":"Nancy","Address":null}
string personJsonWithNull = JsonSerializer.Serialize(person);
Console.WriteLine(personJsonWithNull);
// Serialize and ignore null properties - null Address property is omitted
// Output: {"Name":"Nancy"}
JsonSerializerOptions options = new()
{
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull
};
string personJsonWithoutNull = JsonSerializer.Serialize(person, options);
Console.WriteLine(personJsonWithoutNull);
// Ignore null properties doesn't work when serializing JsonDocument instance
// by using JsonSerializer.
// Output: {"Name":"Nancy","Address":null}
JsonDocument? personJsonDocument = JsonSerializer.Deserialize<JsonDocument>(personJsonWithNull);
personJsonWithNull = JsonSerializer.Serialize(personJsonDocument, options);
Console.WriteLine(personJsonWithNull);
}
}
public class Person
{
public string? Name { get; set; }
public string? Address { get; set; }
}
JsonSerializerOptions
의 기능이 필요한 경우 JsonDocument
대신 강력한 형식의 대상(예: 이 예제의 Person
클래스)과 함께 JsonSerializer
를 사용합니다.
참고 항목
.NET