2013-08-23 5 views
1

Я имею дело с JSON в первый раз и получаю данные от OpenTSDB. Я создал класс C# для десериализации JSON, но получаю ошибку «Невозможно десериализовать текущий массив JSON», как описано ниже.JSON object deserialize to C# object - OpenTSDB

Мой C# код, чтобы получить JSON:

var request = WebRequest.Create("http://localhost:4242/api/query?start=2013/08/21-12:00:00&end=2013/08/22-12:00:00&m=sum:tcollector.collector.lines_sent&o=&yrange=%5B0:%5D&wxh=924x773"); 
     request.ContentType = "application/json; charset=utf-8"; 
     string text; 
     try 
     { 
      var response = (HttpWebResponse) request.GetResponse(); 
      using (var sr = new StreamReader(response.GetResponseStream())) 
      { 
       text = sr.ReadToEnd(); 
      } 

      uxResponse.Text = text; 

      OpenTSDBResponse myObject = (OpenTSDBResponse)Newtonsoft.Json.JsonConvert.DeserializeObject(text, typeof(OpenTSDBResponse)); 

      var variable = Newtonsoft.Json.JsonConvert.DeserializeObject(text); 

      //var tester = myObject; 
     } 
     catch (Exception ex) 
     { 
      uxResponse.Text = GetFullExceptionMessage(ex); 
     } 

JSON я получаю из кода выше (то есть 'текст' переменной):

[{ 
"metric":"tcollector.collector.lines_sent", 
"tags": 
    { 
    "host":"ubuntu1" 
    }, 
"aggregateTags":["collector"], 
"dps": 
    { 
    "1377050434":1271779.0, 
    "1377050494":1272073.0, 
    "1377050554":1272502.0, 
    "1377050614":1273632.0, 
    "1377050674":1273867.0 
    } 
}] 

Моя C# классы

internal class OpenTSDBResponse 
    { 
     [JsonProperty("metric")] 
     public string Metric { get; set; } 

     [JsonProperty("tags")] 
     public Tags Tags { get; set; } 

     [JsonProperty("aggregateTags")] 
     public string[] AggregateTags { get; set; } 

     [JsonProperty("dps")] 
     public List<TimeValue> TimeValues { get; set; } 
    } 

internal class Tags 
{ 

    [JsonProperty("host")] 
    public string Host { get; set; } 
} 

internal class TimeValue 
{ 
    [JsonProperty("Time")] 
    public double Time { get; set; } 

    [JsonProperty("Value")] 
    public double Value { get; set; } 
} 

Ошибка при десериализации объекта:

Не может десериализации текущий массив JSON (например, [1,2,3]) в тип 'MyNamespace.OpenTSDBResponse', потому что для этого требуется объект JSON (например, {"name": "value"}) для десериализации. Чтобы исправить эту ошибку , либо измените JSON на объект JSON (например, {"name": "value"}) или изменить десериализованный тип на массив или тип, который реализует интерфейс коллекции (например, ICollection, IList), например List, который может десериализоваться из массива JSON , JsonArrayAttribute может также быть добавлены к типу, чтобы заставить его десериализации из JSON array.Path «», строка 1, позиция 1.

Дополнительная информация

Я использовал Codeproject десериализации JSON проект для создания моих базовых классов, но он создал новое свойство C# для каждого «1377050434»: 1271779.0, поэтому я обновил свой класс TimeValue. http://www.codeproject.com/Tips/79435/Deserialize-JSON-with-C

Вопрос:

Как я могу получить это в соответствующий C# класса структуры?

Дополнительная информация в ответ на комментарии пользователей ниже:

  • bjaminn Комментарий: Я считаю, что JSON вы получаете массив. Исключение пытается сказать, что вы конвертируете объект [] в OpenTSDBResponse, когда действительно хотите OpenTSDBResponse []. Другим способом отладки этого было бы посмотреть переменную переменной и посмотреть, какой тип она находится в отладчике. Конечно, строка, которая выдает исключение, должна быть прокомментирована.

    Результат: Я изменил десериализации как этот

    OpenTSDBResponse [] MyObject = (OpenTSDBResponse []) Newtonsoft.Json.JsonConvert.DeserializeObject (текст, typeof (OpenTSDBResponse []));

    но получил следующее сообщение об ошибке, когда я побежал:

    Не может десериализации текущего объекта JSON (например, { «имя»: «значение»}) в тип «System.Collections.Generic.List`1 [MyNamespace.OpenTSDBResponseJsonTypes.TimeValue] ', потому что для этого требуется, чтобы десериализован массив JSON (например, [1,2,3]). Чтобы исправить эту ошибку, либо измените JSON на массив JSON (например, [1,2,3]) или изменить десериализованный тип, чтобы он был обычным типом .NET (например, не примитивным типом типа integer, а не типом коллекции, подобным массиву или списку), который можно десериализовать из объекта JSON. JsonObjectAttribute также может быть добавлен к типу, чтобы заставить его десериализацию JSON из object.Path «[0] .dps.1377050434», строки 1, позиция 121.

Дополнительных замечаний по рабочему раствору для других, новых для JSON Я добавил еще одно свойство для своего класса для Словаря, так как это действительно «unix-time-stamp-data», «Value». Это позволяет мне работать в C# с datetime/values. Возможно, лучший способ кастинга, но это работает, не вызывает заметных проблем с производительностью для моего сценария.

[JsonProperty("dps")] 
    public Dictionary<string, double> TimeValues { get; set; } 

    public List<TimeValue> DataPoints 
    { 
     get 
     { 
      List<TimeValue> times = new List<TimeValue>(); 
      DateTime dtDateTime = new DateTime(1970, 1, 1, 0, 0, 0, 0); 

      foreach (var item in TimeValues) 
      { 
       times.Add(new TimeValue 
       { 
        Time = dtDateTime.AddSeconds(double.Parse(item.Key)).ToLocalTime(), 
        Value = item.Value 
       }); 
      } 

      return times; 
     } 
    } 

ответ

1

Я считаю, что JSON, который вы получаете, представляет собой массив. Исключение пытается сказать, что вы конвертируете объект [] в OpenTSDBResponse, когда вы действительно хотите OpenTSDBResponse [].

Другим способом отладки этого является просмотр переменной переменной и посмотреть, какой тип она находится в отладчике. Конечно, строка, которая выдает исключение, должна быть прокомментирована.

Решение новой ошибки Похоже, что DPS не является надлежащим массивом JSON. Вы можете разобрать его на словарь, так как похоже, что в каждом вызове JSON ключи будут разными.

JSON convert dictionary to a list of key value pairs

Новый класс:

internal class OpenTSDBResponse 
    { 
     [JsonProperty("metric")] 
     public string Metric { get; set; } 

     [JsonProperty("tags")] 
     public Tags Tags { get; set; } 

     [JsonProperty("aggregateTags")] 
     public string[] AggregateTags { get; set; } 

     [JsonProperty("dps")] 
     public Dictionary<string,double> TimeValues { get; set; } 
    } 
+0

Я обновил свой вопрос после того, как я попробовал ваше предложение. Разная ошибка, я изменил код, как вы ожидали? Благодарю. – John

+0

Спасибо за обновленный пример, словарь отсортировал это для меня. – John

+0

Могу ли я использовать словарь для словаря , поскольку строки являются датами unix? – John

0
You can such so modify your Json Data and your C# Code,for example 
    [{ 
    "metric":"tcollector.collector.lines_sent", 
    "tags": 
    { 
    "host":"ubuntu1" 
    }, 
    "aggregateTags":["collector"], 
    "dps": 
    [ 
    {"Time":"1377050434","Value":1271779.0}, 
    {"Time":"1377050554","Value":1272502.0}   
    ] 
    }] 
c# Code:   
You provide the data is an Array,so when you deserialize the string,you must such so use generic format of deserializeobject 

    object obj=Newtonsoft.Json.JsonConvert.DeserializeObject<List<OpenTSDBResponse>>(json.ToString()); 
+0

Я не думаю, что могу изменить JSON - я считаю, что он поставляется с OpenTSDB в стандартном формате. – John