關於通過webclient和JSON格式報文與服務器之間通訊的解決方法和遇到的難題


話說做這個很久了,不過我比較磨洋工。所以托了很久,今天才真正跑通了整個流程。

一開始老師要我做的時候,我有點沒明白意思,后來看了msdn后明白了不少。

我要做的是用一句話來概括就是,通過JSON來與后台的J2EE通訊,操作數據。

但就是這樣一個簡單的任務,我大概有認真做了一個禮拜吧。

 

下面說說主要的實現方法:

首先我們要提到webclient這個類,這是system自帶的一個模仿web瀏覽器的類,用它來模仿POST訪問(其實還能GET、PUT、DELETE)。

 

具體的思路是:首先實體化一個webclient,打開端口下載或者上傳JSON字符串,然后通過綁定實體類的方法來序列化或者反序列化JSON報文,最后做到我們需要的數據操作。

 

具體代碼如下:

 

 

1、首先我們需要綁定實體類,之后用微軟的自帶類庫來解析(也可以用JSON.NET這個開源的第三方類庫,不過有些方法我還不懂)

[DataContract]
        public class jsontext
        {
            [DataMember(Order = 0, IsRequired = true)]
            public int total { get; set; }

            [DataMember(Order = 1, IsRequired = true)]
            public weatherInfo[] rows { get; set; }
        }

        [DataContract]
        public class weatherInfo
        {
            [DataMember(Order = 0, IsRequired = true)]
            public int id { get; set; }

            [DataMember(Order = 1)]
            public double weatherType { get; set; }

            [DataMember(Order = 2)]
            public string weatherName { get; set; }

            [DataMember(Order = 3)]
            public double maxTemperature { get; set; }

            [DataMember(Order = 4)]
            public double minTemperature { get; set; }

            [DataMember(Order = 5)]
            public double rainFall { get; set; }

            [DataMember(Order = 6)]
            public double snowFall { get; set; }
        }

        [DataContract]
        public class weatherInsert
        {
            [DataMember(Order = 0, Name = "weatherInfo.iweatherType")]
            public double iweatherType { get; set; }

            [DataMember(Order = 1, Name = "weatherInfo.cweatherName")]
            public string cweatherName { get; set; }

            [DataMember(Order = 2, Name = "weatherInfo.imaxTemperature")]
            public double imaxTemperature { get; set; }

            [DataMember(Order = 3, Name = "weatherInfo.iminTemperature")]
            public double iminTemperature { get; set; }

            [DataMember(Order = 4, Name = "weatherInfo.irainFall")]
            public double irainFall { get; set; }

            [DataMember(Order = 5, Name = "weatherInfo.isnowFall")]
            public double isnowFall { get; set; }
           
        }

 

 

2、然后實例一個webclinet

WebClient webclient = new WebClient();            
            if (!webclient.IsBusy)
            {
                webclient.Encoding = System.Text.Encoding.UTF8;//防止亂碼
                json = webclient.DownloadString(address);
            }

 

3、序列化和反序列化,這里我就寫在一起了

public static class iotmonSerial
        {
            //反序列化
            public static T parse<T>(string jsonstring)
            {
                using (var ms = new MemoryStream(Encoding.UTF8.GetBytes(jsonstring)))
                {
                    return (T)new DataContractJsonSerializer(typeof(T)).ReadObject(ms);
                }
            }

            //序列化
            public static string stringify(object jsonObject)
            {
                using (var ms = new MemoryStream())
                {
                    new DataContractJsonSerializer(jsonObject.GetType()).WriteObject(ms, jsonObject);
                    return Encoding.UTF8.GetString(ms.ToArray());
                }
            }
        }

 

4、通過調用前面的方法以及實體類,真正的解析了JSON,當然現在只是下載了數據,之后我會說如何上傳。

var ppp = iotmonSerial.parse<jsontext>(json);
            foreach (var item in ppp.rows)
            {
                myTextBlock.Text += item.id + "\t" + item.weatherType + "\t" + item.weatherName + "\n";
            }

 

5、然后我們來說說怎么上傳數據吧~(太艱辛了)

Uri address = new Uri("http://localhost:8080/iotMon/WeatherInfo/listWeatherInfoPaged.action");
WebClient webClient = new WebClient();
webClient.UploadStringAsync(address, "POST", testString);

看上去很簡單吧,但是這才是最坑人的地方,因為弄完之后,我發現死活傳不上去。我比對了很多次JSP頁面上發送的字符串,都是一模一樣的。

這是我苦惱了很久的問題,最后和老師調試了好久,終於找到了問題所在。

首先得定義發過去字符串的標頭,詳見http://msdn.microsoft.com/zh-cn/library/system.net.webclient(v=vs.95).aspx(最后有提到)

但是坑爹的MSDN也沒有說解決方案,最后還是感謝強大的百度和谷歌!

 

標頭是如下(不同的服務器可能不一樣,需要調整,第一個是保證編碼是UTF-8的,我們的項目UTF-8的):

webClient.Encoding = System.Text.Encoding.UTF8;
webClient.Headers.Add(HttpRequestHeader.Accept, "json");
webClient.Headers.Add(HttpRequestHeader.ContentType,"application/x-www-form-urlencoded; charset=UTF-8");
webClient.Headers.Add(HttpRequestHeader.UserAgent, "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; SV1; .NET CLR 1.1.4322; .NET CLR 2.0.50727)");

然后這么折騰之后我發現還是不行,最后通過瀏覽器看上傳過去的數據,發現了問題所在!

url發送過去的東西,會有一個url編碼的轉換,JSON報文里面最多的“{”和“[”都被轉換成了“%7B”和“%5B”,所以我們需要Microsoft.JScript.GlobalObject.encodeURIComponent來將已經做好的需要上傳的報文轉換格式。(需要說明的是,我們的J2EE后台寫的比較奇怪,所以上傳和下載下來的格式是不一樣的,這一點我一開始沒發現,走了不少彎路。)

 

到這里,就可以實現上傳和下載了!真是不容易那(大変)!

 

下面是一些需要到的庫文件:

System.Runtime.Serialization;    解析JSON報文
System.Runtime.Serialization.Json;
System.ServiceModel;        綁定實體類需要
System.ServiceModel.Web;
System.IO;
System.Xml;
System.Net;             解析JSON報文
System.Net.Http;
System.Net.Http.Formatting;
System.Web.Script.Serialization;
System.Json;

 

 最后一點忘記補充了,上傳上去的時候需要通過URL編碼,這個視具體項目要不要轉碼。

最新問題,當服務器為linux系統時,需要加上webClient.Headers.Add(HttpRequestHeader.AcceptLanguage, "zh-cn,zh;q=0.8,en-us;q=0.5,en;q=0.3");,不然無法上傳。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM