경우에 따라 어레이 또는 객체에 따라서는 JSON의 시리얼화를 해제한다.
JSON을 사용하여 Facebook에서 반환된 데이터를 역직렬화하는 데 문제가 있습니다.NET 라이브러리
단순한 벽 기둥에서 돌아온 JSON은 다음과 같습니다.
{
"attachment":{"description":""},
"permalink":"http://www.facebook.com/permalink.php?story_fbid=123456789"
}
사진을 찍기 위해 반환된 JSON은 다음과 같습니다.
"attachment":{
"media":[
{
"href":"http://www.facebook.com/photo.php?fbid=12345",
"alt":"",
"type":"photo",
"src":"http://photos-b.ak.fbcdn.net/hphotos-ak-ash1/12345_s.jpg",
"photo":{"aid":"1234","pid":"1234","fbid":"1234","owner":"1234","index":"12","width":"720","height":"482"}}
],
모든 것이 잘 작동하고 나는 아무 문제가 없다.모바일 클라이언트로부터 다음과 같은 JSON을 사용한 심플한 벽면 포스트를 발견했는데, 이 1개의 포스트로 디시리얼라이즈가 실패합니다.
"attachment":
{
"media":{},
"name":"",
"caption":"",
"description":"",
"properties":{},
"icon":"http://www.facebook.com/images/icons/mobile_app.gif",
"fb_object_type":""
},
"permalink":"http://www.facebook.com/1234"
다음 클래스로서 역직렬화하겠습니다.
public class FacebookAttachment
{
public string Name { get; set; }
public string Description { get; set; }
public string Href { get; set; }
public FacebookPostType Fb_Object_Type { get; set; }
public string Fb_Object_Id { get; set; }
[JsonConverter(typeof(FacebookMediaJsonConverter))]
public List<FacebookMedia> { get; set; }
public string Permalink { get; set; }
}
FacebookMediaJsonConverter를 사용하지 않으면 "Cannot deserialize JSON object to type 'System" (JSON 개체를 직렬화할 수 없습니다)라는 오류가 나타납니다.컬렉션포괄적인.리스트1 [ Facebook Media ] 。JSON에서 미디어는 컬렉션이 아니기 때문에 말이 됩니다.
비슷한 문제를 설명하는 이 게시물을 발견했기 때문에 다음 경로를 시도했습니다.JSON을 역직렬화합니다.값이 배열일 때도 있고, " (공백 문자열)일 때도 있습니다.
컨버터는 다음과 같습니다.
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
if (reader.TokenType == JsonToken.StartArray)
return serializer.Deserialize<List<FacebookMedia>>(reader);
else
return null;
}
정상적으로 동작하지만, 새로운 예외가 있습니다.
내부 Json SerializerInternalReader.cs, Create ValueInternal(): 오브젝트를 역직렬화하는 동안 예기치 않은 토큰이 발생했습니다.PropertyName
독자의 가치값은 "permalink"입니다.스위치로 JsonToken에 대한 케이스가 없다는 것을 알 수 있습니다.Property Name(속성명)
컨버터에서 다르게 해야 할 일이 있나요?도와주셔서 감사합니다.
이 경우의 처리 방법에 대한 자세한 설명은 "Using a Custom Json Converter to fixed JSON results" (커스텀 Json 컨버터를 사용하여 잘못된 JSON 결과를 수정함)를 참조하십시오.
요약하면 기본 JSON을 확장할 수 있습니다.NET 컨버터 실행
이슈를 가진 속성에 주석 달기
[JsonConverter(typeof(SingleValueArrayConverter<OrderItem>))] public List<OrderItem> items;단일 개체에 대해 원하는 유형의 목록을 반환하도록 변환기를 확장합니다.
public class SingleValueArrayConverter<T> : JsonConverter { public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) { throw new NotImplementedException(); } public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) { object retVal = new Object(); if (reader.TokenType == JsonToken.StartObject) { T instance = (T)serializer.Deserialize(reader, typeof(T)); retVal = new List<T>() { instance }; } else if (reader.TokenType == JsonToken.StartArray) { retVal = serializer.Deserialize(reader, objectType); } return retVal; } public override bool CanConvert(Type objectType) { return true; } }
기사에서 언급한 바와 같이 이 확장자는 완전히 일반적이지는 않지만 목록을 받아도 상관없습니다.
JSON 개발자.NET은 결국 프로젝트 코드플렉스 사이트를 지원하게 되었습니다.해결책은 다음과 같습니다.
문제는 JSON 오브젝트일 때 Atribute를 지나치지 않았다는 것입니다.다음은 올바른 코드입니다.
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
if (reader.TokenType == JsonToken.StartArray)
{
return serializer.Deserialize<List<FacebookMedia>>(reader);
}
else
{
FacebookMedia media = serializer.Deserialize<FacebookMedia>(reader);
return new List<FacebookMedia>(new[] {media});
}
}
제임스는 또한 위의 방법에 대한 유닛 테스트를 제공할 정도로 친절했습니다.
위의 Camilo Martinez의 답변에 따르면, 이것은 범용 버전을 사용하는 보다 현대적이고, 안전하고, 보다 슬림하고, 완전한 접근법입니다.JsonConverterC# 8.0 입니다.또한 질문에 따라 예상된 2개 이외의 토큰에 대해서도 예외를 발생시킵니다.코드가 필요 이상으로 동작하지 않으면 예기치 않은 데이터를 잘못 처리하여 향후 버그가 발생할 위험이 있습니다.
internal class SingleObjectOrArrayJsonConverter<T> : JsonConverter<ICollection<T>> where T : class, new()
{
public override void WriteJson(JsonWriter writer, ICollection<T> value, JsonSerializer serializer)
{
serializer.Serialize(writer, value.Count == 1 ? (object)value.Single() : value);
}
public override ICollection<T> ReadJson(JsonReader reader, Type objectType, ICollection<T> existingValue, bool hasExistingValue, JsonSerializer serializer)
{
return reader.TokenType switch
{
JsonToken.StartObject => new Collection<T> {serializer.Deserialize<T>(reader)},
JsonToken.StartArray => serializer.Deserialize<ICollection<T>>(reader),
_ => throw new ArgumentOutOfRangeException($"Converter does not support JSON token type {reader.TokenType}.")
};
}
}
그런 다음 다음과 같이 속성을 장식합니다.
[JsonConverter(typeof(SingleObjectOrArrayJsonConverter<OrderItem>))]
public ICollection<OrderItem> items;
을 '있다'에서 '로 바꿨습니다.List<>로로 합니다.ICollection<>으로 이 JSON POCO가 이 타입으로 되어 있으면List<> 치환해 주세요.ICollection ★★★★★★★★★★★★★★★★★」CollectionList상기의 모든 코드로.
시스템을 살펴봅니다.런타임c# 프레임워크의 시리얼화 네임스페이스를 사용하면 원하는 위치에 빠르게 도달할 수 있습니다.
만약 당신이 원한다면 이 프로젝트에서 몇 가지 샘플 코드를 체크할 수 있습니다(내 작업을 연결하려고 하는 것이 아니라 나는 당신이 하고 있는 일을 거의 정확하게 끝냈지만 다른 소스 API로).
도움이 됐으면 좋겠네요
.Net 프레임워크
using Newtonsoft.Json;
using System.IO;
public Object SingleObjectOrArrayJson(string strJson)
{
if(String.IsNullOrEmpty(strJson))
{
//Example
strJson= @"{
'CPU': 'Intel',
'PSU': '500W',
'Drives': [
'DVD read/writer'
/*(broken)*/,
'500 gigabyte hard drive',
'200 gigabyte hard drive'
]
}";
}
JsonTextReader reader = new JsonTextReader(new StringReader(strJson));
//Initialize Read
reader.Read();
if (reader.TokenType == JsonToken.StartArray)
{
return JsonConvert.DeserializeObject<List<Object>>(strJson);
}
else
{
Object media = JsonConvert.DeserializeObject<Object>(strJson);
return new List<Object>(new[] {media});
}
}
참고: "개체"는 응답의 Json 속성에 따라 정의해야 합니다.
뉴턴소프트에 대한 마르티네즈와 mfanto의 대답을 설명하다.Newtonsoft와 함께 사용할 수 있습니다.
다음은 목록(및 올바른 이름)이 아닌 배열로 수행하는 예입니다.
public class SingleValueArrayConverter<T> : JsonConverter
{
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
serializer.Serialize(writer, value);
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
if (reader.TokenType == JsonToken.StartObject
|| reader.TokenType == JsonToken.String
|| reader.TokenType == JsonToken.Integer)
{
return new T[] { serializer.Deserialize<T>(reader) };
}
return serializer.Deserialize<T[]>(reader);
}
public override bool CanConvert(Type objectType)
{
return true;
}
}
그런 다음 속성 위에 다음과 같이 적습니다.
[JsonProperty("INSURANCE")]
[JsonConverter(typeof(SingleValueArrayConverter<InsuranceInfo>))]
public InsuranceInfo[] InsuranceInfo { get; set; }
나머지는 뉴턴소프트가 해줄 거야
return JsonConvert.DeserializeObject<T>(json);
마르티네즈와 엠판토에게 건배!
믿거나 말거나, 이것은 하위 항목과 함께 작동합니다.(필요할 수도 있습니다.) 그래서...다른 오브젝트/어레이 하이브리드가 있는 경우 해당 속성에서 다시 사용합니다.
이를 통해 개체를 json으로 다시 초기화할 수도 있습니다.재시리얼라이즈 할 때는 항상 어레이가 됩니다.
수업은 이렇게 쓰는 게 좋을 것 같은데...!!!
public class FacebookAttachment
{
[JsonProperty("attachment")]
public Attachment Attachment { get; set; }
[JsonProperty("permalink")]
public string Permalink { get; set; }
}
public class Attachment
{
[JsonProperty("media")]
public Media Media { get; set; }
[JsonProperty("name")]
public string Name { get; set; }
[JsonProperty("caption")]
public string Caption { get; set; }
[JsonProperty("description")]
public string Description { get; set; }
[JsonProperty("properties")]
public Properties Properties { get; set; }
[JsonProperty("icon")]
public string Icon { get; set; }
[JsonProperty("fb_object_type")]
public string FbObjectType { get; set; }
}
public class Media
{
}
public class Properties
{
}
언급URL : https://stackoverflow.com/questions/5224697/deserializing-json-when-sometimes-array-and-sometimes-object
'source' 카테고리의 다른 글
| JSON 기반 RESTful 코드의 예외를 처리하는 방법 (0) | 2023.03.01 |
|---|---|
| remove_action()이 WordPress 플러그인에서 작동하지 않음 (0) | 2023.03.01 |
| 제품 유형에 따라 WooCommerce의 "ADD TO CART" 버튼 옆에 있는 커스텀 버튼 (0) | 2023.03.01 |
| WooCommerce에서 변수로 제품 사용자 지정 필드 값을 가져옵니다. (0) | 2023.03.01 |
| 반응: 이벤트 핸들러에서 null입니다. (0) | 2023.03.01 |