2013-09-30 3 views
2

Я пытаюсь десериализовать twitter RateLimit Json с ServiceStack.Text. Я создал соответствующий объект DTO (см. Нижнюю часть сообщения) для снятия JSON. Я использовал System.Runtime.Serialization, чтобы переименовать поля в более дружественные имена (я использовал это во многих других объектах DTO из Twitter). При десериализации объекта RateLimitContext десериализуется правильно, однако все элементы в разделе Ресурсы десериализуются до нуля. Я подозреваю, что что-то не так с DataMemberNames для этого конкретного объекта, так как они содержат несколько «специальных» символов. Это ошибка в ServiceStack.Text или я что-то пропустил в своем DTO?ServiceStack.Text и Twitter JSON

[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:

{ 
"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] Имя являются только для указания одного FIELDNAME псевдоним, то есть они не гнездились и может» t содержит не буквенно-цифровые символы, как вы это делали.

Приведен пример Twitter DTOs for use in ServiceStack сериализаторов.

+0

Я должен был упомянуть, у JSON.Net не было проблем с этими именами полей. Я столкнулся с этой проблемой, когда попытался обменять десериализаторы. –

+0

Я обновил сообщение с образцом Json, возвращенным API. Есть ли у вас какие-либо предложения по обработке этих имен полей? –

+0

Используйте свойство, соответствующее JSON, например 'Dictionary Lists' или [анализировать его динамически] (https://github.com/ServiceStack/ServiceStack.Text#supports-dynamic-json) – mythz

Смежные вопросы