2015-04-04 3 views
2

Я новый пользователь на C#, и у меня возникают некоторые проблемы с моим кодом. Я не могу десериализации данных в формате JSON, и я не могу понять, почему:Deserialize данные JSON с C#

  webRequest = (HttpWebRequest)WebRequest.Create("http://" + Ip.ToString() + ":" + Port.ToString() + "........"); // Create a request to get server info 
      webRequest.Method = "GET"; 
      webRequest.KeepAlive = true; 
      webRequest.ContentType = "application/x-www-form-urlencoded"; 
      webRequest.CookieContainer = cookieJar; //set container for HttpWebRequest 

      webResponse = (HttpWebResponse)webRequest.GetResponse(); // Get the response. 

      reader = new StreamReader(webResponse.GetResponseStream()); 
      ServerInfo outObject = JsonConvert.DeserializeObject<ServerInfo>(reader.ToString()); 
      my_label_ServerInfo.Text = outObject.message; 

инфо-сервер класса:

public class ServerInfo 
{ 
    public string message { get; set; } 
    public string message_timestamp { get; set; } 
} 
+0

Какая ошибка вы получаете? – ZivS

+0

Для исполнения вы действительно не должны преобразовывать 'Stream' в строку. Попробуйте это вместо этого. http://www.newtonsoft.com/json/help/html/DeserializeWithJsonSerializerFromFile.htm – Aron

ответ

0

Что такое json, который приходит в вашем корпусе ответа?

Возможно, вы захотите начать с небольшого теста, чтобы убедиться, что тело ответа может быть правильно десериализовано в вашем классе ServerInfo. Это вопрос личных предпочтений, но мне нравится делать что-то более явно, поскольку это помогает свести к минимуму неожиданное поведение в будущем.

Например, вы можете украсить свой класс ServerInfo так:

// I chose MemberSerialization.OptIn so that all members need to be 
// included explicitly, rather than implicitly (which is the default) 
[JsonObject(MemberSerialization.OptIn)] 
public class ServerInfo 
{ 
    [JsonProperty] 
    public string message { get; set; } 

    [JsonProperty] 
    public string message_timestamp { get; set; } 
} 

Затем вы читаете все тело HttpWebResponse в строку, как это:

reader = new StreamReader(webResponse.GetResponseStream()); 
string responseBody = reader.ReadToEnd(); 
reader.Close(); 

И, наконец, вы десериализации ответьте в свой класс ServerInfo следующим образом:

ServerInfo serverInfo = JsonConvert.DeserializeObject<ServerInfo>(responseBody); 

Это задница ели вашего JSON придет в следующем формате (или аналогичной структура):

{ 
    "message": "Test Message", 
    "message_timestamp": "2015-04-04T20:00:00" 
} 

Конечно, вы должны сначала проверить, если ваш фактический ввод десериализует правильно.Я попробовал формат выше в модульном тесте с этой простой фрагмент кода:

var sb = new StringBuilder(); 
sb.Append("{"); 
sb.AppendLine(); 

sb.AppendFormat("\"{0}\": \"{1}\"", "message", "Test Message"); 
sb.Append(","); 
sb.AppendLine(); 

sb.AppendFormat("\"{0}\": \"{1}\"", "message_timestamp", "2015-04-04T20:00:00"); 
sb.AppendLine(); 

sb.Append("}"); 

string json = sb.ToString(); 

ServerInfo serverInfo = JsonConvert.DeserializeObject<ServerInfo>(json); 

EDIT: Я полностью согласен с Ароном в том, что вы не должны излишне использовать поля-члены и убедитесь утилизировать потоки должным образом.

Улучшение моего первоначального ответа со своими предложениями, следующий код, который я предложил ранее:

webRequest = (HttpWebRequest)WebRequest.Create("http://" + Ip.ToString() + ":" + Port.ToString() + "........"); 
webRequest.Method = "GET"; 
webRequest.KeepAlive = true; 
webRequest.ContentType = "application/x-www-form-urlencoded"; 
webRequest.CookieContainer = cookieJar; 

webResponse = (HttpWebResponse)webRequest.GetResponse(); 

reader = new StreamReader(webResponse.GetResponseStream()); 
string responseBody = reader.ReadToEnd(); 
reader.Close(); 
ServerInfo serverInfo = JsonConvert.DeserializeObject<ServerInfo> 
my_label_ServerInfo.Text = serverInfo.message; 

изменить бы в этом, который будет работать лучше и менее склонен к ошибкам (я удалил комментарии для краткости, см ответ Арона для объяснения):

var webRequest = (HttpWebRequest)WebRequest.Create("http://" + Ip.ToString() + ":" + Port.ToString() + "........"); 
webRequest.Method = "GET"; 
webRequest.KeepAlive = true; 
webRequest.ContentType = "application/x-www-form-urlencoded"; 
webRequest.CookieContainer = cookieJar; 

var webResponse = (HttpWebResponse)webRequest.GetResponse(); 

using (var stream = webResponse.GetResponseStream()) 
using (var reader = new StreamReader(stream)) 
{ 
    JsonSerializer serializer = new JsonSerializer(); 
    ServerInfo serverInfo = (ServerInfo)serializer.Deserialize(reader, typeof(ServerInfo)); 
    my_label_ServerInfo.Text = serverInfo.message; 
} 

Это будет по-прежнему работать с явными атрибутами JSON сериализации, которые я добавил в свой класс ServerInfo. Обратите внимание, что они не являются строго необходимыми, если имена свойств совпадают. Я делаю это в основном только для того, чтобы показать вам, как получить больший контроль над поведением сериализации без необходимости внедрять пользовательский JsonSerializer.

3

В C#,

reader.ToString() 

по умолчанию будет возвращать имя класса , В этом случае, «System.IO.StreamReader»

Что вы хотите

reader.ReadToEnd() 

который будет возвращать все содержимое потока в виде строки.

Это должно заставить его работать, но имейте в виду, что это не лучшая практика. Несколько областей для рассмотрения, как вы узнаете больше о C#:

  • Как уже упоминалось Aron, вы должны обернуть все потоки и читатель в "using" statement, чтобы воспользоваться Dispose pattern, который позволит исполняющему знает, что может освободить ресурсы сразу а не waiting for the finalizer
  • Как показал Фред в своем коде, вы можете избежать преобразования потока в строку и просто позволить библиотеке Json.Net сделать это.
  • Чтобы убедиться, что вы правильно бежать и форматировать запрос URL, вы можете использовать UriBuilder класс: new UriBuilder("http", ip, port, path).Uri)
  • Вы могли бы использовать новые и async дружественный HttpClient класс для загрузки данных.
2

Хотя Джефф прав в ПОЧЕМУ, он работает неправильно. Его ответ по-прежнему не является правильным способом «исправить» ваш код. Строки очень неэффективны в C# (например, почти каждый язык программирования, и мы избегаем их как можно больше).

Так что вы должны делать это вместо этого.

 //STOP USING member fields (when possible), 
     //you encourage threading problems with member fields. 
     var webRequest = (HttpWebRequest)WebRequest.Create("http://" + Ip.ToString() + ":" + Port.ToString() + "........"); // Create a request to get server info 
     webRequest.Method = "GET"; 
     webRequest.KeepAlive = true; 
     webRequest.ContentType = "application/x-www-form-urlencoded"; 
     webRequest.CookieContainer = cookieJar; //set container for HttpWebRequest 

     var webResponse = (HttpWebResponse)webRequest.GetResponse(); 

     //ALWAYS dispose your disposable correctly 
     //Not disposing HttpStreams will cause you to leak TCP/IP 
     //ports. 
     using(var stream = webResponse.GetResponseStream()) 
     using(var reader = new StreamReader(stream)) 
     { 
      JsonSerializer serializer = new JsonSerializer(); 
      ServerInfo outObject = (ServerInfo)serializer.Deserialize(reader, typeof(ServerInfo)); 
      my_label_ServerInfo.Text = outObject.message; 
     } 
0

Я хотел бы предложить подход доступа к значениям JSON с структурированных типов (JSON объект и массив), без того, чтобы заранее определить типы (например, типа ServerInfo) для десериализации в.

JsonObject serverinfo = (JsonObject) JsonObject.Load (responseStream);