前言
代理層的主要工作是調用Web Service,將在FCL層序列化好的Json數據字符串Post到Web Service,然后獲得Reponse,再從響應流中讀取到調用結果Json字符串,在Dispatcher反序列化成數據對象,在UI層呈現出來。
HttpHelper類(參考自:http://blog.csdn.net/eriloan/article/details/7000790)
剛開始是直接在Proxy類中直接寫的Post方法,后來看到這篇帖子,將Http相關的部分封裝成了工具類HttpHelper。原帖中還包含了使用TCPSocket發送請求調用WebService的內容。
1 namespace ProjectmsMGT_Proxy 2 { 3 public class HttpHelper 4 { 5 /// <summary> 6 /// Http請求URL 7 /// </summary> 8 public string Url { set; get; } 9 10 /// <summary> 11 /// 請求參數Key(約定服務方法參數名同名) 12 /// 在使用Post方式向服務器端發送請求的時候,請求數據中包含了參數部分,參數部分我們需要告訴WebService接口方法,實參要傳給的接口方法行參名,由RequestParaKey指定 13 /// 當然當接口方法有多個形參時,就不建議單獨設計這樣一個屬性,直接在sendMsg中添加,此處只是為了突出RequestParaKey的重要性 14 /// </summary> 15 public string RequestParaKey { set; get; } 16 17 /// <summary> 18 /// 證書文件路徑 19 /// </summary> 20 public string CertificateFilePath { set; get; } 21 22 /// <summary> 23 /// 證書文件口令 24 /// </summary> 25 public string CertificateFilePwd { set; get; } 26 27 /// <summary> 28 /// 構造函數,不使用證書 29 /// </summary> 30 /// <param name="url"></param> 31 /// <param name="requestParaKey"></param> 32 public HttpHelper(string url, string requestParaKey) 33 { 34 this.Url = url; 35 this.RequestParaKey = requestParaKey; 36 } 37 38 /// <summary> 39 /// 構造函數,使用證書 40 /// </summary> 41 /// <param name="url"></param> 42 /// <param name="requestParaKey"></param> 43 /// <param name="certFilePath"></param> 44 /// <param name="certFilePwd"></param> 45 public HttpHelper(string url, string requestParaKey, string certFilePath, string certFilePwd) 46 { 47 this.Url = url; 48 this.RequestParaKey = requestParaKey; 49 this.CertificateFilePath = certFilePath; 50 this.CertificateFilePwd = certFilePwd; 51 } 52 53 /// <summary> 54 /// 使用Get方式,發送Http請求 55 /// </summary> 56 /// <param name="methodName">所請求的接口方法名</param> 57 /// <param name="isLoadCert">是否加載證書</param> 58 /// <returns>響應字符串</returns> 59 public string CreateHttpGet(string methodName, bool isLoadCert) 60 { 61 HttpWebRequest request = CreateHttpRequest(methodName, @"GET", isLoadCert); 62 63 return CreateHttpResponse(request); 64 } 65 66 /// <summary> 67 /// 使用Post方式,發送Http請求 68 /// </summary> 69 /// <param name="methodName">所請求的接口方法名</param> 70 /// <param name="sendMsg">請求參數(不包含RequestParaKey部分)</param> 71 /// <param name="isLoadCert">是否加載證書</param> 72 /// <returns>響應字符串</returns> 73 public string CreateHttpPost(string methodName, string sendMsg, bool isLoadCert) 74 { 75 //創建Http請求 76 HttpWebRequest request = CreateHttpRequest(methodName, @"POST", isLoadCert); 77 if (null != sendMsg && !"".Equals(sendMsg)) 78 { 79 //添加請求參數 80 AddHttpRequestParams(request, sendMsg); 81 } 82 83 //獲得響應 84 return CreateHttpResponse(request); 85 } 86 87 /// <summary> 88 /// 將請求參數寫入請求流 89 /// </summary> 90 /// <param name="request"></param> 91 /// <param name="sendMsg"></param> 92 private void AddHttpRequestParams(HttpWebRequest request, string sendMsg) 93 { 94 //將請求參數進行URL編碼 95 string paraUrlCoded = System.Web.HttpUtility.UrlEncode(RequestParaKey) + "=" + 96 System.Web.HttpUtility.UrlEncode(sendMsg); 97 98 byte[] data = Encoding.UTF8.GetBytes(paraUrlCoded); 99 request.ContentLength = data.Length; 100 Stream requestStream = null; 101 using (requestStream = request.GetRequestStream()) 102 { 103 //將請求參數寫入流 104 requestStream.Write(data, 0, data.Length); 105 } 106 107 requestStream.Close(); 108 } 109 110 /// <summary> 111 /// 創建HttpRequest 112 /// </summary> 113 /// <param name="methodName"></param> 114 /// <param name="requestType">POST或者GET</param> 115 /// <param name="isLoadCert"></param> 116 /// <returns>HttpWebRequest對象</returns> 117 private HttpWebRequest CreateHttpRequest(string methodName, string requestType, bool isLoadCert) 118 { 119 HttpWebRequest request = null; 120 try 121 { 122 string requestUriString = Url + "/" + methodName; 123 request = (HttpWebRequest)WebRequest.Create(requestUriString); 124 if (isLoadCert) 125 { 126 //創建證書 127 X509Certificate2 cert = CreateX509Certificate2(); 128 //添加證書認證 129 request.ClientCertificates.Add(cert); 130 } 131 request.KeepAlive = true; 132 request.ContentType = "application/x-www-form-urlencoded"; 133 request.Method = requestType; 134 } 135 catch (Exception) 136 { 137 //Console.WriteLine("創建HttpRequest失敗。原因:" + e.Message); 138 request = null; 139 } 140 141 return request; 142 } 143 144 /// <summary> 145 /// 創建請求響應 146 /// </summary> 147 /// <param name="request"></param> 148 /// <returns>響應字符串</returns> 149 private string CreateHttpResponse(HttpWebRequest request) 150 { 151 String str; 152 HttpWebResponse response = null; 153 Stream responseStream = null; 154 XmlTextReader responseReader = null; 155 try 156 { 157 using (response = (HttpWebResponse)request.GetResponse()) 158 { 159 //獲得響應流 160 responseStream = response.GetResponseStream(); 161 responseReader = new XmlTextReader(responseStream); 162 responseReader.MoveToContent(); 163 str = responseReader.ReadInnerXml(); 164 } 165 } 166 catch (Exception e) 167 { 168 str = "[{\"Rescode\":\"0\",\"Resmsg\":\"通信失敗。原因:" + e.Message + "\"}]"; 169 } 170 finally 171 { 172 if (null != response) 173 { 174 responseReader.Close(); 175 responseStream.Close(); 176 response.Close(); 177 } 178 } 179 180 return str; 181 } 182 183 /// <summary> 184 /// 創建證書 185 /// </summary> 186 /// <returns>X509Certificate2對象</returns> 187 private X509Certificate2 CreateX509Certificate2() 188 { 189 X509Certificate2 cert = null; 190 try 191 { 192 cert = new X509Certificate2(CertificateFilePath, CertificateFilePwd); 193 ServicePointManager.ServerCertificateValidationCallback = 194 new RemoteCertificateValidationCallback(ServerCertificateValidationCallback); 195 } 196 catch (Exception) 197 { 198 //Console.WriteLine("創建X509Certificate2失敗。原因:" + e.Message); 199 cert = null; 200 } 201 return cert; 202 } 203 204 /// <summary> 205 /// Verifies the remote Secure Sockets Layer (SSL) certificate used for authentication 206 /// </summary> 207 /// <param name="obj">An object that contains state information for this validation</param> 208 /// <param name="cer">The certificate used to authenticate the remote party</param> 209 /// <param name="chain">The chain of certificate authorities associated with the remote certificate</param> 210 /// <param name="error">One or more errors associated with the remote certificate</param> 211 /// <returns>A Boolean value that determines whether the specified certificate is accepted for authentication</returns> 212 private bool ServerCertificateValidationCallback(object obj, X509Certificate cer, X509Chain chain, System.Net.Security.SslPolicyErrors error) 213 { 214 return true; 215 } 216 } 217 }
HttpHelper中把SSL證書的部分也包含進來,但是證書認證機制部分ServerCertificateValidationCallback還沒設計,各位大神可以自行發揮。
代理類Proxy
有了HttpHelper之后,代理類的代碼就比較明了了。
1 namespace ProjectmsMGT_Proxy 2 { 3 public class ProjectmsProxy 4 { 5 private readonly string Url = "http://59.68.29.106:8087/IFT_Project.asmx";//通過配置文件獲取Web Service地址 6 private readonly string requestParaKey = "paramaters";//服務端所有接口函數統一的參數名 7 private HttpHelper httpHelper; 8 9 public ProjectmsProxy() 10 { 11 //初始化 12 Initialize(); 13 } 14 15 private void Initialize() 16 { 17 httpHelper = new HttpHelper(this.Url, this.requestParaKey); 18 } 19 20 /// <summary> 21 /// 使用Get方式調用WebService,不帶參數 22 /// </summary> 23 /// <param name="methodName"></param> 24 /// <param name="parasJsonStr"></param> 25 /// <param name="requestType"></param> 26 /// <returns></returns> 27 public string Excute(string methodName, string parasJsonStr, string requestType) 28 { 29 return httpHelper.CreateHttpGet(methodName, false); 30 } 31 32 /// <summary> 33 /// 默認使用Post方式調用WebService,帶參數 34 /// </summary> 35 /// <param name="methodName"></param> 36 /// <param name="parasJsonStr"></param> 37 /// <returns></returns> 38 public string Excute(string methodName, string parasJsonStr) 39 { 40 return httpHelper.CreateHttpPost(methodName, parasJsonStr, false); 41 } 42 43 /// <summary> 44 /// 默認使用Post方式調用WebService,不帶參數 45 /// </summary> 46 /// <param name="methodName"></param> 47 /// <returns></returns> 48 public string Excute(string methodName) 49 { 50 return httpHelper.CreateHttpPost(methodName, null, false); 51 } 52 } 53 }
Proxy中重載了Excute方法,三個參數的表示使用Get方式調用WebService(因為不建議在Get方式下傳參給Web Service),兩個參數和一個參數的Excute默認是使用Post方式帶參數和不帶參數的情況。
總結
將方法名作為參數Post到Web Service可以減少很多重復代碼,不需要對服務端的每個接口函數做寫一個代理函數,這是使用Post方式比使用添加Web服務引用方式更加靈活。