public class DeserializeModel
{
...
public JsonArray Blocks { get; set;}
...
}
// 코드 품질 이슈....
public GetTextOfTarget(JsonArray DeserializeModel.Blocks)
{
foreach (var block in blocks)
{
var items = block.AsObject();
...
...
...
if (isTarget: true)
{
foreach (var item in items)
{
if (item.Key.Equals("text"))
{
foreach (var textItem in item.Value.AsObject())
{
if (textItem.Key.Equals("text"))
{
text = textItem.Value.ToString();
break;
}
}
break;
}
}
}
break;
}
}
중첩된 JosnObject에서 원하는 데이터를 찾기 위해 코드를 작성했습니다. GetTextOfTarget가 if와 foreach문이 중첩의 중첩이 되서 가독성의 문제 등…이 있지 않나 생각이 듭니다.
역직렬화 Model을 작성하여 key에 매칭 시키는 방법도 있긴한데(DeserializeModel처럼), 여러 종류의 Json 데이터 값이 들어오고 그 것에 맞는 Model을 일일이 작성하는 것도 아닌거 같구요, 결론은 코드 품질을 높이고 싶은데, 좋은 방법을 모르겠습니다
분명히 누군가는 저와 같은 생각을 하고 같은 상황을 걲었을 텐데, 좋은 예제가 안 보이는군요.
보통 이런 경우 검색 키워드 선정이 잘 못 되었거나, 간단한건데 삽질하는 경우 더라구요.
여러 종류의 Json 형태가 들어오는데, 거기에 맞게 Model 클래스를 다 작성하기엔 일이 너무 많을 때
저는 dynamic으로 처리를 했던 것 같습니다… (기억이 안 나네요;)
일단 구글링 해보니 마제에 참고할 만한게 올라와있긴 합니다.
Newton.Json을 쓰시는거라면
여기를 참고하셔서 아래와 같이 한다면, 목표로 하는데에 더 가까울 것 같아요.
var definition = new { Name = "" };
string json1 = @"{'Name':'James'}";
var customer1 = JsonConvert.DeserializeAnonymousType(json1, definition);
Console.WriteLine(customer1.Name);
// James
string json2 = @"{'Name':'Mike'}";
var customer2 = JsonConvert.DeserializeAnonymousType(json2, definition);
Console.WriteLine(customer2.Name);
// Mike
var json = """
...
""";
var jsonNode = JsonNode.Parse(json)!;
var blocks = jsonNode["blocks"]!;
foreach (var block in blocks.AsArray())
{
if (block is null)
continue;
if (block["type"]!.GetValue<string>() is "targetType")
{
Console.WriteLine(block["text"]!["text"]!.GetValue<string>());
}
}
// Root myDeserializedClass = JsonConvert.DeserializeObject<Root>(myJsonResponse);
public class Block
{
public string type { get; set; }
public string block_id { get; set; }
public Text text { get; set; }
}
public class Root
{
public string type { get; set; }
public string token { get; set; }
public string action_ts { get; set; }
public Team team { get; set; }
public User user { get; set; }
public List<Block> blocks { get; set; }
}
public class Team
{
public string id { get; set; }
public string domain { get; set; }
}
public class Text
{
public string type { get; set; }
public string text { get; set; }
public bool verbatim { get; set; }
}
public class User
{
public string id { get; set; }
public string username { get; set; }
public string team_id { get; set; }
public string name { get; set; }
}
기본기가 부족하다고 하지 마시고 어떻게 장악해나갈 것이냐 글로 기록하면서 구체화 하면 도움이 많이 됩니다.
먼저 일을 잘하는 방향과 개발을 잘하는 방향은 다르다는 것을 구분해야 하고요,
뭐든지 결과는 단계적으로 완전해지는 프로토타입의 형태일 수 밖에 없다는 한계도 정확히 이해해야 하고
이 JSON 데이터를 이용해서 위의 온라인 변환 툴을 이용해 다음의 클래스를 얻을 수 있습니다.
// Root myDeserializedClass = JsonConvert.DeserializeObject<Root>(myJsonResponse);
public class Poster
{
public string extras { get; set; }
public string description { get; set; }
public int user_id { get; set; }
public object primary_group_id { get; set; }
public object flair_group_id { get; set; }
}
public class Root
{
public List<User> users { get; set; }
public List<object> primary_groups { get; set; }
public List<object> flair_groups { get; set; }
public TopicList topic_list { get; set; }
}
public class TagsDescriptions
{
}
public class Topic
{
public int id { get; set; }
public string title { get; set; }
public string fancy_title { get; set; }
public string slug { get; set; }
public int posts_count { get; set; }
public int reply_count { get; set; }
public int highest_post_number { get; set; }
public string image_url { get; set; }
public DateTime created_at { get; set; }
public DateTime last_posted_at { get; set; }
public bool bumped { get; set; }
public DateTime bumped_at { get; set; }
public string archetype { get; set; }
public bool unseen { get; set; }
public int last_read_post_number { get; set; }
public int unread { get; set; }
public int new_posts { get; set; }
public int unread_posts { get; set; }
public bool pinned { get; set; }
public object unpinned { get; set; }
public bool visible { get; set; }
public bool closed { get; set; }
public bool archived { get; set; }
public int notification_level { get; set; }
public bool bookmarked { get; set; }
public bool liked { get; set; }
public TagsDescriptions tags_descriptions { get; set; }
public int views { get; set; }
public int like_count { get; set; }
public bool has_summary { get; set; }
public string last_poster_username { get; set; }
public int category_id { get; set; }
public bool pinned_globally { get; set; }
public object featured_link { get; set; }
public bool has_accepted_answer { get; set; }
public bool can_have_answer { get; set; }
public List<Poster> posters { get; set; }
}
public class TopicList
{
public bool can_create_topic { get; set; }
public string more_topics_url { get; set; }
public int per_page { get; set; }
public List<Topic> topics { get; set; }
}
public class User
{
public int id { get; set; }
public string username { get; set; }
public string name { get; set; }
public string avatar_template { get; set; }
public object flair_name { get; set; }
public bool admin { get; set; }
public bool moderator { get; set; }
public int trust_level { get; set; }
}
이제 이 클래스를 이용해서 특정 정보를 취해보겠습니다.
using System.Text.Json;
var c = new HttpClient();
var json = await c.GetStringAsync("https://forum.dotnetdev.kr/latest.json?no_definitions=true&page=1");
var page = JsonSerializer.Deserialize<Root>(json);
var topic = page!.topic_list.topics[0];
Console.WriteLine(topic.title);
Console.WriteLine(topic.views);
Console.WriteLine(page.users.FirstOrDefault(x => x.id == topic.posters[0].user_id)!.username);
// -----
// Root myDeserializedClass = JsonConvert.DeserializeObject<Root>(myJsonResponse);
public class Poster
{
public string extras { get; set; }
public string description { get; set; }
public int user_id { get; set; }
public object primary_group_id { get; set; }
public object flair_group_id { get; set; }
}
public class Root
{
public List<User> users { get; set; }
public List<object> primary_groups { get; set; }
public List<object> flair_groups { get; set; }
public TopicList topic_list { get; set; }
}
public class TagsDescriptions
{
}
public class Topic
{
public int id { get; set; }
public string title { get; set; }
public string fancy_title { get; set; }
public string slug { get; set; }
public int posts_count { get; set; }
public int reply_count { get; set; }
public int highest_post_number { get; set; }
public string image_url { get; set; }
public DateTime created_at { get; set; }
public DateTime last_posted_at { get; set; }
public bool bumped { get; set; }
public DateTime bumped_at { get; set; }
public string archetype { get; set; }
public bool unseen { get; set; }
public int last_read_post_number { get; set; }
public int unread { get; set; }
public int new_posts { get; set; }
public int unread_posts { get; set; }
public bool pinned { get; set; }
public object unpinned { get; set; }
public bool visible { get; set; }
public bool closed { get; set; }
public bool archived { get; set; }
public int notification_level { get; set; }
public bool? bookmarked { get; set; }
public bool? liked { get; set; }
public TagsDescriptions tags_descriptions { get; set; }
public int views { get; set; }
public int like_count { get; set; }
public bool has_summary { get; set; }
public string last_poster_username { get; set; }
public int category_id { get; set; }
public bool pinned_globally { get; set; }
public object featured_link { get; set; }
public bool has_accepted_answer { get; set; }
public bool can_have_answer { get; set; }
public List<Poster> posters { get; set; }
}
public class TopicList
{
public bool can_create_topic { get; set; }
public string more_topics_url { get; set; }
public int per_page { get; set; }
public List<Topic> topics { get; set; }
}
public class User
{
public int id { get; set; }
public string username { get; set; }
public string name { get; set; }
public string avatar_template { get; set; }
public object flair_name { get; set; }
public bool admin { get; set; }
public bool moderator { get; set; }
public int trust_level { get; set; }
}