2014-07-21 17 views
1

我想反序列化由Yahoo!返回的JSON。幻想API,使用這種資源:反序列化Yahoo!幻想API播放器JSON

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]'

如果我排除PlayerRoot類中的Player屬性,則反序列化是成功的(但當然缺乏大多數有用的信息)。

我正在使用手工編碼的對象模型; 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" 
    } 
} 

一注:"0"對象在JSON上面會重複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獲得大部分我需要的東西。

+1

這可能有助於http://stackoverflow.com/questions/24536533/how-can-i-parse-a-json-string-that-would-cause-illegal-c-sharp-identifiers – EZI

+0

我可以使用'[DeserializeAs(Name =「0」)]'屬性反序列化「0」元素。 – LiquidPony

+2

併爲1或2或.... N? ,你會聲明n個類/屬性嗎? – EZI

回答

1

我無法使用RestSharp的內置解串器反序列化這個JSON。我認爲雅虎在這裏返回一些相當奇怪的JSON(players對象本質上是一個對象列表的列表字典),這種奇怪是使自動解序列化困難。

我解決了這個問題,使用Json.NETCustomCreationConverter。我不是特別這個解決方案,我認爲有一個更好的方式來做到這一點,但時間緊迫,這是我想出了(錯誤處理/記錄/等,爲簡潔,刪除):

新的客戶端代碼

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; } 
} 

CustomCreationCon換器

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; 
    } 
}