我正在尝试反序列化Yahoo!返回的JSON。 fantasy API,使用此资源:
http://fantasysports.yahooapis.com/fantasy/v2/game/nfl/players;start=0;count=1?format=json
在尝试反序列化Player
对象(这是一个数组数组)时,RestSharp抛出以下异常:
无法投射类型' RestSharp.JsonArray'键入' System.Collections.Generic.IDictionary`2 [System.String,System.Object]'
如果我从Player
类中排除PlayerRoot
属性,则反序列化成功(但当然缺少大部分有用信息)。
我使用的是手工编码的对象模型; Visual Studio中的Paste Special-->Paste JSON as Classes
操作不适用于下面显示的JSON,但它看起来似乎是有效的JSON。
我的对象模型是否存在错误的?我的假设是关于player
元素(嵌套数组)的某些内容正在炸毁RestSharp JSON反序列化器。
客户代码
public void GetPlayers()
{
int start = 0;
int count = 1;
var request =
new RestRequest("game/{gameType}/players;start={start};count={count}",
Method.GET);
request.AddUrlSegment("gameType", _gameType);
request.AddUrlSegment("start", start.ToString());
request.AddUrlSegment("count", count.ToString());
// This extension adds "?format=json" to the query string
request.AddJsonParam();
var response = _client.Execute<FantasyModel>(request);
var data = (FantasyModel)response.Data;
}
模型
public class FantasyModel
{
public FantasyContent FantasyContent { get; set; }
}
public class FantasyContent
{
[DeserializeAs(Name = "xml:lang")]
public string Language { get; set; }
[DeserializeAs(Name = "yahoo:uri")]
public string YahooUri { get; set; }
public string Time { get; set; }
public string Copyright { get; set; }
public string RefreshRate { get; set; }
public List<Game> Game { get; set; }
}
public class Game
{
public string GameKey { get; set; }
public string GameId { get; set; }
public string Name { get; set; }
public string Code { get; set; }
public string Type { get; set; }
public string Url { get; set; }
public string Season { get; set; }
public StatCategories StatCategories { get; set; }
public Players Players { get; set; }
}
public class Players
{
[DeserializeAs(Name = "0")]
public PlayerRoot PlayerRoot { get; set; }
public int Count { get; set; }
}
public class PlayerRoot
{
public PlayerRoot()
{
Player = new List<List<Player>>();
}
public List<List<Player>> Player { get; set; }
}
public class Player
{
public Player()
{
Name = new PlayerName();
ByeWeeks = new ByeWeeks();
Headshot = new Headshot();
EligiblePositions = new List<EligiblePosition>();
}
public string PlayerKey { get; set; }
public string PlayerId { get; set; }
public PlayerName Name { get; set; }
public string EditorialPlayerKey { get; set; }
public string EditorialTeamKey { get; set; }
public string EditorialTeamFullName { get; set; }
public string EditorialTeamAbbr { get; set; }
public ByeWeeks ByeWeeks { get; set; }
public string UniformNumber { get; set; }
public string DisplayPosition { get; set; }
public Headshot Headshot { get; set; }
public string ImageUrl { get; set; }
public string IsUndroppable { get; set; }
public string PositionType { get; set; }
public List<EligiblePosition> EligiblePositions { get; set; }
}
public class PlayerName
{
public string Full { get; set; }
public string First { get; set; }
public string Last { get; set; }
public string AsciiFirst { get; set; }
public string AsciiLast { get; set; }
}
public class ByeWeeks
{
public string Week { get; set; }
}
public class Headshot
{
public string Url { get; set; }
public string Size { get; set; }
}
public class EligiblePosition
{
public string Position { get; set; }
}
JSON
{
"fantasy_content": {
"xml:lang": "en-US",
"yahoo:uri": "\/fantasy\/v2\/game\/nfl\/players;count=1;start=0",
"game": [
{
"game_key": "331",
"game_id": "331",
"name": "Football",
"code": "nfl",
"type": "full",
"url": "http:\/\/football.fantasysports.yahoo.com\/f1",
"season": "2014"
},
{
"players": {
"0": {
"player": [
[
{
"player_key": "331.p.8850"
},
{
"player_id": "8850"
},
{
"name": {
"full": "Jamaal Charles",
"first": "Jamaal",
"last": "Charles",
"ascii_first": "Jamaal",
"ascii_last": "Charles"
}
},
{
"editorial_player_key": "nfl.p.8850"
},
{
"editorial_team_key": "nfl.t.12"
},
{
"editorial_team_full_name": "Kansas City Chiefs"
},
{
"editorial_team_abbr": "KC"
},
{
"bye_weeks": {
"week": "6"
}
},
{
"uniform_number": "25"
},
{
"display_position": "RB"
},
{
"headshot": {
"url": "http:\/\/l.yimg.com\/iu\/api\/res\/1.2\/084uD0cG9qCYdPSjJLX9.A--\/YXBwaWQ9eXZpZGVvO2NoPTg2MDtjcj0xO2N3PTY1OTtkeD0xO2R5PTE7Zmk9dWxjcm9wO2g9NjA7cT0xMDA7dz00Ng--\/http:\/\/l.yimg.com\/j\/assets\/i\/us\/sp\/v\/nfl\/players_l\/20120913\/8850.jpg",
"size": "small"
},
"image_url": "http:\/\/l.yimg.com\/iu\/api\/res\/1.2\/084uD0cG9qCYdPSjJLX9.A--\/YXBwaWQ9eXZpZGVvO2NoPTg2MDtjcj0xO2N3PTY1OTtkeD0xO2R5PTE7Zmk9dWxjcm9wO2g9NjA7cT0xMDA7dz00Ng--\/http:\/\/l.yimg.com\/j\/assets\/i\/us\/sp\/v\/nfl\/players_l\/20120913\/8850.jpg"
},
{
"is_undroppable": "0"
},
{
"position_type": "O"
},
{
"eligible_positions": [
{
"position": "RB"
}
]
},
[ ],
[ ]
]
]
},
"count": 1
}
}
],
"time": "215.82293510437ms",
"copyright": "Data provided by Yahoo! and STATS, LLC",
"refresh_rate": "60"
}
}
一个注意事项:上面JSON中的"0"
对象将重复n
次,game/{gameType}/players;start={start};count={count}
,其中n = {count}
。生成的JSON看起来像:
{
"fantasy_content": {
...
"players": {
"0": { }
"1": { }
"2": { }
...
出于这个问题的目的,我只带回一个对象({count} = 1
)。
修改
进一步审核后,player
对象应为List<List<object>>
或object[][]
,因为播放器的每个属性都是数组中自己的元素。
我仍然不确定如何使用RestSharp
反序列化器反序列化该内容,但我可以使用Json.NET
获得我需要的大部分内容。
答案 0 :(得分:1)
我无法使用RestSharp内置的反序列化器反序列化此JSON。我认为雅虎在这里返回一些相当奇怪的JSON(players
对象本质上是一个对象列表列表的字典),而这种奇怪之处在于使自动反序列化变得困难。
我使用Json.NET
和CustomCreationConverter
解决了这个问题。我并不特别喜欢这个解决方案,我认为有更好的方法可以做到这一点,但是在紧迫的期限内,这就是我提出的(为简洁起见,错误处理/记录/删除等) :
新客户代码
var request =
new RestRequest("game/{gameType}/players;start={start};count={count}", Method.GET);
request.AddUrlSegment("gameType", _gameType);
request.AddUrlSegment("start", start.ToString());
request.AddUrlSegment("count", count.ToString());
request.AddJsonParam();
var response = _client.Execute(request);
var json = JObject.Parse(response.Content);
var playersJson = json["fantasy_content"]["game"][1]["players"];
// Remove the count element
playersJson.Last.Remove();
var players = JsonConvert.DeserializeObject<Dictionary<string, Player>>(
playersJson.ToString(), new JsonPlayerConverter());
新玩家类
public class Player
{
public Player()
{
Name = new PlayerName();
ByeWeeks = new ByeWeeks();
Headshot = new Headshot();
EligiblePositions = new List<EligiblePosition>();
}
[JsonProperty(PropertyName = "player_key")]
public string PlayerKey { get; set; }
[JsonProperty(PropertyName = "player_id")]
public string PlayerId { get; set; }
[JsonProperty(PropertyName = "name")]
public PlayerName Name { get; set; }
[JsonProperty(PropertyName = "editorial_player_key")]
public string EditorialPlayerKey { get; set; }
[JsonProperty(PropertyName = "editorial_team_key")]
public string EditorialTeamKey { get; set; }
[JsonProperty(PropertyName = "editorial_team_full_name")]
public string EditorialTeamFullName { get; set; }
[JsonProperty(PropertyName = "editorial_team_abbr")]
public string EditorialTeamAbbr { get; set; }
[JsonProperty(PropertyName = "bye_weeks")]
public ByeWeeks ByeWeeks { get; set; }
[JsonProperty(PropertyName = "uniform_number")]
public string UniformNumber { get; set; }
[JsonProperty(PropertyName = "display_position")]
public string DisplayPosition { get; set; }
[JsonProperty(PropertyName = "headshot")]
public Headshot Headshot { get; set; }
[JsonProperty(PropertyName = "image_url")]
public string ImageUrl { get; set; }
[JsonProperty(PropertyName = "is_undroppable")]
public string IsUndroppable { get; set; }
[JsonProperty(PropertyName = "position_type")]
public string PositionType { get; set; }
[JsonProperty(PropertyName = "eligible_positions")]
public List<EligiblePosition> EligiblePositions { get; set; }
}
<强> CustomCreationConverter 强>
public class JsonPlayerConverter : CustomCreationConverter<Player>
{
public override Player Create(Type objectType)
{
throw new NotImplementedException();
}
public Player Create(Type objectType, JObject obj)
{
var array = obj["player"][0];
var content = array.Children<JObject>();
var player = new Player();
foreach (var prop in player.GetType().GetProperties())
{
var attr = prop.GetCustomAttributes(typeof(JsonPropertyAttribute), false).FirstOrDefault();
var propName = ((JsonPropertyAttribute)attr).PropertyName;
var jsonElement = content.FirstOrDefault(c => c.Properties()
.Any(p => p.Name == propName));
var value = jsonElement.GetValue(propName);
var type = prop.PropertyType;
if (type == typeof(string))
{
prop.SetValue(player, (string)value, null);
}
else if (type == typeof(PlayerName))
{
var playerName = JsonConvert.DeserializeObject<PlayerName>(value.ToString());
prop.SetValue(player, (PlayerName)playerName, null);
}
else if (type == typeof(Headshot))
{
var headshot = JsonConvert.DeserializeObject<Headshot>(value.ToString());
prop.SetValue(player, headshot, null);
}
else if (type == typeof(ByeWeeks))
{
var byeWeeks = JsonConvert.DeserializeObject<ByeWeeks>(value.ToString());
prop.SetValue(player, byeWeeks, null);
}
else if (type == typeof(List<EligiblePosition>))
{
var eligiblePositions = JsonConvert.DeserializeObject<List<EligiblePosition>>(value.ToString());
prop.SetValue(player, eligiblePositions, null);
}
}
return player;
}
public override object ReadJson(Newtonsoft.Json.JsonReader reader, Type objectType, object existingValue, Newtonsoft.Json.JsonSerializer serializer)
{
var obj = JObject.Load(reader);
var target = Create(objectType, obj);
serializer.Populate(obj.CreateReader(), target);
return target;
}
}