c# - ServiceStack.Text 和 Twitter JSON

标签 c# servicestack deserialization servicestack-text

我正在尝试使用 ServiceStack.Text 反序列化 twitter RateLimit Json。我为下拉的 JSON 创建了一个适当的 DTO 对象(查看帖子底部)。我利用 System.Runtime.Serialization 将字段重命名为更友好的名称(我在 Twitter 的许多其他 DTO 对象中使用了它)。反序列化对象时,RateLimitContext 正确反序列化,但 Resources 下的所有项目都反序列化为 null。我怀疑这个特定对象的 DataMemberNames 有问题,因为它们包含几个“特殊”字符。这是 ServiceStack.Text 中的错误还是我的 DTO 中遗漏了什么?

[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 = "/users/search")]
        public RateLimitEntry Search { get; set; }

        [DataMember(Name = "/users/suggestions")]
        public RateLimitEntry Suggestions { get; set; }

        [DataMember(Name = "/users/contributors")]
        public RateLimitEntry Contributors { get; set; }

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

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

        [DataMember(Name = "/users/contributees")]
        public RateLimitEntry Contributees { get; set; }

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

        [DataMember(Name = "/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; }
    }
}

这是 API 返回的示例 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": {
        "/users/profile_banner": {
            "limit": 180,
            "remaining": 180,
            "reset": 1380314146
        },
        "/users/suggestions/:slug/members": {
            "limit": 15,
            "remaining": 15,
            "reset": 1380314146
        },
        "/users/show/:id": {
            "limit": 180,
            "remaining": 180,
            "reset": 1380314146
        },
        "/users/suggestions": {
            "limit": 15,
            "remaining": 15,
            "reset": 1380314146
        },
        "/users/lookup": {
            "limit": 180,
            "remaining": 180,
            "reset": 1380314146
        },
        "/users/search": {
            "limit": 180,
            "remaining": 180,
            "reset": 1380314146
        },
        "/users/contributors": {
            "limit": 15,
            "remaining": 15,
            "reset": 1380314146
        },
        "/users/contributees": {
            "limit": 15,
            "remaining": 15,
            "reset": 1380314146
        },
        "/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
        }
    }
}

最佳答案

[DataMember] 名称仅用于指定单个 字段名别名,即它们没有嵌套并且不能像您所做的那样包含非字母数字字符在这里。

这是一个 Twitter DTOs for use in ServiceStack 的例子序列化程序。

关于c# - ServiceStack.Text 和 Twitter JSON,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19097650/

相关文章:

c# - 使用授权 header 信号器进行未经授权的访问

c# - 使用 Servicestack 在 RabbitMQ 队列上设置 TTL

apache-kafka - Kafka AVRO - 从长到日期时间的转换

redis - Windows 2008 R2 上使用 Redis 的大型数据集的缓存策略

asp.net - 使用 servicestack 防止 401 更改为 302

c# - 当您不知道命名空间时如何反序列化 XML?

java - 嵌入式Java对象的Jackson反序列化

c# - 是否可以在代码优先上下文中添加 View ?

c# - 检查记录列是否有一些特殊值

c# - 大型数据库的模型优先或代码优先