JsonSerializer.Parse(String, Type, JsonSerializerOptions)
๋ ๋์ ExpandoObject
๋ฐํ ์ ํ์ ์ง์ํฉ๋๊น?
์ด ๊ฐ์:
dynamic p = JsonSerializer.Parse(json, typeof(ExpandoObject));
์๋์, ์ด ๊ธฐ๋ฅ์ ํ์ฌ ์ง์๋์ง ์์ง๋ง 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
ExpandoObject์ ๋ํ JsonSerializer ์ง์(์์ ์กฐ์น)
๋๋ ์ด๋ณด์, ๋ง์ ๊ณณ์ด ์๋ฒฝํ์ง ์์ต๋๋ค. ์์ ํ๋ ๋ชจ๋ ์ฌ๋์ ํ์ํฉ๋๋ค
.net Core3 ์ง์ ์ ํจ
๋ค์์ ์ฌ์ฉํ์ฌ ์ถ๊ฐ:
```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์ ์ผ๋ง๋ ๋ง์ ํฌํ๋ฅผ ํ๋์ง๋ ์ค์ํ์ง ์์ต๋๋ค. ๊ทธ๋ฌํ ๊ธฐ๋ฅ์ ์์ฒด ๊ฐ๋ฐ์ ํ์ํ์ง ์์ผ๋ฏ๋ก ๋ฒ์๋ฅผ ๋ฒ์ด๋ฉ๋๋ค ...
๋ฌธ์ ๋ ํญ์ ๋์ผํฉ๋๋ค. ๋๋ฌด ๋ง์ ๋ง์ผํ
= ๋๋ฌด ๋ง์ ๊ธฐ๋
์ด ๊ธฐ๋ฅ์ด ํ์ํ ์ฌ๋๋ค์ ๋๊ธฐ ์ํด ์์ ์ฝ๋ ์ํ์ ์ฐธ์กฐํ์ฌ ์ฐจ๋จ์ ํด์ ํ์ธ์.
ExpandoObject
List<object>
, ์ปฌ๋ ์
์๋ 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๊ฐ ์ง์ ํ ๋ด์ฉ์ ๊ธฐ๋ฐ์ผ๋ก ์ฝ๋ ์กฐ๊ฐ์ ์์ ํ ์ ์์ต๋๊น?
๊ทธ๊ฒ์ ๋ด ์ฝ๋๊ฐ ์๋ ์๊ณ ์ด ์ค๋ ๋์ ์๋ถ๋ถ์์ ํ์ ๋ฟ์ ๋๋ค .
๊ฐ์ฅ ์ ์ฉํ ๋๊ธ
์ด์ ๋ํ ์ฌ์ฉ ์ฌ๋ก๋ ์์ต๋๋ค. HttpClient๋ฅผ ์ฌ์ฉํ์ฌ REST API๋ฅผ ํธ์ถํ๊ณ ์๋ต์์ ๋จ์ผ ์์ฑ์ ๊ฒ์ํ๊ณ ์ถ์ต๋๋ค. ์๋ต์ ๊ตฌ๋ฌธ ๋ถ์ํ๊ธฐ ์ํด ์ ์ฉ ํด๋์ค๋ฅผ ๋ง๋ค๊ณ ์ถ์ง ์์ต๋๋ค... JSON.NET์ ์ฌ์ฉํ๋ฉด "๋์ "์ ์ฌ์ฉํ๊ณ ์ ํํ ์์ฑ์ ์ก์ธ์คํ ์ ์์ต๋๋ค.