2013-09-30 1 views
2

ServiceStack.Text로 트위터 RateLimit Json을 비 직렬화하려고 시도 중입니다. 나는 JSON이 풀려나는 적절한 DTO 객체 (게시물 하단을 보라)를 만들었다. System.Runtime.Serialization을 사용하여 더 친숙한 이름으로 필드의 이름을 바꿨습니다 (나는 이것을 Twitter의 다른 DTO 개체에서 많이 사용했습니다). 객체의 직렬화를 해제하면 RateLimitContext가 제대로 deserialize되지만 Resources 아래의 모든 항목은 null로 직렬화됩니다. 나는이 특별한 객체에 대해 DataMemberNames에 뭔가 문제가 있다고 의심한다. 왜냐하면 그것들은 몇개의 "특별한"문자들을 포함하고 있기 때문이다. 이것은 ServiceStack.Text의 버그입니까, 아니면 DTO에 누락 된 것이 있습니까?ServiceStack.Text 및 Twitter JSON

{ 
"rate_limit_context": { 
    "access_token": "ajksldjalsda-akjflkasjfltpowfaalksjdfAPQPIJFaflkjaq" 
}, 
"resources": { 
    "lists": { 
     "/lists/subscribers": { 
      "limit": 180, 
      "remaining": 180, 
      "reset": 1380314146 
     }, 
     "/lists/list": { 
      "limit": 15, 
      "remaining": 15, 
      "reset": 1380314146 
     }, 
     "/lists/memberships": { 
      "limit": 15, 
      "remaining": 15, 
      "reset": 1380314146 
     }, 
     "/lists/ownerships": { 
      "limit": 15, 
      "remaining": 15, 
      "reset": 1380314146 
     }, 
     "/lists/subscriptions": { 
      "limit": 15, 
      "remaining": 15, 
      "reset": 1380314146 
     }, 
     "/lists/members": { 
      "limit": 180, 
      "remaining": 180, 
      "reset": 1380314146 
     }, 
     "/lists/subscribers/show": { 
      "limit": 15, 
      "remaining": 15, 
      "reset": 1380314146 
     }, 
     "/lists/statuses": { 
      "limit": 180, 
      "remaining": 180, 
      "reset": 1380314146 
     }, 
     "/lists/members/show": { 
      "limit": 15, 
      "remaining": 15, 
      "reset": 1380314146 
     }, 
     "/lists/show": { 
      "limit": 15, 
      "remaining": 15, 
      "reset": 1380314146 
     } 
    }, 
    "application": { 
     "/application/rate_limit_status": { 
      "limit": 180, 
      "remaining": 178, 
      "reset": 1380314022 
     } 
    }, 
    "friendships": { 
     "/friendships/incoming": { 
      "limit": 15, 
      "remaining": 15, 
      "reset": 1380314146 
     }, 
     "/friendships/lookup": { 
      "limit": 15, 
      "remaining": 15, 
      "reset": 1380314146 
     }, 
     "/friendships/outgoing": { 
      "limit": 15, 
      "remaining": 15, 
      "reset": 1380314146 
     }, 
     "/friendships/no_retweets/ids": { 
      "limit": 15, 
      "remaining": 15, 
      "reset": 1380314146 
     }, 
     "/friendships/show": { 
      "limit": 180, 
      "remaining": 180, 
      "reset": 1380314146 
     } 
    }, 
    "blocks": { 
     "/blocks/ids": { 
      "limit": 15, 
      "remaining": 15, 
      "reset": 1380314146 
     }, 
     "/blocks/list": { 
      "limit": 15, 
      "remaining": 15, 
      "reset": 1380314146 
     } 
    }, 
    "geo": { 
     "/geo/similar_places": { 
      "limit": 15, 
      "remaining": 15, 
      "reset": 1380314146 
     }, 
     "/geo/search": { 
      "limit": 15, 
      "remaining": 15, 
      "reset": 1380314146 
     }, 
     "/geo/reverse_geocode": { 
      "limit": 15, 
      "remaining": 15, 
      "reset": 1380314146 
     }, 
     "/geo/id/:place_id": { 
      "limit": 15, 
      "remaining": 15, 
      "reset": 1380314146 
     } 
    }, 
    "users": { 
     "https://stackoverflow.com/users/profile_banner": { 
      "limit": 180, 
      "remaining": 180, 
      "reset": 1380314146 
     }, 
     "https://stackoverflow.com/users/suggestions/:slug/members": { 
      "limit": 15, 
      "remaining": 15, 
      "reset": 1380314146 
     }, 
     "https://stackoverflow.com/users/show/:id": { 
      "limit": 180, 
      "remaining": 180, 
      "reset": 1380314146 
     }, 
     "https://stackoverflow.com/users/suggestions": { 
      "limit": 15, 
      "remaining": 15, 
      "reset": 1380314146 
     }, 
     "https://stackoverflow.com/users/lookup": { 
      "limit": 180, 
      "remaining": 180, 
      "reset": 1380314146 
     }, 
     "https://stackoverflow.com/users/search": { 
      "limit": 180, 
      "remaining": 180, 
      "reset": 1380314146 
     }, 
     "https://stackoverflow.com/users/contributors": { 
      "limit": 15, 
      "remaining": 15, 
      "reset": 1380314146 
     }, 
     "https://stackoverflow.com/users/contributees": { 
      "limit": 15, 
      "remaining": 15, 
      "reset": 1380314146 
     }, 
     "https://stackoverflow.com/users/suggestions/:slug": { 
      "limit": 15, 
      "remaining": 15, 
      "reset": 1380314146 
     } 
    }, 
    "prompts": { 
     "/prompts/record_event": { 
      "limit": 15, 
      "remaining": 15, 
      "reset": 1380314146 
     }, 
     "/prompts/suggest": { 
      "limit": 15, 
      "remaining": 15, 
      "reset": 1380314146 
     } 
    }, 
    "followers": { 
     "/followers/list": { 
      "limit": 15, 
      "remaining": 15, 
      "reset": 1380314146 
     }, 
     "/followers/ids": { 
      "limit": 15, 
      "remaining": 15, 
      "reset": 1380314146 
     } 
    }, 
    "statuses": { 
     "/statuses/mentions_timeline": { 
      "limit": 15, 
      "remaining": 15, 
      "reset": 1380314146 
     }, 
     "/statuses/show/:id": { 
      "limit": 180, 
      "remaining": 180, 
      "reset": 1380314146 
     }, 
     "/statuses/oembed": { 
      "limit": 180, 
      "remaining": 180, 
      "reset": 1380314146 
     }, 
     "/statuses/retweeters/ids": { 
      "limit": 15, 
      "remaining": 15, 
      "reset": 1380314146 
     }, 
     "/statuses/home_timeline": { 
      "limit": 15, 
      "remaining": 15, 
      "reset": 1380314146 
     }, 
     "/statuses/user_timeline": { 
      "limit": 180, 
      "remaining": 180, 
      "reset": 1380314146 
     }, 
     "/statuses/retweets/:id": { 
      "limit": 15, 
      "remaining": 15, 
      "reset": 1380314146 
     }, 
     "/statuses/retweets_of_me": { 
      "limit": 15, 
      "remaining": 15, 
      "reset": 1380314146 
     } 
    }, 
    "help": { 
     "/help/privacy": { 
      "limit": 15, 
      "remaining": 15, 
      "reset": 1380314146 
     }, 
     "/help/tos": { 
      "limit": 15, 
      "remaining": 15, 
      "reset": 1380314146 
     }, 
     "/help/configuration": { 
      "limit": 15, 
      "remaining": 15, 
      "reset": 1380314146 
     }, 
     "/help/languages": { 
      "limit": 15, 
      "remaining": 15, 
      "reset": 1380314146 
     } 
    }, 
    "friends": { 
     "/friends/ids": { 
      "limit": 15, 
      "remaining": 15, 
      "reset": 1380314146 
     }, 
     "/friends/list": { 
      "limit": 15, 
      "remaining": 15, 
      "reset": 1380314146 
     } 
    }, 
    "direct_messages": { 
     "/direct_messages/show": { 
      "limit": 15, 
      "remaining": 15, 
      "reset": 1380314146 
     }, 
     "/direct_messages/sent_and_received": { 
      "limit": 15, 
      "remaining": 15, 
      "reset": 1380314146 
     }, 
     "/direct_messages/sent": { 
      "limit": 15, 
      "remaining": 15, 
      "reset": 1380314146 
     }, 
     "/direct_messages": { 
      "limit": 15, 
      "remaining": 15, 
      "reset": 1380314146 
     } 
    }, 
    "account": { 
     "/account/verify_credentials": { 
      "limit": 15, 
      "remaining": 15, 
      "reset": 1380314146 
     }, 
     "/account/settings": { 
      "limit": 15, 
      "remaining": 15, 
      "reset": 1380314146 
     } 
    }, 
    "favorites": { 
     "/favorites/list": { 
      "limit": 15, 
      "remaining": 15, 
      "reset": 1380314146 
     } 
    }, 
    "saved_searches": { 
     "/saved_searches/destroy/:id": { 
      "limit": 15, 
      "remaining": 15, 
      "reset": 1380314146 
     }, 
     "/saved_searches/list": { 
      "limit": 15, 
      "remaining": 15, 
      "reset": 1380314146 
     }, 
     "/saved_searches/show/:id": { 
      "limit": 15, 
      "remaining": 15, 
      "reset": 1380314146 
     } 
    }, 
    "search": { 
     "/search/tweets": { 
      "limit": 180, 
      "remaining": 180, 
      "reset": 1380314146 
     } 
    }, 
    "trends": { 
     "/trends/available": { 
      "limit": 15, 
      "remaining": 15, 
      "reset": 1380314146 
     }, 
     "/trends/place": { 
      "limit": 15, 
      "remaining": 15, 
      "reset": 1380314146 
     }, 
     "/trends/closest": { 
      "limit": 15, 
      "remaining": 15, 
      "reset": 1380314146 
     } 
    } 
} 

}

답변

0

[DataMember] 이름의 만 하나의 필드 이름의 별칭을 지정하기위한, 즉 그들이 중첩 할 수 있습니다하지 않을된다 ': 여기

[DataContract] 
public class RateLimitResult 
{ 
    [DataMember(Name = "rate_limit_context")] 
    public RateLimitContextEntry RateLimitContext { get; set; } 

    [DataContract] 
    public class RateLimitContextEntry 
    { 
     [DataMember(Name = "access_token")] 
     public string AccessToken { get; set; } 
    } 

    [DataMember(Name = "resources")] 
    public ResourcesEntry Resources { get; set; } 

    [DataContract] 
    public class RateLimitEntry 
    { 
     [DataMember(Name = "remaining")] 
     public int Remaining { get; set; } 

     [DataMember(Name = "reset")] 
     public long Reset { get; set; } 

     [DataMember(Name = "limit")] 
     public int Limit { get; set; } 
    } 

    [DataContract] 
    public class HelpEntry 
    { 
     [DataMember(Name = "/help/privacy")] 
     public RateLimitEntry Privacy { get; set; } 

     [DataMember(Name = "/help/configuration")] 
     public RateLimitEntry Configuration { get; set; } 

     [DataMember(Name = "/help/tos")] 
     public RateLimitEntry Tos { get; set; } 

     [DataMember(Name = "/help/languages")] 
     public RateLimitEntry Languages { get; set; } 
    } 

    [DataContract] 
    public class StatusesEntry 
    { 
     [DataMember(Name = "/statuses/oembed")] 
     public RateLimitEntry Oembed { get; set; } 

     [DataMember(Name = "/statuses/user_timeline")] 
     public RateLimitEntry UserTimeline { get; set; } 

     [DataMember(Name = "/statuses/mentions_timeline")] 
     public RateLimitEntry MentionsTimeline { get; set; } 

     [DataMember(Name = "/statuses/home_timeline")] 
     public RateLimitEntry HomeTimeline { get; set; } 

     [DataMember(Name = "/statuses/show/:id")] 
     public RateLimitEntry ShowId { get; set; } 

     [DataMember(Name = "/statuses/retweets/:id")] 
     public RateLimitEntry RetweetsId { get; set; } 

     [DataMember(Name = "/statuses/retweets_of_me")] 
     public RateLimitEntry RetweetsOfMe { get; set; } 
    } 

    [DataContract] 
    public class UsersEntry 
    { 
     [DataMember(Name = "https://stackoverflow.com/users/search")] 
     public RateLimitEntry Search { get; set; } 

     [DataMember(Name = "https://stackoverflow.com/users/suggestions")] 
     public RateLimitEntry Suggestions { get; set; } 

     [DataMember(Name = "https://stackoverflow.com/users/contributors")] 
     public RateLimitEntry Contributors { get; set; } 

     [DataMember(Name = "https://stackoverflow.com/users/suggestions/:slug/members")] 
     public RateLimitEntry SuggestionsSlugMembers { get; set; } 

     [DataMember(Name = "https://stackoverflow.com/users/suggestions/:slug")] 
     public RateLimitEntry SuggestionsSlug { get; set; } 

     [DataMember(Name = "https://stackoverflow.com/users/contributees")] 
     public RateLimitEntry Contributees { get; set; } 

     [DataMember(Name = "https://stackoverflow.com/users/lookup")] 
     public RateLimitEntry Lookup { get; set; } 

     [DataMember(Name = "https://stackoverflow.com/users/profile_banner")] 
     public RateLimitEntry ProfileBanner { get; set; } 
    } 

    [DataContract] 
    public class SearchEntry 
    { 
     [DataMember(Name = "/search/tweets")] 
     public RateLimitEntry Tweets { get; set; } 
    } 

    [DataContract] 
    public class TrendsEntry 
    { 
     [DataMember(Name = "/trends/available")] 
     public RateLimitEntry Available { get; set; } 

     [DataMember(Name = "/trends/place")] 
     public RateLimitEntry Place { get; set; } 

     [DataMember(Name = "/trends/closest")] 
     public RateLimitEntry Closest { get; set; } 
    } 

    [DataContract] 
    public class SavedSearchesEntry 
    { 
     [DataMember(Name = "/saved_searches/destroy/:id")] 
     public RateLimitEntry DestroyId { get; set; } 

     [DataMember(Name = "/saved_searches/list")] 
     public RateLimitEntry List { get; set; } 

     [DataMember(Name = "/saved_searches/show/:id")] 
     public RateLimitEntry ShowId { get; set; } 
    } 

    [DataContract] 
    public class FavoritesEntry 
    { 
     [DataMember(Name = "/favorites/list")] 
     public RateLimitEntry List { get; set; } 
    } 

    [DataContract] 
    public class AccountEntry 
    { 
     [DataMember(Name = "/account/verify_credentials")] 
     public RateLimitEntry VerifyCredentials { get; set; } 

     [DataMember(Name = "/account/settings")] 
     public RateLimitEntry Settings { get; set; } 
    } 

    [DataContract] 
    public class DirectMessagesEntry 
    { 
     [DataMember(Name = "/direct_messages/show")] 
     public RateLimitEntry Show { get; set; } 

     [DataMember(Name = "/direct_messages/sent_and_received")] 
     public RateLimitEntry SentAndReceived { get; set; } 

     [DataMember(Name = "/direct_messages/sent")] 
     public RateLimitEntry Sent { get; set; } 

     [DataMember(Name = "/direct_messages")] 
     public RateLimitEntry Messages { get; set; } 
    } 

    [DataContract] 
    public class FriendsEntry 
    { 
     [DataMember(Name = "/friends/ids")] 
     public RateLimitEntry Ids { get; set; } 

     [DataMember(Name = "/friends/list")] 
     public RateLimitEntry List { get; set; } 
    } 

    [DataContract] 
    public class FollowersEntry 
    { 
     [DataMember(Name = "/followers/list")] 
     public RateLimitEntry List { get; set; } 

     [DataMember(Name = "/followers/ids")] 
     public RateLimitEntry Ids { get; set; } 
    } 

    [DataContract] 
    public class PromptsEntry 
    { 
     [DataMember(Name = "/prompts/record_event")] 
     public RateLimitEntry RecordEvent { get; set; } 

     [DataMember(Name = "/prompts/suggest")] 
     public RateLimitEntry Suggest { get; set; } 
    } 

    [DataContract] 
    public class GeoEntry 
    { 
     [DataMember(Name = "/geo/similar_places")] 
     public RateLimitEntry SimilarPlaces { get; set; } 

     [DataMember(Name = "/geo/search")] 
     public RateLimitEntry Search { get; set; } 

     [DataMember(Name = "/geo/reverse_geocode")] 
     public RateLimitEntry ReverseGeocode { get; set; } 

     [DataMember(Name = "/geo/id/:place_id")] 
     public RateLimitEntry PlaceId { get; set; } 
    } 

    [DataContract] 
    public class BlocksEntry 
    { 
     [DataMember(Name = "/blocks/ids")] 
     public RateLimitEntry Ids { get; set; } 

     [DataMember(Name = "/blocks/list")] 
     public RateLimitEntry List { get; set; } 
    } 

    [DataContract] 
    public class FriendshipsEntry 
    { 
     [DataMember(Name = "/friendships/incoming")] 
     public RateLimitEntry Incoming { get; set; } 

     [DataMember(Name = "/friendships/lookup")] 
     public RateLimitEntry Lookup { get; set; } 

     [DataMember(Name = "/friendships/outgoing")] 
     public RateLimitEntry Outgoing { get; set; } 

     [DataMember(Name = "/friendships/no_retweets/ids")] 
     public RateLimitEntry NoRetweetsIds { get; set; } 

     [DataMember(Name = "/friendships/show")] 
     public RateLimitEntry Show { get; set; } 
    } 

    [DataContract] 
    public class ApplicationEntry 
    { 
     [DataMember(Name = "/application/rate_limit_status")] 
     public RateLimitEntry RateLimitStatus { get; set; } 
    } 

    [DataContract] 
    public class ListsEntry 
    { 
     [DataMember(Name = "/lists/subscribers")] 
     public RateLimitEntry Subscribers { get; set; } 

     [DataMember(Name = "/lists/list")] 
     public RateLimitEntry List { get; set; } 

     [DataMember(Name = "/lists/memberships")] 
     public RateLimitEntry Memberships { get; set; } 

     [DataMember(Name = "/lists/ownerships")] 
     public RateLimitEntry Ownerships { get; set; } 

     [DataMember(Name = "/lists/subscriptions")] 
     public RateLimitEntry Subscriptions { get; set; } 

     [DataMember(Name = "/lists/members")] 
     public RateLimitEntry Members { get; set; } 

     [DataMember(Name = "/lists/subscribers/show")] 
     public RateLimitEntry ShowSubscribers { get; set; } 

     [DataMember(Name = "/lists/statuses")] 
     public RateLimitEntry Statuses { get; set; } 

     [DataMember(Name = "/lists/members/show")] 
     public RateLimitEntry ShowMembers { get; set; } 

     [DataMember(Name = "/lists/show")] 
     public RateLimitEntry Show { get; set; } 
    } 

    [DataContract] 
    public class ResourcesEntry 
    { 
     [DataMember(Name = "lists")] 
     public ListsEntry Lists { get; set; } 

     [DataMember(Name = "application")] 
     public ApplicationEntry Application { get; set; } 

     [DataMember(Name = "friendships")] 
     public FriendshipsEntry Friendships { get; set; } 

     [DataMember(Name = "blocks")] 
     public BlocksEntry Blocks { get; set; } 

     [DataMember(Name = "geo")] 
     public GeoEntry Geo { get; set; } 

     [DataMember(Name = "users")] 
     public UsersEntry Users { get; set; } 

     [DataMember(Name = "prompts")] 
     public PromptsEntry Prompts { get; set; } 

     [DataMember(Name = "followers")] 
     public FollowersEntry Followers { get; set; } 

     [DataMember(Name = "statuses")] 
     public StatusesEntry Statuses { get; set; } 

     [DataMember(Name = "help")] 
     public HelpEntry Help { get; set; } 

     [DataMember(Name = "friends")] 
     public FriendsEntry Friends { get; set; } 

     [DataMember(Name = "direct_messages")] 
     public DirectMessagesEntry DirectMessages { get; set; } 

     [DataMember(Name = "account")] 
     public AccountEntry Account { get; set; } 

     [DataMember(Name = "favorites")] 
     public FavoritesEntry Favorites { get; set; } 

     [DataMember(Name = "saved_searches")] 
     public SavedSearchesEntry SavedSearches { get; set; } 

     [DataMember(Name = "search")] 
     public SearchEntry Search { get; set; } 

     [DataMember(Name = "trends")] 
     public TrendsEntry Trends { get; set; } 
    } 
} 

샘플 JSON은 API에 의해 반환 여기에서했던 것처럼 영숫자가 아닌 문자가 포함되어 있지 않습니다.

다음은 Twitter DTOs for use in ServiceStack 시리얼 라이저의 예입니다.

+0

내가 언급 했어야 할 점은 JSON.Net에는 이러한 필드 이름에 문제가 없다는 점입니다. 나는 디시리얼라이저를 교환하려고 할 때만이 문제에 부딪쳤다. –

+0

API에서 반환 한 샘플 Json으로 게시물을 업데이트했습니다. 해당 필드 이름을 처리하는 것에 대한 제안 사항이 있습니까? –

+0

'Dictionary Lists'또는 [동적으로 구문 분석] (https://github.com/ServiceStack/ServiceStack.Text#supports-dynamic-json)과 같은 JSON과 일치하는 속성을 사용하십시오. – mythz