2015-04-04 83 views
2

我是C#中的新用户,我的代码存在一些问题。 我不能反序列化JSON数据,我无法理解为什么:用C反序列化JSON数据#

  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 2015-04-04 17:10:00

+0

对于性能,你真的不应该把'Stream'转换成'string'。试试这个。 http://www.newtonsoft.com/json/help/html/DeserializeWithJsonSerializerFromFile.htm – Aron 2015-04-04 18:37:17

回答

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

这是屁股uming您的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); 

编辑:我完全,你不应该使用不必要成员字段,并始终确保妥善处置流用阿隆同意。

提高我原来的答复与他的建议,下面的代码我刚才所说:

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

这将仍然与我添加到您的ServerInfo类显式的JSON序列化属性一起工作。请注意,如果属性名称匹配,则它们不是绝对必需的。我这样做主要是为了向您展示如何在不需要实现定制的JsonSerializer的情况下获得对序列化行为的更多控制权。

3

在C#中,

reader.ToString() 

将默认返回类的名字。在这种情况下,“就是System.IO.StreamReader”

你想要的是

reader.ReadToEnd() 

将返回流的全部内容作为一个字符串。

这应该会导致它工作,但请注意这不是最佳实践。考虑几个方面,你了解C#:

  • 正如阿隆所说,你应该换你所有的流和读者"using" statementDispose pattern的,这将让运行时知道它可以释放资源的时候了而不是waiting for the finalizer
  • 正如Fred在他的代码中演示的那样,您可以避免将流转换为字符串,并让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);