Runtime: "๋™์ " ๋ฐ ์“ฐ๊ธฐ ๊ฐ€๋Šฅํ•œ DOM ์ง€์›

์— ๋งŒ๋“  2019๋…„ 05์›” 29์ผ  ยท  47์ฝ”๋ฉ˜ํŠธ  ยท  ์ถœ์ฒ˜: dotnet/runtime

JsonSerializer.Parse(String, Type, JsonSerializerOptions) ๋Š” ๋™์  ExpandoObject ๋ฐ˜ํ™˜ ์œ ํ˜•์„ ์ง€์›ํ•ฉ๋‹ˆ๊นŒ?

์ด ๊ฐ™์€:
dynamic p = JsonSerializer.Parse(json, typeof(ExpandoObject));

area-System.Text.Json enhancement json-functionality-doc

๊ฐ€์žฅ ์œ ์šฉํ•œ ๋Œ“๊ธ€

์ด์— ๋Œ€ํ•œ ์‚ฌ์šฉ ์‚ฌ๋ก€๋„ ์žˆ์Šต๋‹ˆ๋‹ค. HttpClient๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ REST API๋ฅผ ํ˜ธ์ถœํ•˜๊ณ  ์‘๋‹ต์—์„œ ๋‹จ์ผ ์†์„ฑ์„ ๊ฒ€์ƒ‰ํ•˜๊ณ  ์‹ถ์Šต๋‹ˆ๋‹ค. ์‘๋‹ต์„ ๊ตฌ๋ฌธ ๋ถ„์„ํ•˜๊ธฐ ์œ„ํ•ด ์ „์šฉ ํด๋ž˜์Šค๋ฅผ ๋งŒ๋“ค๊ณ  ์‹ถ์ง€ ์•Š์Šต๋‹ˆ๋‹ค... JSON.NET์„ ์‚ฌ์šฉํ•˜๋ฉด "๋™์ "์„ ์‚ฌ์šฉํ•˜๊ณ  ์„ ํƒํ•œ ์†์„ฑ์— ์•ก์„ธ์Šคํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋ชจ๋“  47 ๋Œ“๊ธ€

์•„๋‹ˆ์š”, ์ด ๊ธฐ๋Šฅ์€ ํ˜„์žฌ ์ง€์›๋˜์ง€ ์•Š์ง€๋งŒ vNext์— ๋Œ€ํ•ด ๊ณ ๋ คํ•ด์•ผ ํ•  ์‚ฌํ•ญ์ž…๋‹ˆ๋‹ค. ๊ธฐ๋Šฅ ์š”์ฒญ์— ๋™๊ธฐ๋ฅผ ๋ถ€์—ฌํ•˜๋Š” ์‚ฌ์šฉ ์˜ˆ๊ฐ€ ์žˆ์Šต๋‹ˆ๊นŒ?

๋ฏธ๋ž˜๋กœ ํ‘œ์‹œ.

System.NotSupportedException : The collection type 'System.Dynamic.ExpandoObject' is not supported.

@ahsonkhan GraphQL์ด ์ข‹์€ ์˜ˆ์ž…๋‹ˆ๋‹ค.

์‚ฌ์–‘์€ JSON์„ ๊ถŒ์žฅํ•˜์ง€๋งŒ ์‘๋‹ต์˜ ํŠน์ • ์ง๋ ฌํ™”์™€ ๊ด€๋ จ์ด ์—†์Šต๋‹ˆ๋‹ค.
์ด๊ฒƒ์€ ์‘๋‹ต์˜ "๋ฐ์ดํ„ฐ" ํ•„๋“œ๊ฐ€ ๋™์  ์œ ํ˜•์ž„์„ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค. ์œ ์ถ”ํ•  ์ˆ˜ ์—†๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค.
ExpandoObject๊ฐ€ ์—†์œผ๋ฉด ์—ญ์ง๋ ฌํ™”๋Š” JSON ์ƒ์„ฑ ์œ ํ˜•์„ ๋™์ ์œผ๋กœ ๋งŒ๋“ญ๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ ๋™์ ์ด JToken์ด๋ผ๋Š” ์‚ฌ์‹ค์„ ์•Œ๊ณ  ์ถ”์ƒ ๋™์  "๋ฐ์ดํ„ฐ"์— ์•ก์„ธ์Šคํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

ExpandoObject๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๊ณตํ†ต ๊ฐœ์ฒด์ฒ˜๋Ÿผ ๋™์  "๋ฐ์ดํ„ฐ"์— ๋Œ€ํ•œ ์•ก์„ธ์Šค๋ฅผ ๊ฐ•์ œํ•  ์ˆ˜ ์žˆ๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค.

@ahsonkhan ๋˜ ๋‹ค๋ฅธ ์˜ˆ๋Š” ์šฐ๋ฆฌ ํ”„๋กœ์ ํŠธ์˜ Configuration Service์ž…๋‹ˆ๋‹ค. MongoDB์—์„œ ์ปฌ๋ ‰์…˜์„ ์ƒ์„ฑํ•˜๋Š” REST ๋์ ๊ณผ ๊ฐ™์€ ์ปฌ๋ ‰์…˜์„ ๋…ธ์ถœํ•ฉ๋‹ˆ๋‹ค(๋‹จ์ˆœํ•œ ๋”๋ฏธ REST ๋ž˜ํผ๊ฐ€ ์•„๋‹ˆ๋ฉฐ ๋‚˜๋จธ์ง€ ์ปฌ๋ ‰์…˜๊ณผ mongo ์ปฌ๋ ‰์…˜์—๋Š” ์ •ํ™•ํ•œ 1-1 ๋งคํ•‘์ด ์—†์œผ๋ฉฐ ํŠน์ • ๊ทœ์น™๋„ ์ง€์ •ํ•ฉ๋‹ˆ๋‹ค).

๋”ฐ๋ผ์„œ ์šฐ๋ฆฌ ํ”„๋กœ์ ํŠธ์—์„œ๋Š” ๋™์ /ExpandoObject ์ง€์›์ด ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค.

๋‹ค๋ฅธ ๋งˆ์ดํฌ๋กœ์„œ๋น„์Šค์—์„œ๋„ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.

์šฐ๋ฆฌ๋Š” ๋˜ํ•œ ์ด ํ•œ๊ณ„์— ๋ถ€๋”ช์ณค์Šต๋‹ˆ๋‹ค. ์šฐ๋ฆฌ์˜ ์‚ฌ์šฉ ์‚ฌ๋ก€๋Š” json ์ง๋ ฌํ™” ์ „์— ๋™์  ๊ฐ์ฒด๋ฅผ ์ ์ง„์ ์œผ๋กœ ๊ตฌ์ถ•ํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๋” ์„ฑ์ˆ™ํ•œ Json.NET ์ง๋ ฌ ๋ณ€ํ™˜๊ธฐ๋กœ ๋Œ์•„๊ฐ”์Šต๋‹ˆ๋‹ค.

์–˜๋“ค ์•„

์ง€๊ธˆ ์‚ฐ์ฑ…์€ ๋ฌด์—‡์ž…๋‹ˆ๊นŒ?
์–ด๋Š ๊ฒƒ์„ ์‚ฌ์šฉํ•  ๊ฒƒ์ธ์ง€ ๊ตฌ์„ฑํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๊นŒ?
@SidShety ๋‹˜ ์ด ๋ง์”€ํ•˜์‹  ๋‚ด์šฉ์ด ์ข€ ๋” ์„ฑ์ˆ™ํ•œ ๊ฒƒ์œผ๋กœ ๋Œ์•„๊ฐ”์Šต๋‹ˆ๋‹ค. ์„ค๋ช…ํ•ด ์ฃผ์‹œ๊ฒ ์Šต๋‹ˆ๊นŒ?

@MickeyReznikov : https://stackoverflow.com/questions/15455304/deserialize-a-property-as-an-expandoobject-using-json-net ๋˜๋Š” Google "json.net expandoobject" ์ฐธ์กฐ

@MickeyReznikov , ์งˆ๋ฌธ์— ๋Œ€ํ•œ ๋‹ต๋ณ€์ด ๋˜์—ˆ์Šต๋‹ˆ๊นŒ? @SidShetye ๋Š” ์ธ๋ฐ•์Šค ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ(System.Text.Json)๊ฐ€ ์•„์ง ๋™์  ๊ฐœ์ฒด๋ฅผ ์ง€์›ํ•˜์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์— ๋™์  ๊ฐœ์ฒด๋ฅผ ์ง๋ ฌํ™”ํ•˜๊ธฐ ์œ„ํ•ด Newtonsoft.Json ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์„ ์˜๋ฏธํ–ˆ๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. asp.net ์•ฑ์˜ ๊ฒฝ์šฐ ๋‹ค์‹œ AddNewtonsoftJson์œผ๋กœ ๊ตฌ์„ฑํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

https://docs.microsoft.com/en-us/aspnet/core/migration/22-to-30?view=aspnetcore-3.0&tabs=visual-studio#jsonnet -support๋ฅผ ์ฐธ์กฐ

์ด์— ๋Œ€ํ•œ ์‚ฌ์šฉ ์‚ฌ๋ก€๋„ ์žˆ์Šต๋‹ˆ๋‹ค. HttpClient๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ REST API๋ฅผ ํ˜ธ์ถœํ•˜๊ณ  ์‘๋‹ต์—์„œ ๋‹จ์ผ ์†์„ฑ์„ ๊ฒ€์ƒ‰ํ•˜๊ณ  ์‹ถ์Šต๋‹ˆ๋‹ค. ์‘๋‹ต์„ ๊ตฌ๋ฌธ ๋ถ„์„ํ•˜๊ธฐ ์œ„ํ•ด ์ „์šฉ ํด๋ž˜์Šค๋ฅผ ๋งŒ๋“ค๊ณ  ์‹ถ์ง€ ์•Š์Šต๋‹ˆ๋‹ค... JSON.NET์„ ์‚ฌ์šฉํ•˜๋ฉด "๋™์ "์„ ์‚ฌ์šฉํ•˜๊ณ  ์„ ํƒํ•œ ์†์„ฑ์— ์•ก์„ธ์Šคํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

https://github.com/dotnet/corefx/issues/41472 ์—์„œ @ghost1372 :

์•ˆ๋…•ํ•˜์„ธ์š” ์ด๊ณณ์ด ์ด ์งˆ๋ฌธ์„ ํ•˜๊ธฐ์— ์ข‹์€ ๊ณณ์ด๊ธฐ๋ฅผ ๋ฐ”๋ž๋‹ˆ๋‹ค
๋™์  ๊ฐœ์ฒด๋ฅผ ์—ญ์ง๋ ฌํ™”ํ•  ์ˆ˜ ์—†๋Š” ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค.
์ด ์ฝ”๋“œ๋ฅผ ์‚ฌ์šฉํ–ˆ์ง€๋งŒ ์ž‘๋™ํ•˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค. ์ด ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ๋Š” ๋ฐฉ๋ฒ•์ด ์žˆ์Šต๋‹ˆ๊นŒ?

var objList = System.Text.Json.JsonSerializer.Deserialize<List<dynamic>>(json);

๋งŽ์€ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์—์„œ ์ €์žฅ ํ”„๋กœ์‹œ์ €์˜ ๋ฐ์ดํ„ฐ ํ•„๋“œ๋ฅผ ์ œ์–ดํ•˜๊ณ  jquery.jtable์„ ์‚ฌ์šฉํ•˜์—ฌ ๋ชฉ๋ก ๋ฐ ๊ฒ€์ƒ‰ ๋ชฉ๋ก ํŽ˜์ด์ง€๋ฅผ ๋™์ ์œผ๋กœ ๋ Œ๋”๋งํ•ฉ๋‹ˆ๋‹ค.

ExpandoObject์— ๋Œ€ํ•œ JsonSerializer ๊ธฐ๋ณธ ์ œ๊ณต ์ง€์›์ด ์—†์œผ๋ฉด dotnet ํ•ต์‹ฌ ๊ธฐ๋ณธ ์ œ๊ณต Json ์ง๋ ฌํ™”๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.

@estiller ์™€ @SidShetye๊ฐ€ ์ด๋ฏธ ์–ธ๊ธ‰ํ•œ ๊ฒƒ๊ณผ ๋™์ผํ•œ ์‚ฌ์šฉ ์‚ฌ๋ก€๋ฅผ ๊ณต์œ ํ•ฉ๋‹ˆ๋‹ค.
๊ทธ๋™์•ˆ Json.NET์œผ๋กœ ๋‹ค์‹œ ์ „ํ™˜ํ•ด์•ผ ํ–ˆ์Šต๋‹ˆ๋‹ค.

๋ฏธ๋ž˜ ๋ณด๋‹ค _์ง€๊ธˆ_์— ๋” ๊ฐ€๊นŒ์šด ์ด์ •ํ‘œ๋ฅผ ๊ฐ€์งˆ ์ˆ˜ ์žˆ์Šต๋‹ˆ๊นŒ? ๐Ÿค”

ExpandoObject๋Š” ์˜ค๋žซ๋™์•ˆ BCL์— ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค.

ExpandoObject์— ๋Œ€ํ•œ ๋Œ€์•ˆ์ด ์žˆ์Šต๋‹ˆ๊นŒ?

@fatihyildizhan ์•„๋‹ˆ์š” ๋Œ€์•ˆ์ด ์—†์Šต๋‹ˆ๋‹ค.

๊ทธ๋Ÿฌ๋‚˜ ์šฐ๋ฆฌ๋Š” ์ž์ฒด ExpandoObject ๋ณ€ํ™˜๊ธฐ๋ฅผ ์ž‘์„ฑํ–ˆ์Šต๋‹ˆ๋‹ค. ์ด ๊ธฐ์‚ฌ์—์„œ ํžŒํŠธ๋ฅผ ์–ป์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ASP.NET Core 3.0: ์ƒˆ System.Text.Json์— ๋Œ€ํ•œ ์‚ฌ์šฉ์ž ์ง€์ • JsonConverter

์ง๋ ฌํ™”๋งŒ ํ•„์š”ํ•˜๋ฏ€๋กœ ์ง๋ ฌํ™”๋งŒ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค.

๋‚˜๋Š” ์ด๊ฒƒ์ด ์•„์ง ์ง€์›๋˜์ง€ ์•Š๋Š”๋‹ค๋Š” ๊ฒƒ์— ๋†€๋ž๋‹ค.

์ด๊ฒƒ์„ 5.0์œผ๋กœ ์˜ฎ๊ธฐ์‹ญ์‹œ์˜ค.

5.0์œผ๋กœ ์ด๋™ํ•˜์‹œ๊ฒ ์Šต๋‹ˆ๊นŒ? ์ตœ์†Œ 1๋…„์€ ๊ธฐ๋‹ค๋ ค์•ผ ํ•œ๋‹ค๋Š” ๋œป์ธ๊ฐ€์š”? JSON.Net์œผ๋กœ ๋Œ์•„๊ฐ€์‹ญ์‹œ์˜ค.

5.0? ์™€์šฐ, ํ™•์‹คํžˆ ์งœ์ฆ๋‚ฉ๋‹ˆ๋‹ค.

์ผ์‹œ์ ์ธ ๋ฌธ์ œ ํ•ด๊ฒฐ์„ ์œ„ํ•ด ์‚ฌ์šฉ์ž ์ง€์ • ๋ณ€ํ™˜๊ธฐ์™€ ํ•จ๊ป˜ JsonDocument๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์ง€๋งŒ IDisposable์ž…๋‹ˆ๋‹ค.

public sealed class EventObject
    {
        [JsonPropertyName("id")]
        public long Id
        {
            get; set;
        }

        [JsonPropertyName("eventData")]
        [JsonConverter(typeof(JsonDocumentConverter))]
        public System.Text.Json.JsonDocument EventData
        {
            get; set;
        }
    }

    internal sealed class JsonDocumentConverter
        : JsonConverter<System.Text.Json.JsonDocument>
    {
        public override JsonDocument Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
        {
            return JsonDocument.ParseValue(ref reader);
        }

        public override void Write(Utf8JsonWriter writer, JsonDocument value, JsonSerializerOptions options)
        {
            value.WriteTo(writer);
        }
    }

System.Text.Json์ด ์žˆ๋Š” ๊ฒฝ์šฐ ๋” ์ด์ƒ ๋‹ค์Œ POST ์ž‘์—…์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.

[HttpPost]
public async Task<IActionResult> SubmitAsync(dynamic model)

๋Œ€์‹  ๋‹ค์Œ ๋ฐฉ๋ฒ•์„ ์‚ฌ์šฉํ•ด์•ผ ํ–ˆ์ง€๋งŒ ๋‹ค์šด์ŠคํŠธ๋ฆผ ๋ฐฑ์—”๋“œ ์ฝ”๋“œ์—์„œ '๋ชจ๋ธ'์„ ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•์€ ์—†์—ˆ์Šต๋‹ˆ๋‹ค.

[HttpPost]
public async Task<IActionResult> SubmitAsync(JsonElement model)

'๋ชจ๋ธ'์€ ๋ณต์žกํ•œ ๊ฐœ์ฒด์ด๋ฉฐ ๊ฐœ์ฒด ๋ฐ/๋˜๋Š” ๊ธฐํƒ€ ์ค‘์ฒฉ๋œ ๋ณตํ•ฉ ๊ฐœ์ฒด์˜ ์ปฌ๋ ‰์…˜์„ ํฌํ•จํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ฒฐ๋ก ์„ ๋‚ด๋ฆด ์ˆ˜ ์žˆ์œผ๋ ค๋ฉด dynamic ์ค‘ ๊ฐ์ฒด JsonElement , ์šฐ๋ฆฌ๋Š” model.GetRawText์„ (์ „ํ™”) ๋ฐ Newtonsoft ๋™์  ๊ฐ์ฒด๋กœ ๋””์ฝ”๋”ฉํ•ด์•ผํ–ˆ๋‹ค. ์ด ์—ฐ์Šต์˜ ์ฃผ์š” ๋ชฉ์ ์€ ํ”„๋กœ์ ํŠธ์—์„œ Newtonsoft.json์„ ํ•ด์ œํ•˜๋Š” ๊ฒƒ์ด๊ธฐ ๋•Œ๋ฌธ์— ์ด ๋ฐฉ๋ฒ•์€ ์›ํ•˜๋Š” ๋ฐฉ๋ฒ•์ด ์•„๋‹™๋‹ˆ๋‹ค.

์ด ํ‹ฐ์ผ“/๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๋Š” ๊ฒƒ์ด ์šฐ๋ฆฌ๊ฐ€ ๊ฒช๊ณ  ์žˆ๋Š” ๋ฌธ์ œ์— ๋Œ€ํ•œ ์ˆ˜์ •์„ ์˜๋ฏธํ•œ๋‹ค๊ณ  ๊ฐ€์ •ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๊นŒ? ์กฐ๊ธˆ ์‹œ๊ธ‰ํ•œ ๋ฌธ์ œ์ธ ๊ฒƒ ๊ฐ™์€๋ฐ, ์ข€ ๋” ๋นจ๋ฆฌ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ์„๊นŒ์š”?

/cc @ahsonkhan @terrajobst

.NET Core 3.0 JsonSerializer.Deserialize๋ฅผ ๋™์  ๊ฐœ์ฒด๋กœ

ExpandoObject์— ๋Œ€ํ•œ JsonSerializer ์ง€์›(์ž„์‹œ ์กฐ์น˜)
๋‚˜๋Š” ์ดˆ๋ณด์ž, ๋งŽ์€ ๊ณณ์ด ์™„๋ฒฝํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์ˆ˜์ •ํ•˜๋Š” ๋ชจ๋“  ์‚ฌ๋žŒ์„ ํ™˜์˜ํ•ฉ๋‹ˆ๋‹ค
.net Core3 ์ง€์› ์•ˆ ํ•จ

Json ๋ณ€ํ™˜๊ธฐ ์ถ”๊ฐ€

๋‹ค์Œ์„ ์‚ฌ์šฉํ•˜์—ฌ ์ถ”๊ฐ€:

  • System.Text.Json ์‚ฌ์šฉ;
  • System.Text.Json.Serialization ์‚ฌ์šฉ;

```C#
///


/// ์ž„์‹œ ๋™์  ๋ณ€ํ™˜๊ธฐ
/// ์ž‘์„ฑ์ž:[email protected]
///

๊ณต๊ฐœ ํด๋ž˜์Šค DynamicJsonConverter : JsonConverter
{
๊ณต๊ฐœ ์žฌ์ •์˜ ๋™์  ์ฝ๊ธฐ(์ฐธ์กฐ Utf8JsonReader ๋ฆฌ๋”,
typeToConvert๋ฅผ ์ž…๋ ฅํ•˜๊ณ ,
JsonSerializerOptions ์˜ต์…˜)
{

        if (reader.TokenType == JsonTokenType.True)
        {
            return true;
        }

        if (reader.TokenType == JsonTokenType.False)
        {
            return false;
        }

        if (reader.TokenType == JsonTokenType.Number)
        {
            if (reader.TryGetInt64(out long l))
            {
                return l;
            }

            return reader.GetDouble();
        }

        if (reader.TokenType == JsonTokenType.String)
        {
            if (reader.TryGetDateTime(out DateTime datetime))
            {
                return datetime;
            }

            return reader.GetString();
        }

        if (reader.TokenType == JsonTokenType.StartObject)
        {
            using JsonDocument documentV = JsonDocument.ParseValue(ref reader);
            return ReadObject(documentV.RootElement);
        }
        // Use JsonElement as fallback.
        // Newtonsoft uses JArray or JObject.
        JsonDocument document = JsonDocument.ParseValue(ref reader);
        return document.RootElement.Clone();
    }

    private object ReadObject(JsonElement jsonElement)
    {
        IDictionary<string, object> expandoObject = new ExpandoObject();
        foreach (var obj in jsonElement.EnumerateObject())
        {
            var k = obj.Name;
            var value = ReadValue(obj.Value);
            expandoObject[k] = value;
        }
        return expandoObject;
    }
    private object? ReadValue(JsonElement jsonElement)
    {
        object? result = null;
        switch (jsonElement.ValueKind)
        {
            case JsonValueKind.Object:
                result = ReadObject(jsonElement);
                break;
            case JsonValueKind.Array:
                result = ReadList(jsonElement);
                break;
            case JsonValueKind.String:
                //TODO: Missing Datetime&Bytes Convert
                result = jsonElement.GetString();
                break;
            case JsonValueKind.Number:
                //TODO: more num type
                result = 0;
                if (jsonElement.TryGetInt64(out long l))
                {
                    result = l;
                }
                break;
            case JsonValueKind.True:
                result = true;
                break;
            case JsonValueKind.False:
                result = false;
                break;
            case JsonValueKind.Undefined:
            case JsonValueKind.Null:
                result = null;
                break;
            default:
                throw new ArgumentOutOfRangeException();
        }
        return result;
    }

    private object? ReadList(JsonElement jsonElement)
    {
        IList<object?> list = new List<object?>();
        foreach (var item in jsonElement.EnumerateArray())
        {
            list.Add(ReadValue(item));
        }
        return list.Count == 0 ? null : list;
    }
    public override void Write(Utf8JsonWriter writer,
        object value,
        JsonSerializerOptions options)
    {
       // writer.WriteStringValue(value.ToString());
    }
}
## How to Use?

```C#
var serializerOptions = new JsonSerializerOptions
{
    Converters = { new DynamicJsonConverter() }
};
return JsonSerializer.Deserialize<dynamic>("{OK:"200"}", serializerOptions);

@tchivs , ๊ท€ํ•˜์˜ ์†”๋ฃจ์…˜์ด ์ €์—๊ฒŒ
c# var serializerOptions = new JsonSerializerOptions(); serializerOptions.Converters.Add(new DynamicJsonConverter()); return JsonSerializer.Deserialize<dynamic>("{OK:"200"}", serializerOptions);

JsonElement ์œ ํ˜•์„ ์‚ฌ์šฉํ•ด ๋ณด์‹ญ์‹œ์˜ค.

public JsonElement MyProperty {get; set;}

@tchivs , ์ฝ”๋“œ๋ฅผ ์ผ๋ถ€ ์ˆ˜์ •ํ–ˆ์Šต๋‹ˆ๋‹ค. EDennis.DynamicDeserialization ์— ์ฝ”๋“œ(์ƒ˜ํ”Œ ์ฝ˜์†” ํ”„๋กœ์ ํŠธ์— ์žˆ์Œ)๋ฅผ ๊ฒŒ์‹œํ–ˆ์Šต๋‹ˆ๋‹ค.

๋” ๋ณต์žกํ•œ ๊ฐœ์ฒด์™€ ๋‹ค์–‘ํ•œ ์‹œ๋‚˜๋ฆฌ์˜ค์—์„œ ์ด ์ ‘๊ทผ ๋ฐฉ์‹์„ ํ…Œ์ŠคํŠธํ•  ๊ฒƒ์ž…๋‹ˆ๋‹ค(์˜ˆ: ๊ธฐ์กด์˜ ์™„์ „ํ•œ ํ˜•์‹์˜ EF Core ์—”ํ„ฐํ‹ฐ๋ฅผ ํŒจ์น˜ํ•˜๋Š” ๋ฐ ์‚ฌ์šฉ๋˜๋Š” ๋™์  ๊ฐœ์ฒด์˜ ์—ญ์ง๋ ฌํ™”, ํ…Œ์ŠคํŠธ ์‚ฌ๋ก€๋ฅผ ์œ„ํ•œ json ๊ฐœ์ฒด ๋ฐ ๋ฐฐ์—ด์˜ โ€‹โ€‹์—ญ์ง๋ ฌํ™”). ์ด ๊ธฐ๋Šฅ์ด ์œ ์šฉํ•˜๊ฑฐ๋‚˜ ๋ฌธ์ œ๊ฐ€ ์žˆ๋Š” ๊ฒฝ์šฐ ์•Œ๋ ค์ฃผ์‹ญ์‹œ์˜ค.

์ปค๋ฎค๋‹ˆํ‹ฐ ํ•ด๊ฒฐ ๋ฐฉ๋ฒ•์— ๊ฐ์‚ฌ๋“œ๋ฆฝ๋‹ˆ๋‹ค. ๋งˆ์ดํฌ๋กœ์†Œํ”„ํŠธ๊ฐ€ ํ•ฉ๋ฆฌ์ ์ธ ์‹œ๊ฐ„ ๋‚ด์— ์ด ๊ธฐ๋Šฅ์„ ๋‚ด๋†“์„ ์ˆ˜ ์—†๋‹ค๋Š” ๊ฒƒ์€ ๋†€๋ผ์šด ์ผ์ž…๋‹ˆ๋‹ค. ์ผ์ข…์˜ ๋™์  ๊ฐœ์ฒด ์—†์ด GraphQL ์‘๋‹ต์œผ๋กœ ์ž‘์—…ํ•˜๋ฉด ์žฅํ™ฉํ•˜๊ณ  ๋ณด๊ธฐ ํ‰ํ•œ ์ฝ”๋“œ๊ฐ€ ๋งŽ์ด ์ƒ์„ฑ๋ฉ๋‹ˆ๋‹ค. ๋˜๋Š” ๊นŠ์ด ์ค‘์ฒฉ๋œ ์†์„ฑ์˜ ์กด์žฌ ์—ฌ๋ถ€๋ฅผ ํ™•์ธํ•˜๋Š” ๊ฒƒ๋งŒ์œผ๋กœ๋„ ์ถฉ๋ถ„ํ•ฉ๋‹ˆ๋‹ค.

๋‚˜๋Š” ์ฃผ์„ ์Šค๋ ˆ๋“œ๋ฅผ ์ฝ์—ˆ๊ณ  ๋Œ€๋ถ€๋ถ„์€ ์—ญ์ง๋ ฌํ™”์— ์ค‘์ ์„ ๋‘๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ๋™์  ๊ฐœ์ฒด์˜ ์ง๋ ฌํ™”๋„ ๋ถ„๋ช…ํžˆ ์ž๋™์œผ๋กœ "์‹คํŒจ"ํ•˜๋Š” ๋ฌธ์ œ์— ์ง๋ฉดํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ๋‚ด ์‹œ๋‚˜๋ฆฌ์˜ค๋ฅผ ์žฌํ˜„ํ•˜๊ธฐ ์œ„ํ•ด ๋‹ค์Œ๊ณผ ๊ฐ™์€ ์ตœ์†Œํ•œ์˜ ์žฌํ˜„์„ ์ƒ๊ฐํ•ด ๋ƒˆ์Šต๋‹ˆ๋‹ค.

using System;
using System.Collections.Generic;
using System.Dynamic;
using System.Text.Json;

namespace SampleConsoleApp
{
    class Program
    {
        static void Main(string[] args)
        {
            dynamic d = new CustomDynamicObject();
            d.AProperty = 10;
            var s = JsonSerializer.Serialize(d);

            Console.WriteLine(s);
            Console.Read();
        }
    }

    class CustomDynamicObject : DynamicObject 
    {
        private readonly IDictionary<string, object> properties = new Dictionary<string, object>();

        public override bool TryGetMember(GetMemberBinder binder, out object result) => properties.TryGetValue(binder.Name, out result);

        public override bool TrySetMember(SetMemberBinder binder, object value)
        {
            properties[binder.Name] = value;
            return true;
        }

        public override IEnumerable<string> GetDynamicMemberNames()
        {
            foreach (var item in properties.Keys)
            {
                yield return item;
            }
        }
    }
}

s ์‹คํ–‰ ์‹œ {} ์ด๋ฏ€๋กœ ์ง๋ ฌํ™”๋Š” ์‹คํŒจํ•˜์ง€ ์•Š์ง€๋งŒ ๋นˆ json ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค.

์ด๊ฒƒ์ด ์˜ฌ๋ฐ”๋ฅธ ๋ฌธ์ œ์ž…๋‹ˆ๊นŒ? ์•„๋‹ˆ๋ฉด ๋‹ค๋ฅธ ๊ฒƒ์„ ์˜ฌ๋ฆฌ๊ฑฐ๋‚˜ ํŒ”๋กœ์šฐํ•ด์•ผ ํ•˜๋‚˜์š”?

์ด๊ฒƒ์ด ์˜ฌ๋ฐ”๋ฅธ ๋ฌธ์ œ์ž…๋‹ˆ๊นŒ? ์•„๋‹ˆ๋ฉด ๋‹ค๋ฅธ ๊ฒƒ์„ ์˜ฌ๋ฆฌ๊ฑฐ๋‚˜ ํŒ”๋กœ์šฐํ•ด์•ผ ํ•˜๋‚˜์š”?

์ด๊ฒƒ์€ ์˜ฌ๋ฐ”๋ฅธ ๋ฌธ์ œ์ž…๋‹ˆ๋‹ค. ๋™์ผํ•œ ๊ธฐ๋Šฅ์˜ ๋‘ ์ ˆ๋ฐ˜์— ๋Œ€ํ•ด ํ•˜๋‚˜๋ฅผ ์—ด ํ•„์š”๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค. ์ด ๋ฌธ์ œ๋Š” expando ๊ฐœ์ฒด์— ๋Œ€ํ•œ ์ง€์› ์ถ”๊ฐ€์— ๊ด€ํ•œ ๊ฒƒ์ž…๋‹ˆ๋‹ค(์–‘์ชฝ ๋ชจ๋‘ ์ง๋ ฌํ™” ๋ฐ ์—ญ์ง๋ ฌํ™”๋ฅผ ์˜๋ฏธํ•จ).

์ €๋Š” ์˜ค๋Š˜ ์ด ๋ฌธ์ œ๋ฅผ ๋งŒ๋‚ฌ์Šต๋‹ˆ๋‹ค. JsonElement ํ๊ธฐ๋œ JsonDocument ์— ์˜์กดํ•˜์ง€ ์•Š์œผ๋ฉด JsonElement ๊ฐ€ ์ž˜ ์ž‘๋™ํ•œ๋‹ค๊ณ  ๋งํ•˜๊ณ  ์‹ถ์—ˆ์Šต๋‹ˆ๋‹ค. ์ด ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•  ์ˆ˜ ์žˆ๋Š” ํ•œ ๊ฐ€์ง€ ๋ฐฉ๋ฒ•์€ JsonDocument ๋Œ€ํ•œ ์†Œ๋ฉธ์ž๋ฅผ ๊ตฌํ˜„ํ•˜์—ฌ ๋ชจ๋“  JsonElement ๊ฐœ์ฒด๊ฐ€ ์ˆ˜์ง‘๋˜๋ฉด ํ๊ธฐ๋ฅผ ๋‚˜์ค‘์— ์—ฐ๊ธฐํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

๋˜ํ•œ ๋™์  ๊ฐœ์ฒด๊ฐ€ ํ•„์š”ํ–ˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ์•„์ง ๊ตฌํ˜„๋˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค. ๋‚ด ํ•ด๊ฒฐ์ฑ…์€ ์‚ฌ์ „์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ์—ˆ์Šต๋‹ˆ๋‹ค.
JsonSerializer.Deserialize<Dictionary<string, string>>(response)
๊ทธ๋Ÿฐ ๋‹ค์Œ ํ•„์š”ํ•œ ํ‚ค๋ฅผ ์ฐพ์Šต๋‹ˆ๋‹ค. :)

์ œ ์ •์‹ ์„ ์œ„ํ•ด - ๋ฌธ์ œ๊ฐ€ 5.0, ํŠนํžˆ ExpandoObject ์ง€์› ๋˜๋Š” ๋™์  ๊ฐœ์ฒด๋กœ ์—ญ์ง๋ ฌํ™”ํ•˜๋Š” ๊ธฐ๋Šฅ์— ๋Œ€ํ•œ ๋ฒ”์œ„์ž…๋‹ˆ๊นŒ? ์—ฌ๊ธฐ์˜ ๋Œ€ํ™”๊ฐ€ ๋ชจ๋‘ ๋ฌธ์ œ ์ œ๋ชฉ๊ณผ ์ผ์น˜ํ•˜์ง€ ์•Š๋Š” ๊ฒƒ ๊ฐ™์œผ๋ฉฐ ๋‚˜๋Š” ํ™•์‹คํžˆ ํ›„์ž๊ฐ€ ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค. ์ œ ๊ฒฝ์šฐ์—๋Š” ์ค‘์ฒฉ๋œ ๋™์ , ํŠนํžˆ List<Dictionary<string, dynamic>> ์—ญ์ง๋ ฌํ™”ํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ์ง€๊ธˆ์€ Newtonsoft๋กœ ๋‹ค์‹œ ์ „ํ™˜ํ–ˆ์Šต๋‹ˆ๋‹ค.

@tchivs ์œ ์šฉํ•œ ์ฝ”๋“œ์˜ ์ผ๋ถ€ C# 8 ๊ตฌ๋ฌธ ์„คํƒ• ๋ชจ๋“œ๋ฅผ ๊ณต์œ ํ•˜๊ณ  ์‹ถ์—ˆ์Šต๋‹ˆ๋‹ค. :)

/// <summary>
/// Temp Dynamic Converter with c# 8
/// by:[email protected]
/// </summary>
public class DynamicJsonConverter : JsonConverter<dynamic>
{
    public override dynamic Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
        => reader.TokenType switch
        {
            JsonTokenType.True => true,
            JsonTokenType.False => false,
            JsonTokenType.Number => reader.TryGetInt64(out long l) ? 1 : reader.GetDouble(),
            JsonTokenType.String => reader.TryGetDateTime(out DateTime datetime) ? datetime.ToString() : reader.GetString(),
            JsonTokenType.StartObject =>  ReadObject(JsonDocument.ParseValue(ref reader).RootElement),
            // Use JsonElement as fallback.
                _ =>JsonDocument.ParseValue(ref reader).RootElement.Clone()
        };

    private object ReadObject(JsonElement jsonElement)
    {
        IDictionary<string, object> expandoObject = new ExpandoObject();
        foreach (var obj in jsonElement.EnumerateObject())
        {
            var k = obj.Name;
            var value = ReadValue(obj.Value);
            expandoObject[k] = value;
        }
        return expandoObject;
    }
    private object? ReadValue(JsonElement jsonElement)
        =>
         jsonElement.ValueKind switch
        {
            JsonValueKind.Object => ReadObject(jsonElement),
            JsonValueKind.Array => ReadList(jsonElement),
            JsonValueKind.String => jsonElement.GetString(),
            JsonValueKind.Number =>  jsonElement.TryGetInt64(out long l) ? 1 :0,
            JsonValueKind.True => true,
            JsonValueKind.False =>false,
            JsonValueKind.Undefined => null,
            JsonValueKind.Null => null,
                _ => throw new ArgumentOutOfRangeException()
        };

    private object? ReadList(JsonElement jsonElement)
    {
        var list = new List<object?>();
        jsonElement.EnumerateArray().ToList().ForEach(j => list.Add(ReadValue(j)));
        return list.Count == 0 ? null : list;
    }

    public override void Write(Utf8JsonWriter writer,
        object value,
        JsonSerializerOptions options)
        {
        // writer.WriteStringValue(value.ToString());
        }
}

@rs38 ์—ฌ๊ธฐ ์ฝ”๋“œ์— ๊ฐ์‚ฌ๋“œ๋ฆฝ๋‹ˆ๋‹ค. ์ •ํ™•ํžˆ ์ œ๊ฐ€ ํ•„์š”๋กœ ํ•˜๋Š” ๊ฒƒ์ด์—ˆ์Šต๋‹ˆ๋‹ค. ๋งค์šฐ ๋ฏธ๋ฌ˜ํ•˜์ง€๋งŒ ์ค‘์š”ํ•œ ๋ณ€ํ™”๊ฐ€ ํ•„์š”ํ•จ์„ ์ง€์ ํ•˜๊ณ  ์‹ถ์—ˆ์Šต๋‹ˆ๋‹ค. "์ˆซ์ž" ์œ ํ˜•์„ ๊ตฌ๋ฌธ ๋ถ„์„ํ•˜๋Š” ๋‘ ์ค„์€ ์••์ถ•๋œ ๋ฒ„์ „์—์„œ ์˜ฌ๋ฐ”๋ฅด์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

JsonTokenType.Number => reader.TryGetInt64(out long l) ? 1 : reader.GetDouble(),

ํ•ด์•ผํ•œ๋‹ค

JsonTokenType.Number => reader.TryGetInt64(out long l) ? l : reader.GetDouble(),

JsonValueKind.Number => jsonElement.TryGetInt64(out long l) ? 1 :0,

ํ•ด์•ผํ•œ๋‹ค

JsonValueKind.Number => jsonElement.TryGetInt64(out long l) ? l :0,

@layomia ์‹ฌ๊ฐํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์ง€์›์€ ์˜ค๋ž˜์ „์— ์ด๋ฃจ์–ด์กŒ์–ด์•ผ ํ–ˆ์Šต๋‹ˆ๋‹ค(์‚ฌ์‹ค System.Text.Json์€ ๋‚ด ์ƒ๊ฐ์— ๊ทธ๊ฒƒ ์—†์ด๋Š” ์‹œ์ž‘๋˜์ง€ ๋ง์•˜์–ด์•ผ ํ–ˆ์Šต๋‹ˆ๋‹ค)! ๊ทธ๋ฆฌ๊ณ  ์šฐ๋ฆฌ๋Š” ๊ธฐํ•œ๋„ ์—†์Šต๋‹ˆ๋‹ค!

๋‚ด ์‹œ๋‚˜๋ฆฌ์˜ค๋Š” CosmosDB์— ๊ด€ํ•œ ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์ด JsonSerializer๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ์ƒˆ๋กœ์šด .NET SDK๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ฟผ๋ฆฌํ•˜๊ณ  ์žˆ์œผ๋ฉฐ ์Šคํ‚ค๋งˆ๊ฐ€ ์—†๋Š” ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์ด๋ฏ€๋กœ ์ˆ˜ํ–‰ํ•ด์•ผ ํ•˜๋Š” ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ๋ฐ์ดํ„ฐ์˜ ๊ฐ ํ”„๋กœ์ ์…˜์— ๋Œ€ํ•œ ํด๋ž˜์Šค๋ฅผ ๋งŒ๋“ค๊ณ  ์‹ถ์ง€ ์•Š์Šต๋‹ˆ๋‹ค(๋‹ค์–‘ํ•œ ์ฟผ๋ฆฌ๊ฐ€ ์žˆ์Œ) .
๋™์  ๊ฐœ์ฒด ๋ชฉ๋ก์œผ๋กœ ์ฟผ๋ฆฌ ๊ฒฐ๊ณผ๊ฐ€ ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค.

@SocVi100 ์ด ๋ฌธ์ œ์— ๋Œ€ํ•ด Microsoft์— ํฌ๋ง์„ ๋‘์ง€ ๋งˆ์‹ญ์‹œ์˜ค. Newtonsoft์˜ Json.net์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค. @layomia ๋Š” ๊ฐ€๊นŒ์šด ์žฅ๋ž˜์˜ ํ†ตํ•ฉ์— ๋Œ€ํ•œ ๋ชจ๋“  ํฌ๋ง์„

์™œ ๊ธฐ์—ฌํ•˜์ง€ ์•Š์Šต๋‹ˆ๊นŒ? ๊ทธ๊ฒƒ์„ ๊ตฌํ˜„ํ•˜๊ณ  PR์„ ๋„ฃ์–ด!

https://github.com/dotnet/runtime/blob/master/docs/coding-guidelines/adding-api-guidelines.md
https://github.com/dotnet/runtime/blob/master/docs/area-owners.md (๋ฆฌ๋“œ:
@ericstj |, ์†Œ์œ ์ž: @layomia @steveharter @jozkee)

์™œ ๊ธฐ์—ฌํ•˜์ง€ ์•Š์Šต๋‹ˆ๊นŒ? ๊ทธ๊ฒƒ์„ ๊ตฌํ˜„ํ•˜๊ณ  PR์„ ๋„ฃ์–ด!

๋‚ด๊ฐ€ ํ•  ์ˆ˜ ์žˆ์—ˆ์œผ๋ฉด ์ข‹๊ฒ ์–ด.

๋‚ด ์‹œ๋‚˜๋ฆฌ์˜ค๋Š” CosmosDB์— ๊ด€ํ•œ ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์ด JsonSerializer๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ์ƒˆ๋กœ์šด .NET SDK๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ฟผ๋ฆฌํ•˜๊ณ  ์žˆ์œผ๋ฉฐ ์Šคํ‚ค๋งˆ๊ฐ€ ์—†๋Š” ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์ด๋ฏ€๋กœ ์ˆ˜ํ–‰ํ•ด์•ผ ํ•˜๋Š” ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ๋ฐ์ดํ„ฐ์˜ ๊ฐ ํ”„๋กœ์ ์…˜์— ๋Œ€ํ•œ ํด๋ž˜์Šค๋ฅผ ๋งŒ๋“ค๊ณ  ์‹ถ์ง€ ์•Š์Šต๋‹ˆ๋‹ค(๋‹ค์–‘ํ•œ ์ฟผ๋ฆฌ๊ฐ€ ์žˆ์Œ) .
๋™์  ๊ฐœ์ฒด ๋ชฉ๋ก์œผ๋กœ ์ฟผ๋ฆฌ ๊ฒฐ๊ณผ๊ฐ€ ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค.

CosmosClientBuilder.WithCustomSerializer ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋‹ค๋ฅธ ์ง๋ ฌ ๋ณ€ํ™˜๊ธฐ๋ฅผ ๊ตฌ์„ฑํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋‹ค์Œ์€ ์˜ˆ์ž…๋‹ˆ๋‹ค. CosmosJsonNetSerializer

์ด ๊ธฐ๋Šฅ์„ 5.0์— ๋งž์ถœ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. ๋‚˜๋จธ์ง€ 5.0 ๊ธฐ๋Šฅ ์ž‘์—…๊ณผ ํ•จ๊ป˜ ์šฐ์„  ์ˆœ์œ„๋ฅผ ์ง€์ •ํ•ด์•ผ ํ–ˆ์ง€๋งŒ ์ด ์ž‘์—…์€ ์ ํ•ฉํ•˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค. FWIW ์ด๊ฒƒ์€ ์ปท ๋ผ์ธ์— ๋งค์šฐ ๊ฐ€๊นŒ์› ์œผ๋ฏ€๋กœ ๋Šฆ์€ ์›€์ง์ž„์ž…๋‹ˆ๋‹ค.

@layomia ๋Š” ๊ฐ€๊นŒ์šด ์žฅ๋ž˜์˜ ํ†ตํ•ฉ์— ๋Œ€ํ•œ ๋ชจ๋“  ํฌ๋ง์„

@RobbyDeLaet ์ด ํ† ๋ก ์„ ๊ฑด์„ค์ ์œผ๋กœ ์œ ์ง€ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๊นŒ? ์šฐ๋ฆฌ๋Š” ๋””์ž์ธ ์›์น™์„ ์œ ์ง€ํ•˜๋ฉด์„œ ๊ฐ€์žฅ ๋งŽ์ด ์š”์ฒญํ•œ ๊ณ ๊ฐ ๊ธฐ๋Šฅ์— ์‘๋‹ตํ•˜๊ธฐ ์œ„ํ•ด ์ตœ์„ ์„ ๋‹คํ•˜๋ ค๊ณ ํ•ฉ๋‹ˆ๋‹ค. Newtonsoft.Json์˜ ๊ธฐ๋Šฅ ํŒจ๋ฆฌํ‹ฐ์™€ ๊ด€๋ จํ•˜์—ฌ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์„ค๋ช… ํ•ฉ๋‹ˆ๋‹ค.

System.Text.Json์€ ์ฃผ๋กœ ์„ฑ๋Šฅ, ๋ณด์•ˆ ๋ฐ ํ‘œ์ค€ ์ค€์ˆ˜์— ์ค‘์ ์„ ๋‘ก๋‹ˆ๋‹ค. ์ผ๋ถ€ ์‹œ๋‚˜๋ฆฌ์˜ค์˜ ๊ฒฝ์šฐ System.Text.Json์—๋Š” ๊ธฐ๋ณธ ์ œ๊ณต ๊ธฐ๋Šฅ์ด ์—†์ง€๋งŒ ๊ถŒ์žฅ๋˜๋Š” ํ•ด๊ฒฐ ๋ฐฉ๋ฒ•์ด ์žˆ์Šต๋‹ˆ๋‹ค. ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์ด ๋ˆ„๋ฝ๋œ ๊ธฐ๋Šฅ์— ์˜์กดํ•˜๋Š” ๊ฒฝ์šฐ ๋ฌธ์ œ๋ฅผ ์ œ์ถœํ•˜์—ฌ ์‹œ๋‚˜๋ฆฌ์˜ค์— ๋Œ€ํ•œ ์ง€์›์„ ์ถ”๊ฐ€ํ•  ์ˆ˜ ์žˆ๋Š”์ง€ ์•Œ์•„๋ณด์‹ญ์‹œ์˜ค.

์šฐ๋ฆฌ๋Š” Newtonsoft.JSON์„ ๋Œ€์ฒดํ•˜๋Š” ๊ฒƒ์„ ๋ชฉํ‘œ๋กœ ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ํšจ๊ณผ๊ฐ€ ์žˆ์œผ๋ฉด ๊ณ„์† ์‚ฌ์šฉํ•˜์‹ญ์‹œ์˜ค. ์„ฑ๋Šฅ, ๋ณด์•ˆ, ํ‘œ์ค€ ์ค€์ˆ˜ ๋ฐ ๊ณ„์ธตํ™”์—์„œ ๋‹ฌ์„ฑํ•œ ์ด์ ์„ ์œ ์ง€ํ•˜๋ฉด์„œ System.Text.Json์„ ์ตœ๋Œ€ํ•œ ์œ ์šฉํ•˜๊ฒŒ ๋งŒ๋“ค๊ธฐ ์œ„ํ•ด ์ตœ์„ ์„ ๋‹คํ•  ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์‹œ๊ฐ„์ด ์ง€๋‚จ์— ๋”ฐ๋ผ ๊ฐ€๋Šฅํ•œ ํ•œ ๋งŽ์€ ์‚ฌ๋žŒ๋“ค์ด ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๊ธฐ๋ฅผ ๋ฐ”๋ž๋‹ˆ๋‹ค. ์ €๋Š” ์—ฌ๊ธฐ์—์„œ ๊ด€์‹ฌ์„ ๋ฐ›๊ณ  ์žˆ์œผ๋ฉฐ ์•ž์œผ๋กœ ์ด ์ผ์— ์ง‘์ค‘ํ•  ๊ฒƒ์ž…๋‹ˆ๋‹ค.

์ œ์•ˆํ•ด ์ฃผ์…”์„œ ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค. ๋‚˜๋Š” ๋งˆ์นจ๋‚ด ์—ญ์ง๋ ฌํ™”๋ฅผ ์œ„ํ•ด์„œ๋งŒ Newtonsoft ์ง๋ ฌ ๋ณ€ํ™˜๊ธฐ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ค‘๊ฐ„์— ๊ฐ”์ง€๋งŒ ์—ฌ์ „ํžˆ ํ…Œ์ŠคํŠธํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. CosmosDB์˜ ๊ธฐ๋ณธ ์ง๋ ฌ ๋ณ€ํ™˜๊ธฐ์—์„œ ExpandoObject ์ง€์›์„ ๋ฐ›๋Š” ๊ฒƒ์ด ๋„ˆ๋ฌด ์˜ค๋ž˜ ์ง€์†๋˜์ง€ ์•Š๊ธฐ๋ฅผ ๋ฐ”๋ž๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ ์ด์ „ ์ง๋ ฌ ๋ณ€ํ™˜๊ธฐ๋ฅผ ์ œ๊ฑฐํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
@RobbyDeLaet , ์˜๊ฒฌ ์ฃผ์…”์„œ ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค! ๋‚˜๋Š” ๋งˆ์ดํฌ๋กœ์†Œํ”„ํŠธ๊ฐ€ ๊ตฌํ˜„ํ•˜๋Š” ๊ฒƒ์— ๋Œ€ํ•ด ๋ณ„๋กœ ๊ธฐ๋Œ€ํ•˜์ง€ ์•Š๋Š”๋‹ค. ๋‚˜๋Š” ๊ทธ๊ฒƒ์— ๋Œ€ํ•ด ๋„ˆ๋ฌด ๋งŽ์ด ์ขŒ์ ˆ๊ฐ์„ ๋Š๊ผˆ๋‹ค. ํ”„๋ฆฌ๋žœ์„œ ๊ฐœ๋ฐœ์ž๋กœ์„œ ์ €๋Š” ๋ฌธ์ž ๊ทธ๋Œ€๋กœ CosmosDB, EntityFramework ๋ฐ Identity ์ธํ”„๋ผ์— ํ•„์ˆ˜ ๊ธฐ๋Šฅ์ด ๊ตฌํ˜„๋˜๊ธฐ๋ฅผ ๋ช‡ ๋…„ ๋™์•ˆ ๊ธฐ๋‹ค๋ ธ๋Š”๋ฐ, ๊ทธ๋“ค์€ ์šฐ๋ฆฌ๋ฅผ ๋ฌด์‹œํ•˜๊ณ  ์ œ๋ฉ‹๋Œ€๋กœ ์›€์ง์˜€์Šต๋‹ˆ๋‹ค. ๊ทธ๋“ค์ด UserVoice์— ์–ผ๋งˆ๋‚˜ ๋งŽ์€ ํˆฌํ‘œ๋ฅผ ํ–ˆ๋Š”์ง€๋Š” ์ค‘์š”ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌํ•œ ๊ธฐ๋Šฅ์€ ์ž์ฒด ๊ฐœ๋ฐœ์— ํ•„์š”ํ•˜์ง€ ์•Š์œผ๋ฏ€๋กœ ๋ฒ”์œ„๋ฅผ ๋ฒ—์–ด๋‚ฉ๋‹ˆ๋‹ค ...
๋ฌธ์ œ๋Š” ํ•ญ์ƒ ๋™์ผํ•ฉ๋‹ˆ๋‹ค. ๋„ˆ๋ฌด ๋งŽ์€ ๋งˆ์ผ€ํŒ… = ๋„ˆ๋ฌด ๋งŽ์€ ๊ธฐ๋Œ€

์ด ๊ธฐ๋Šฅ์ด ํ•„์š”ํ•œ ์‚ฌ๋žŒ๋“ค์„ ๋•๊ธฐ ์œ„ํ•ด ์œ„์˜ ์ฝ”๋“œ ์ƒ˜ํ”Œ์„ ์ฐธ์กฐํ•˜์—ฌ ์ฐจ๋‹จ์„ ํ•ด์ œํ•˜์„ธ์š”.

  • @tchivs์—์„œ (๊ฐœ์ฒด์—๋Š” ExpandoObject List<object> , ์ปฌ๋ ‰์…˜์—๋Š”
  • @denmitchell์—์„œ ( ExpandoObject ๋Œ€์‹  ๊ฐœ์ฒด์— ๋Œ€ํ•ด IL Emit ์‚ฌ์šฉ)

์ด ๊ธฐ๋Šฅ์— ๋Œ€ํ•œ ์š”๊ตฌ ์‚ฌํ•ญ์„ ์ง€์›ํ•˜๊ธฐ ์œ„ํ•ด ์ƒˆ๋กœ์šด ์‚ฌ์šฉ์ž ์ง€์ • ๋ณ€ํ™˜๊ธฐ ์ƒ˜ํ”Œ์„ ์ œ๊ณตํ•˜๊ณ  ์ค€๋น„๊ฐ€ ๋˜๋ฉด ์—ฌ๊ธฐ์— ๋งํฌํ•  ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๊ทธ ํ›„์— Newtonsoft ํ•ด๊ฒฐ ๋ฐฉ๋ฒ• ์„น์…˜์— ํ•ด๋‹น ์ƒ˜ํ”Œ์„ ์ถ”๊ฐ€ @tdykstra

์•„์ง ๋…ผ์˜๋˜์ง€ ์•Š์€ ํ•œ ๊ฐ€์ง€ ์„ธ๋ถ€ ์‚ฌํ•ญ์€ dynamic ํ•˜๋ ค๋ฉด ๋งค์šฐ ํฐ System.Linq.Expressions.dll ์–ด์…ˆ๋ธ”๋ฆฌ์— ๋Œ€ํ•œ ์ฐธ์กฐ๊ฐ€ ํ•„์š”ํ•˜๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์ด ํ•ฉ๋ณ‘์ฆ์€ ์šฐ๋ฆฌ๊ฐ€ ์ƒˆ ์–ด์…ˆ๋ธ”๋ฆฌ (์˜ˆ์—์„œ ๋™์  ๋ณ€ํ™˜์„ ์ถ”๊ฐ€ ๋ฏธ๋ž˜์— ์˜๋ฏธ System.Text.Json.Converters.dll ์‚ฌ๋žŒ๋“ค์„ ์œ„ํ•ด ์œ ๋ฃŒ๋กœ ํ”Œ๋ ˆ์ด๋ฅผ ์–ป๊ธฐ ์œ„ํ•ด) ์ด๋Ÿฌํ•œ ์ž์ฒด์— ํฌํ•จ ๋œ ์‘์šฉ ํ”„๋กœ๊ทธ๋žจ ๋˜๋Š” Blazor๋กœ ๋ฐฐํฌ ํฌ๊ธฐ (์•ฝ ์น˜๋ฃŒ๊ฐ€ ํด๋ผ์ด์–ธํŠธ ์•ฑ).

์ œ ์ •์‹ ์„ ์œ„ํ•ด - ๋ฌธ์ œ๊ฐ€ 5.0, ํŠนํžˆ ExpandoObject ์ง€์› ๋˜๋Š” ๋™์  ๊ฐœ์ฒด๋กœ ์—ญ์ง๋ ฌํ™”ํ•˜๋Š” ๊ธฐ๋Šฅ์— ๋Œ€ํ•œ ๋ฒ”์œ„์ž…๋‹ˆ๊นŒ? ์—ฌ๊ธฐ์˜ ๋Œ€ํ™”๊ฐ€ ๋ชจ๋‘ ๋ฌธ์ œ ์ œ๋ชฉ๊ณผ ์ผ์น˜ํ•˜์ง€ ์•Š๋Š” ๊ฒƒ ๊ฐ™์œผ๋ฉฐ ๋‚˜๋Š” ํ™•์‹คํžˆ ํ›„์ž๊ฐ€ ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค. ์ œ ๊ฒฝ์šฐ์—๋Š” ์ค‘์ฒฉ๋œ ๋™์ , ํŠนํžˆ List<Dictionary<string, dynamic>> ์—ญ์ง๋ ฌํ™”ํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ์ง€๊ธˆ์€ Newtonsoft๋กœ ๋‹ค์‹œ ์ „ํ™˜ํ–ˆ์Šต๋‹ˆ๋‹ค.

์ด์ œ ์ค‘์ฒฉ๋œ ๊ฐœ์ฒด๋ฅผ ์—ญ์ง๋ ฌํ™”ํ•˜๊ธฐ ์œ„ํ•ด ๊ตฌํ˜„ํ•œ ์ด์ „ ํ•จ์ˆ˜๋ฅผ ํ…Œ์ŠคํŠธํ•˜๊ณ  ์žˆ์œผ๋ฉฐ ์ด ํ•ญ๋ชฉ์—์„œ "valueKind"๋กœ ์–ธ๊ธ‰๋œ ๋™์ผํ•œ ๋ฌธ์ œ๋ฅผ ํ™•์ธํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

์ƒˆ๋กœ์šด neetonsoft.json ํŒจํ‚ค์ง€๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ด ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•  ์ˆ˜ ์žˆ๋Š” ๋ฐฉ๋ฒ•์ด ์žˆ์Šต๋‹ˆ๊นŒ? ์œ„์˜ ์ฝ”๋“œ๋Š” ๋ฃจํŠธ ์ˆ˜์ค€ ๊ฐœ์ฒด์— ๋Œ€ํ•ด ์ž‘๋™ํ–ˆ์ง€๋งŒ ์ค‘์ฒฉ ๊ฐœ์ฒด์—๋Š” ์ž‘๋™ํ•˜์ง€ ์•Š์•˜๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค.

@ericstj ์ฃ„์†กํ•ฉ๋‹ˆ๋‹ค. ์ œ ๋ฐ˜์‘์ด ๋„ˆ๋ฌด ๋ถ€์ •์ ์ด๊ณ  ๊ฐ€ํ˜นํ–ˆ์„ ์ˆ˜๋„ ์žˆ์ง€๋งŒ @SocVi100 ๊ณผ ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ ์ €๋Š” ํ”„๋ฆฌ๋žœ์Šค ๊ฐœ๋ฐœ์ž์ด๋ฉฐ ๋•Œ๋กœ๋Š” ์ขŒ์ ˆ๊ฐ์ด ์šฐ์œ„๋ฅผ ์ ํ•˜๊ธฐ๋„ ํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ์ ์–ด๋„ ์—ฌ๊ธฐ์—์„œ ๋…ผ์˜๊ฐ€ ์‹œ์ž‘๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ์‘๋‹ตํ•ด ์ฃผ์…”์„œ ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค. ์ด์ œ ์ด ์š”์ฒญ์˜ ์ƒํƒœ์— ๋Œ€ํ•œ ๋ช…ํ™•ํ•œ ๋ฉ”์‹œ์ง€๋ฅผ ๋ฐ›์•˜์Šต๋‹ˆ๋‹ค.

์ œ ์ •์‹ ์„ ์œ„ํ•ด - 5.0, ํŠนํžˆ ExpandoObject ์ง€์› ๋˜๋Š” ๋™์  ๊ฐœ์ฒด๋กœ ์—ญ์ง๋ ฌํ™”ํ•˜๋Š” ๊ธฐ๋Šฅ์— ๋Œ€ํ•œ ๋ฌธ์ œ์ž…๋‹ˆ๋‹ค.

์›ํ•˜๋Š” ์˜๋ฏธ ์ฒด๊ณ„์— ๋™์  ์œ ํ˜•์ด ์žˆ๋‹ค๊ณ  ๊ฐ€์ •ํ•ฉ๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ ์—ญ์ง๋ ฌํ™” ํ›„์— ๋ชจ๋“  ์†์„ฑ(์ค‘์ฒฉ ํฌํ•จ)์— ๋Šฆ์€ ๋ฐ”์ธ๋”ฉ ๋ฐฉ์‹์œผ๋กœ ์•ก์„ธ์Šคํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

dynamic obj = JsonSerializer.Deserialize<dynamic>(json);
string s = obj.MyChildProperty.MyStringList[2];

์›ํ•˜๋Š” ์˜๋ฏธ ์ฒด๊ณ„๊ฐ€ ExpandoObject ๋ช…์‹œ์ ์œผ๋กœ ์ง€์›ํ•œ๋‹ค๊ณ  ๊ฐ€์ •ํ•ฉ๋‹ˆ๋‹ค.

ExpandoObject expando = JsonSerializer.Deserialize<ExpandoObject>(json);
dynamic obj = expando;
string s = obj.MyChildProperty.MyStringList[2];

๊ทธ๋ž˜์„œ ๋ฒ”์œ„์— ๋Œ€ํ•œ ๋‚˜์˜ ์ดํ•ด:

  • Deserialize<dynamic>(json) ๋Š” ๊ธฐ๋ณธ, ์ปฌ๋ ‰์…˜ ๋˜๋Š” ๊ฐœ์ฒด๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค. ์—ฌ๊ธฐ์„œ ๊ฐœ์ฒด๋Š” ExpandoObject ์žˆ์ง€๋งŒ ๊ตฌํ˜„์— ๋”ฐ๋ผ IDynamicMetaObjectProvider ๋˜๋Š” JITed ์œ ํ˜•์ด ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๊ฒƒ์€ ํ•ญ์ƒ JsonElement ๋ฐ˜ํ™˜ํ•˜๋Š” ์˜ค๋Š˜๊ณผ ๋‹ค๋ฆ…๋‹ˆ๋‹ค.
  • Deserialize<ExpandoObject>(json) ( IDynamicMetaObjectProvider ๋ฅผ ๊ตฌํ˜„ํ•จ)์€ ์ ์ ˆํ•œ ExpandoObject ๋ฅผ ์ƒ์„ฑํ•ด์•ผ ํ•˜๋ฉฐ ์ด๋Š” dynamic ์™€ ํ•จ๊ป˜ ์‚ฌ์šฉ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๊ฒƒ์€ ๋ฃจํŠธ ์†์„ฑ์— ๋Œ€ํ•œ expando ์†์„ฑ๋งŒ ์ƒ์„ฑํ•˜๊ณ  ๋ชจ๋“  ์ค‘์ฒฉ ์†์„ฑ์— ๋Œ€ํ•œ JsonElement ์ธ์Šคํ„ด์Šค๋งŒ ์ƒ์„ฑํ•˜๋Š” ์˜ค๋Š˜๋‚ ๊ณผ ๋‹ค๋ฆ…๋‹ˆ๋‹ค.
  • Serialize<ExpandoObect>() ๋Š” ์˜ˆ์ƒ๋Œ€๋กœ ์ž‘๋™ํ•ฉ๋‹ˆ๋‹ค
  • Serialize<IDynamicMetaObjectProvider ()>๋Š” ExpandoObject ๊ฐ€ ์‚ฌ์šฉ๋˜์ง€ ์•Š๋Š” ์‹œ๋‚˜๋ฆฌ์˜ค๊ฐ€ ์žˆ๋Š”์ง€ ์—ฌ๋ถ€์— ๋”ฐ๋ผ ๊ตฌํ˜„๋  ์ˆ˜๋„ ์žˆ๊ณ  ๊ตฌํ˜„๋˜์ง€ ์•Š์„ ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค.

3.0 - 5.0์˜ ์˜๋ฏธ:

  • ExpandoObject ์ง๋ ฌํ™”๋Š” ExpandoObject ๊ฐ€ IDictionary<string, object> ExpandoObject ๊ตฌํ˜„ํ•˜๊ณ  STJ๊ฐ€ ๊ฐ object ๊ฐ’์ด ํ”„๋ฆฌ๋ฏธํ‹ฐ๋ธŒ, ์ปฌ๋ ‰์…˜ ๋˜๋Š” ๊ฐ์ฒด์ธ์ง€์— ์ƒ๊ด€์—†์ด ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ์ง๋ ฌํ™”ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์ž‘๋™ํ•ฉ๋‹ˆ๋‹ค.
  • ExpandoObject ์ผ์ข…์˜ ์ž‘์—…์œผ๋กœ ์—ญ์ง๋ ฌํ™”ํ•˜์ง€๋งŒ ๋ฃจํŠธ ์†์„ฑ๋งŒ "์ ์ ˆํ•œ" expando ์†์„ฑ์ž…๋‹ˆ๋‹ค. ๋ชจ๋“  ์ค‘์ฒฉ ์†์„ฑ์€ JsonElement ์ด๋ฏ€๋กœ ํ”„๋กœ๊ทธ๋ž˜๋ฐ ๋ชจ๋ธ์— ๋ถˆ์ผ์น˜๊ฐ€ ์žˆ์œผ๋ฏ€๋กœ ์‚ฌ์šฉ์ž ์ง€์ • ๋ณ€ํ™˜๊ธฐ๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š” ํ•œ ExpandoObject ์—ญ์ง๋ ฌํ™”๋ฅผ ํ”ผํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

3.0-5.0์— ๋Œ€ํ•œ ์˜ต์…˜:

  • ์œ„์˜ ๊ฒŒ์‹œ๋ฌผ์—์„œ ์–ธ๊ธ‰ํ•œ ๋Œ€๋กœ ExpandoObject ๋ฐ\๋˜๋Š” object ๋Œ€ํ•œ ์‚ฌ์šฉ์ž ์ •์˜ ๋ณ€ํ™˜๊ธฐ๋ฅผ ์ž‘์„ฑํ•˜์‹ญ์‹œ์˜ค. 6.0 ๊ธฐ๋Šฅ์— ์ด์ƒ์ ์œผ๋กœ ๋งคํ•‘๋˜๋Š” ์ƒˆ ์ƒ˜ํ”Œ์— ๋Œ€ํ•œ ๋งํฌ๋ฅผ ๊ณง ์ œ๊ณตํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.
  • ๋‹น์‹ ์€ ๋‹จ์ง€ ์ง๋ ฌํ™”, ์—ญ ์ง๋ ฌํ™”ํ•˜์ง€ ์•Š์œผ๋ฉด, ๋‹น์‹ ์ด ์‚ฌ์šฉํ•  ์ˆ˜์žˆ๋Š” ExpandoObject (๋˜๋Š” dynamic ์œ ํ˜•์„ ๊ธฐ๋ฐ˜์œผ๋กœํ•˜๋Š” ๊ฒฝ์šฐ ExpandoObject ). ExpandoObject ์—ญ์ง๋ ฌํ™”ํ•˜๋ฉด STJ์—์„œ ์˜ค๋Š˜๋‚  ๋ถˆ์ผ์น˜ ๋ฌธ์ œ๊ฐ€ ์žˆ์œผ๋ฏ€๋กœ ์—ญ์ง๋ ฌํ™”ํ•˜๋Š” ๊ฒฝ์šฐ ExpandoObject ๋Š” ๊ถŒ์žฅ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.
  • ๋™์  ๊ฐœ์ฒด ๋Œ€์‹  JsonElement ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. JsonElement ๋Š” JSON์ด ๋งคํ•‘๋˜๋Š” ์œ ํ˜•์„ "์ถ”์ธก"ํ•˜์ง€ ์•Š์œผ๋ฏ€๋กœ GetString(), GetInt32() ๋“ฑ์„ ํ˜ธ์ถœํ•˜์—ฌ ๋ช…์‹œ์ ์ด์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

๋˜ํ•œ ๊ตฌํ˜„์— ๋”ฐ๋ผ ์‚ฌ์šฉ์ž ์ง€์ • ๋ณ€ํ™˜๊ธฐ์˜ ๊ตฌํ˜„์€ ์—ญ์ง๋ ฌํ™” ์ค‘์— JSON์ด ๋งคํ•‘๋˜๋Š” CLR ์œ ํ˜•์— ๋Œ€ํ•ด ์•ฝ๊ฐ„์˜ "์ถ”์ธก"์ด ์žˆ์Œ์„ ์˜๋ฏธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด JSON ๋ฌธ์ž์—ด์€ DateTime ๋˜๋Š” string ์— ๋งคํ•‘๋  ์ˆ˜ ์žˆ๊ณ  JSON ๋ฒˆํ˜ธ๋Š” double ๋˜๋Š” long ๋งคํ•‘๋  ์ˆ˜ ์žˆ์œผ๋ฉฐ JSON ๋ฐฐ์—ด ์œ ํ˜•์„ ๊ฒฐ์ •ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์ด๊ฒƒ์€ Newtonsoft ์˜๋ฏธ๋ก ๊ณผ ๋น„๊ตํ•˜๊ณ  ์กฐ์‚ฌํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ๋˜ํ•œ ์†์„ฑ์ด object ์œ ํ˜•(์˜ค๋Š˜๋‚  JsonElement )

๋‹ค์Œ์€ 3.0 - 5.0 STJ ์˜๋ฏธ ์ฒด๊ณ„์˜ ๋ช‡ ๊ฐ€์ง€ ์˜ˆ์ž…๋‹ˆ๋‹ค.

using System;
using System.Collections.Generic;
using System.Dynamic;
using System.Diagnostics;
using System.Linq;
using System.Text.Json;

namespace ConsoleApp
{
    class Program
    {
        const string ExpectedJson = "{\"A\":\"A\",\"B\":[1,2],\"C\":42,\"D\":\"2020-01-01T00:00:00\",\"E\":{\"A_Child\":\"A_Child\"}}";

        static void Main(string[] args)
        {
            DateTime dateTime = new DateTime(2020, 1, 1);

            dynamic myDynamicChild = new ExpandoObject();
            myDynamicChild.A_Child = "A_Child";

            dynamic myDynamic = new ExpandoObject();
            myDynamic.A = "A";
            myDynamic.B = new List<int>() { 1, 2 };
            myDynamic.C = 42;
            myDynamic.D = dateTime;
            myDynamic.E = myDynamicChild;

            // Verify we can call late-bound property.
            int c = myDynamic.C;
            Debug.Assert(c == 42);

            // STJ can serialize with ExpandoObject since it implements IDictionary<string, object>.
            string json = JsonSerializer.Serialize<ExpandoObject>(myDynamic);
            Debug.Assert(json == ExpectedJson);

            // Using 'dynamic' against backing ExpandoObject works.
            json = JsonSerializer.Serialize<dynamic>(myDynamic);
            Debug.Assert(json == ExpectedJson);

            // Deserialize with <dynamic>, <object> and <JsonElement>.
            // For 5.0, using one of these is recommended over ExpandoObject because the programming model will be
            // consistent for the root type and all nested types.
            // Using <JsonElement> makes it clear and non-abiguous.
            // Using <object> by default uses 'JsonElement', but can be overridden by a custom converter.
            // Using <dynamic> uses 'object' which uses 'JsonElement'.
            {
                dynamic d = JsonSerializer.Deserialize<dynamic>(json);
                VerifyJsonElement(d);

                try
                {
                    // We will get an exception here if we try to access a dynamic property since 'object' is deserialized
                    // as a JsonElement and not an ExpandoObject.
                    c = d.C;
                    Debug.Fail("Should have thrown Exception!");
                }
                catch (Exception ex)
                {
                    Debug.Assert(ex.Message == "'System.Text.Json.JsonElement' does not contain a definition for 'C'");
                }

                // Serializing with <object> creates a JsonElement by default (can be changed by a custom converter).
                object o = JsonSerializer.Deserialize<object>(json);
                VerifyJsonElement((JsonElement)o);

                // Serialize with explicit <JsonElement>.
                JsonElement e = JsonSerializer.Deserialize<JsonElement>(json);
                VerifyJsonElement(e);
            }

            // Deserialize with ExpandoObject. This creates an ExpandoObject with the root Type having Expando-properties
            // but the value of those properties will be JsonElement. All other nested properties\objects\collections will
            // also be JsonElement. Due to the inconsistency of having only root-level Expando-properties (such as A_Child),
            // deserializing as ExpandoObject is not recommended (unless a ExpandoObject custom converter is used).
            {
                // When STJ deserializes, it creates ExpandoObjects via IDictionary<string, object> where 'object' is JsonElement.
                ExpandoObject expando = JsonSerializer.Deserialize<ExpandoObject>(json);
                Debug.Assert(((IDictionary<string, object>)expando).Keys.Count == 5);
                myDynamic = expando;

                JsonElement jsonElement = myDynamic.A;
                Debug.Assert(jsonElement.GetString() == "A");

                jsonElement = myDynamic.B;
                Debug.Assert(jsonElement.EnumerateArray().Count() == 2);

                jsonElement = myDynamic.C;
                Debug.Assert(jsonElement.GetInt32() == 42);

                jsonElement = myDynamic.D;
                Debug.Assert(jsonElement.GetDateTime() == dateTime);

                jsonElement = myDynamic.E;
                // Here we have an inconsistency. Nested object property must use JsonElement (not a dynamic property).
                Debug.Assert(jsonElement.GetProperty("A_Child").GetString() == "A_Child");

                // Re-serialize works as expected.
                json = JsonSerializer.Serialize<ExpandoObject>(myDynamic);
                Debug.Assert(json == ExpectedJson);

                // Re-serialize works as expected; dynamic works here since backed by ExpandoObject in this example.
                json = JsonSerializer.Serialize<dynamic>(myDynamic);
                Debug.Assert(json == ExpectedJson);
            }

            void VerifyJsonElement(JsonElement elem)
            {
                // Verify JsonElement
                Debug.Assert(elem.GetProperty("A").GetString() == "A");
                Debug.Assert(elem.GetProperty("B").EnumerateArray().Count() == 2);
                Debug.Assert(elem.GetProperty("C").GetInt32() == 42);
                Debug.Assert(elem.GetProperty("D").GetDateTime() == dateTime);
                Debug.Assert(elem.GetProperty("E").GetProperty("A_Child").GetString() == "A_Child");

                // Re-serialize
                json = JsonSerializer.Serialize<dynamic>(elem);
                Debug.Assert(json == ExpectedJson);

                json = JsonSerializer.Serialize<JsonElement>(elem);
                Debug.Assert(json == ExpectedJson);
            }
        }
    }
}

@rs38 @ryan-hollister-q2๊ฐ€ ์ง€์ ํ•œ ๋‚ด์šฉ์„ ๊ธฐ๋ฐ˜์œผ๋กœ ์ฝ”๋“œ ์กฐ๊ฐ์„ ์ˆ˜์ •ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๊นŒ?

์•ฝ์†ํ•œ ๋Œ€๋กœ ๋™์  ๊ตฌํ˜„ ์ƒ˜ํ”Œ์„ ์ œ๊ณตํ•˜๋Š” PR์€ https://github.com/dotnet/runtime/pull/42097์— ์žˆ์Šต๋‹ˆ๋‹ค.

@rs38 @ryan-hollister-q2๊ฐ€ ์ง€์ ํ•œ ๋‚ด์šฉ์„ ๊ธฐ๋ฐ˜์œผ๋กœ ์ฝ”๋“œ ์กฐ๊ฐ์„ ์ˆ˜์ •ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๊นŒ?

๊ทธ๊ฒƒ์€ ๋‚ด ์ฝ”๋“œ๊ฐ€ ์•„๋‹ˆ ์—ˆ๊ณ  ์ด ์Šค๋ ˆ๋“œ์˜ ์•ž๋ถ€๋ถ„์—์„œ ํ–ˆ์„ ๋ฟ์ž…๋‹ˆ๋‹ค .

์ด ํŽ˜์ด์ง€๊ฐ€ ๋„์›€์ด ๋˜์—ˆ๋‚˜์š”?
0 / 5 - 0 ๋“ฑ๊ธ‰