JSON.NET을 사용하여 JSON 데이터를 C #으로 역 직렬화


144

저는 C # 및 JSON 데이터 작업에 비교적 익숙하지 않으며 지침을 찾고 있습니다. .NET3.5SP1 및 JSON.NET 3.5r6과 함께 C # 3.0을 사용하고 있습니다.

JSON 구조에서 채워야하는 정의 된 C # 클래스가 있습니다. 그러나 웹 서비스에서 검색된 항목에 대한 모든 JSON 구조가 C # 클래스 내에 정의 된 가능한 모든 속성을 포함하지는 않습니다.

나는 틀린, 어려운 방법으로 일을하고 있었고 JObject에서 각 값을 하나씩 골라 문자열을 원하는 클래스 속성으로 변환했습니다.

JsonSerializer serializer = new JsonSerializer();
var o = (JObject)serializer.Deserialize(myjsondata);

MyAccount.EmployeeID = (string)o["employeeid"][0];

JSON 구조를 C # 클래스로 역 직렬화하고 JSON 소스에서 누락 된 데이터를 처리하는 가장 좋은 방법은 무엇입니까?

내 수업은 다음과 같이 정의됩니다.

  public class MyAccount
  {

    [JsonProperty(PropertyName = "username")]
    public string UserID { get; set; }

    [JsonProperty(PropertyName = "givenname")]
    public string GivenName { get; set; }

    [JsonProperty(PropertyName = "sn")]
    public string Surname { get; set; }

    [JsonProperty(PropertyName = "passwordexpired")]
    public DateTime PasswordExpire { get; set; }

    [JsonProperty(PropertyName = "primaryaffiliation")]
    public string PrimaryAffiliation { get; set; }

    [JsonProperty(PropertyName = "affiliation")]
    public string[] Affiliation { get; set; }

    [JsonProperty(PropertyName = "affiliationstatus")]
    public string AffiliationStatus { get; set; }

    [JsonProperty(PropertyName = "affiliationmodifytimestamp")]
    public DateTime AffiliationLastModified { get; set; }

    [JsonProperty(PropertyName = "employeeid")]
    public string EmployeeID { get; set; }

    [JsonProperty(PropertyName = "accountstatus")]
    public string AccountStatus { get; set; }

    [JsonProperty(PropertyName = "accountstatusexpiration")]
    public DateTime AccountStatusExpiration { get; set; }

    [JsonProperty(PropertyName = "accountstatusexpmaxdate")]
    public DateTime AccountStatusExpirationMaxDate { get; set; }

    [JsonProperty(PropertyName = "accountstatusmodifytimestamp")]
    public DateTime AccountStatusModified { get; set; }

    [JsonProperty(PropertyName = "accountstatusexpnotice")]
    public string AccountStatusExpNotice { get; set; }

    [JsonProperty(PropertyName = "accountstatusmodifiedby")]
    public Dictionary<DateTime, string> AccountStatusModifiedBy { get; set; }

    [JsonProperty(PropertyName = "entrycreatedate")]
    public DateTime EntryCreatedate { get; set; }

    [JsonProperty(PropertyName = "entrydeactivationdate")]
    public DateTime EntryDeactivationDate { get; set; }

  }

파싱 ​​할 JSON 샘플은 다음과 같습니다.

{
    "givenname": [
        "Robert"
    ],
    "passwordexpired": "20091031041550Z",
    "accountstatus": [
        "active"
    ],
    "accountstatusexpiration": [
        "20100612000000Z"
    ],
    "accountstatusexpmaxdate": [
        "20110410000000Z"
    ],
    "accountstatusmodifiedby": {
        "20100214173242Z": "tdecker",
        "20100304003242Z": "jsmith",
        "20100324103242Z": "jsmith",
        "20100325000005Z": "rjones",
        "20100326210634Z": "jsmith",
        "20100326211130Z": "jsmith"
    },
    "accountstatusmodifytimestamp": [
        "20100312001213Z"
    ],
    "affiliation": [
        "Employee",
        "Contractor",
        "Staff"
    ],
    "affiliationmodifytimestamp": [
        "20100312001213Z"
    ],
    "affiliationstatus": [
        "detached"
    ],
    "entrycreatedate": [
        "20000922072747Z"
    ],
    "username": [
        "rjohnson"
    ],
    "primaryaffiliation": [
        "Staff"
    ],
    "employeeid": [
        "999777666"
    ],
    "sn": [
        "Johnson"
    ]
}

답변:



76

일반적인 DeserializeObject 메소드를 사용해 보셨습니까?

JsonConvert.DeserializeObject<MyAccount>(myjsondata);

JSON 데이터에서 누락 된 필드는 단순히 NULL로 두어야합니다.

최신 정보:

JSON 문자열이 배열이면 다음을 시도하십시오.

var jarray = JsonConvert.DeserializeObject<List<MyAccount>>(myjsondata);

jarray그런 다음이어야합니다 List<MyAccount>.

다른 업데이트 :

당신이 얻는 예외는 객체 배열과 일치하지 않습니다. 직렬화 기가 사전 유형 accountstatusmodifiedby속성에 문제가 있다고 생각합니다 .

accountstatusmodifiedby 직렬화 에서 속성을 제외하고 도움이되는지 확인하십시오. 그렇다면 해당 속성을 다르게 표현해야 할 수도 있습니다.

설명서 : Json.NET을 사용하여 JSON 직렬화 및 역 직렬화


감사. 그러나 "JSON 배열을 'System.String'유형으로 역 직렬화 할 수 없습니다."라는 오류가 발생합니다. JSON givenname 배열을 클래스 GivenName 문자열로 직렬화 해제하려고 할 때 (예 :). C # 클래스에서 문자열로 정의한 JSON 속성은 단일 요소 배열 일뿐입니다. 이것이 직렬화 해제 프로세스 중에 이러한 종류의 문제가 발생함에 따라 하나씩 값을 선택하기 시작한 이유입니다. 내가 간과하는 다른 마술?

따라서 ... DateTime AccountStatusExpiration(예를 들어)는 코드에 정의 된대로 null을 허용하지 않습니다. 널 입력 가능하게하려면 무엇이 필요합니까? ?로 간단히 변경 DateTime하십시오 DateTime?.
Hamish Grubijan

50

답변은 https://stackoverflow.com/a/10718128/776476 에서 재현되었습니다.

C # dynamic형식을 사용하면 작업을보다 쉽게 ​​수행 할 수 있습니다. 이 기술은 또한 마술 문자열에 의존하지 않기 때문에 리팩토링을 더 간단하게 만듭니다.

제이슨

json아래 문자열은 HTTP API 호출에서 간단한 응답이며 두 가지 속성을 정의 Id하고 Name.

{"Id": 1, "Name": "biofractal"}

씨#

사용은 JsonConvert.DeserializeObject<dynamic>()단순히 일반적인 방법으로 해당 속성에 액세스 동적 타입으로이 문자열을 역 직렬화합니다.

var results = JsonConvert.DeserializeObject<dynamic>(json);
var id = results.Id;
var name= results.Name;

참고 : NewtonSoft 어셈블리의 NuGet 링크는 http://nuget.org/packages/newtonsoft.json 입니다. 추가하는 것을 잊지 마십시오 : using Newtonsoft.Json;클래스에 액세스하십시오.


7
<dynamic>의 사용을 좋아하십시오. 그러나 결과를 얻으려면이 작업을 수행해야했습니다. result [ "Id"]. Value and result [ "Name"]. Value
fredw

1
dynamic이 훌륭한 대안이지만 위의 예제는 'magic strings'를 사용하지 않고 대신 일반적인 VS 리팩토링 기술 중에 업데이트되는 강력한 형식의 제네릭을 사용하고 있습니다 (이 질문의 범위를 벗어난 MVC의 View 내부는 제외).
gcoleman0828

4
당신은 여전히 ​​'매직 스트링'을 가지고 있으며 이제는 동적을 사용하여 숨겨졌습니다!
Ian Ringrose

사실, @IanRingrose의 지적대로 biofractal은 "매직 스트링"으로 거꾸로되어 있습니다. 에 의해 리턴 된 동적 오브젝트 DeserializeObject<dynamic>는 정의에 따라 "유형 확인"이 아닙니다. 다음 줄 그래서 results.Idresults.Name컴파일 타임에 확인할 수 없습니다. 런타임시 오류가 발생합니다. 이 같은 강력한 형식의 호출과 대조하십시오 DeserializeObject<List<MyAccount>>. 이러한 속성에 대한 참조 는 컴파일 타임에 확인할 있습니다. 을 사용 dynamic하면 편리하지만 속성 이름으로 "매직 문자열"이 도입됩니다. 견고성 감소 IMHO.
ToolmakerSteve

8

당신이 사용할 수있는:

JsonConvert.PopulateObject(json, obj);

여기 : jsonjson 문자열이며 obj대상 객체입니다. 참조 :

참고 : PopulateObject()목록 데이터는, 이후의 OBJ 삭제되지 Populate(), obj's목록 구성원의 의지가 JSON 문자열에서 원래의 데이터와 데이터를 포함


2
PopulateObject-Populate가 오브젝트 모델에 없습니다.
amok

1
이것은 나를 위해 완벽했습니다! 꽤 복잡한 JSON 문자열이있는 문제가 있었는데 C # 객체로 캐스트하려고 할 때 'NotNull'로 표시된 항목은 JSON 문자열에 존재하더라도 객체에서 누락됩니다. 아주 이상한. 나는이 방법을 사용했으며 완벽하게 작동했습니다!
jward01

3

bbant의 답변을 바탕으로 원격 URL에서 JSON을 직렬화 해제하는 완벽한 솔루션입니다.

using Newtonsoft.Json;
using System.Net.Http;

namespace Base
{
    public class ApiConsumer<T>
    {
        public T data;
        private string url;

        public CalendarApiConsumer(string url)
        {
            this.url = url;
            this.data = getItems();
        }

        private T getItems()
        {
            T result = default(T);
            HttpClient client = new HttpClient();

            // This allows for debugging possible JSON issues
            var settings = new JsonSerializerSettings
            {
                Error = (sender, args) =>
                {
                    if (System.Diagnostics.Debugger.IsAttached)
                    {
                        System.Diagnostics.Debugger.Break();
                    }
                }
            };

            using (HttpResponseMessage response = client.GetAsync(this.url).Result)
            {
                if (response.IsSuccessStatusCode)
                {
                    result = JsonConvert.DeserializeObject<T>(response.Content.ReadAsStringAsync().Result, settings);
                }
            }
            return result;
        }
    }
}

사용법은 다음과 같습니다.

ApiConsumer<FeedResult> feed = new ApiConsumer<FeedResult>("http://example.info/feeds/feeds.aspx?alt=json-in-script");

Xamasoft JSON 클래스 생성기를FeedResult 사용하여 생성 된 클래스는 어디에 있습니까?

다음은 웹 버전에서 설명 할 수없는 이상한 속성 이름을 허용하는 사용 된 설정의 스크린 샷입니다 .

Xamasoft JSON 클래스 생성기


1

객체를 잘못 만들었다는 것을 알았습니다. http://json2csharp.com/ 을 사용 하여 JSON에서 객체 클래스를 생성했습니다. 올바른 Oject가 있으면 문제없이 캐스트 할 수있었습니다. Norbit, Noob 실수. 같은 문제가있는 경우 추가 할 것이라고 생각했습니다.


1

자세한 내용은 일부 클래스 생성기 온라인을 확인하십시오. 그러나 일부 답변이 유용하다고 생각합니다. 유용한 내 접근 방식은 다음과 같습니다.

다음 코드는 동적 메소드를 염두에두고 작성되었습니다.

dynObj = (JArray) JsonConvert.DeserializeObject(nvm);

foreach(JObject item in dynObj) {
 foreach(JObject trend in item["trends"]) {
  Console.WriteLine("{0}-{1}-{2}", trend["query"], trend["name"], trend["url"]);
 }
}

이 코드는 기본적으로 Json 문자열에 포함 된 멤버에 액세스 할 수있게합니다. 수업이 필요없는 다른 방법. query, trendurljson으로 문자열에 포함 된 개체입니다.

이 웹 사이트를 사용할 수도 있습니다 . 수업을 100 % 신뢰하지 말고 아이디어를 얻으십시오.


0

샘플 데이터가 정확하고 주어진 이름 및 대괄호로 묶인 다른 항목이 JS의 배열이라고 가정하면 해당 데이터 유형에 List를 사용하고 싶을 것입니다. 그리고 accountstatusexpmaxdate에 대한 목록 ... 예를 들어 날짜의 형식이 잘못되어 예제의 다른 내용이 확실하지 않은 것 같습니다.

이것은 오래된 게시물이지만 문제를 기록하고 싶었습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.