1) 方案一, 使用Web Service 基礎功能沒問題, 只是在連接https (ssh) 網站時, 需要針對https進行開發 (即http 和https 生成兩套接口, 不太容易統一 ). 后來改為使用web頁面交互(實質是.ashx) 結果也遇到了不少問題.
2) 方案二, 使用
HttpWebRequest .
HttpWebRequest
這東西get數據很容易, POST卻很麻煩, 最終代碼如下:

1 public class WebApiClient 2 { 3 public string Url { get; set; } 4 private CookieContainer Cookies = new CookieContainer(); 5 6 7 public static string Get( string url ) 8 { 9 //this code can fix https after .net 4.6 10 if (url.StartsWith("https", StringComparison.CurrentCultureIgnoreCase)) 11 { 12 System.Net.ServicePointManager.ServerCertificateValidationCallback = new RemoteCertificateValidationCallback(CheckValidationResult); 13 } 14 System.Net.HttpWebRequest request = (System.Net.HttpWebRequest)WebRequest.Create(url); 15 request.Method = "GET"; 16 request.ContentType = "application/x-www-form-urlencoded"; 17 18 System.Net.HttpWebResponse response = (System.Net.HttpWebResponse)request.GetResponse(); 19 System.IO.Stream s = response.GetResponseStream(); 20 using (StreamReader reader = new StreamReader(s)) 21 { 22 string strValue = reader.ReadToEnd(); 23 return strValue; 24 } 25 } 26 private static bool CheckValidationResult(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors errors) 27 { 28 return true; 29 } 30 public Result<DataTable> CallWebApi(string action, string json ) 31 { 32 return CallWebApi(action, json, null, null); 33 } 34 public Result<DataTable> CallWebApi(string action, string json, string fileName, byte[] fileData) 35 { 36 string responseContent; 37 var memStream = new MemoryStream(); 38 var webRequest = (HttpWebRequest)WebRequest.Create(Url); 39 var boundary = "---------------" + DateTime.Now.Ticks.ToString("x"); 40 var beginBoundary = Encoding.ASCII.GetBytes("--" + boundary + "\r\n"); 41 //var fileStream = new FileStream(filePath, FileMode.Open, FileAccess.Read); 42 var endBoundary = Encoding.ASCII.GetBytes("--" + boundary + "--\r\n"); 43 webRequest.Method = "POST"; 44 //webRequest.Timeout = timeOut; 45 webRequest.ContentType = "multipart/form-data; boundary=" + boundary; 46 if (!string.IsNullOrEmpty(fileName)) 47 { 48 const string filePartHeader = 49 "Content-Disposition: form-data; name=\"{0}\"; filename=\"{1}\"\r\n" + 50 "Content-Type: application/octet-stream\r\n\r\n"; 51 var header = string.Format(filePartHeader, "file1", fileName); 52 var headerbytes = Encoding.UTF8.GetBytes(header); 53 memStream.Write(beginBoundary, 0, beginBoundary.Length); 54 memStream.Write(headerbytes, 0, headerbytes.Length); 55 memStream.Write(fileData, 0, fileData.Length); 56 } 57 58 59 var stringKeyHeader = "\r\n--" + boundary + 60 "\r\nContent-Disposition: form-data; name=\"{0}\"" + 61 "\r\n\r\n{1}\r\n"; 62 var bytes = Encoding.UTF8.GetBytes(string.Format(stringKeyHeader, "action", action)); 63 memStream.Write(bytes, 0, bytes.Length); 64 bytes = Encoding.UTF8.GetBytes(string.Format(stringKeyHeader, "json", json)); 65 memStream.Write(bytes, 0, bytes.Length); 66 67 memStream.Write(endBoundary, 0, endBoundary.Length); 68 webRequest.ContentLength = memStream.Length; 69 var requestStream = webRequest.GetRequestStream(); 70 memStream.Position = 0; 71 var tempBuffer = new byte[memStream.Length]; 72 memStream.Read(tempBuffer, 0, tempBuffer.Length); 73 memStream.Close(); 74 requestStream.Write(tempBuffer, 0, tempBuffer.Length); 75 requestStream.Close(); 76 var httpWebResponse = (HttpWebResponse)webRequest.GetResponse(); 77 using (var httpStreamReader = new StreamReader(httpWebResponse.GetResponseStream(), 78 Encoding.GetEncoding("utf-8"))) 79 { 80 responseContent = httpStreamReader.ReadToEnd(); 81 } 82 httpWebResponse.Close(); 83 webRequest.Abort(); 84 try 85 { 86 return JsonConvert.DeserializeObject<Result<DataTable>>(responseContent); 87 } 88 catch (Exception ex) 89 { 90 throw new ApplicationException("Parse server result error: " + responseContent, ex); 91 } 92 } 93 94 }
POST數據的麻煩, 封裝一下可以忍了,
但是連接HTTPS的網站時, 有的網站可以, 有的網站會出錯:
System.Net.WebException: The underlying connection was closed: An unexpected error occurred on a send. ---> System.IO.IOException: Unable to read data from the transport connection: An existing connection was forcibly closed by the remote host. ---> System.Net.Sockets.SocketException: An existing connection was forcibly closed by the remote host
at System.Net.Sockets.Socket.Receive(Byte[] buffer, Int32 offset, Int32 size, SocketFlags socketFlags)
at System.Net.Sockets.NetworkStream.Read(Byte[] buffer, Int32 offset, Int32 size)
--- End of inner exception stack trace ---
at System.Net.Sockets.NetworkStream.Read(Byte[] buffer, Int32 offset, Int32 size)
at System.Net.FixedSizeReader.ReadPacket(Byte[] buffer, Int32 offset, Int32 count)
at System.Net.Security.SslState.StartReceiveBlob(Byte[] buffer, AsyncProtocolRequest asyncRequest)
at System.Net.Security.SslState.ForceAuthentication(Boolean receiveFirst, Byte[] buffer, AsyncProtocolRequest asyncRequest)
at System.Net.Security.SslState.ProcessAuthentication(LazyAsyncResult lazyResult)
at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
at System.Net.TlsStream.ProcessAuthentication(LazyAsyncResult result)
at System.Net.TlsStream.Write(Byte[] buffer, Int32 offset, Int32 size)
at System.Net.ConnectStream.WriteHeaders(Boolean async)
--- End of inner exception stack trace ---
at System.Net.HttpWebRequest.GetResponse()
如果是普通的桌面程序 , 在.net 4.6以上版本時, Create
HttpWebRequest
對象前添加
if(url.StartsWith("https",StringComparison.CurrentCultureIgnoreCase))
{
System.Net.ServicePointManager.ServerCertificateValidationCallback=newRemoteCertificateValidationCallback(CheckValidationResult);
}
privatestatic bool CheckValidationResult(object sender, X509Certificate certificate, X509Chain chain,SslPolicyErrors errors)
{
returntrue;
}
有的web服務器要求較新的HTTPS的安裝協議, 這種情況下.net4.0以下的版本不支持, 因此要升級到.net4.6以上, 並且在創建HttpWebRequest對象前加入如下設置代碼:
ServicePointManager.SecurityProtocol=SecurityProtocolType.Tls|SecurityProtocolType.Tls11|SecurityProtocolType.Tls12|SecurityProtocolType.Ssl3;
這樣就可以最大程度的兼容各種安全協議了. 有的時候發現我們的程序挑.net framework的版本, 大都是由這個原因引起的.
解決了HttpWebRequest連接HTTPS的問題之后, 該方案成為了功能最強的方案(重要是能較好的支持文件的上傳)
方案三 使用WebBrowser控件 .
初步試了一下, get https的頁面沒有問題, post 的略有麻煩, 網上查到的方法是截獲post事件進行處理:
WebBrowser 其實是對 ActiveX 控件 SHDocVw 的封裝,而這個SHDocVw的很多底層調用WebBrowser控件並沒有提供實現,我們需要直接操作 SHDoceVw 控件來實現這些高級調用。操作方法如下: 2、在 Form1_Load 中添加如下語句 SHDocVw.WebBrowser wb = (SHDocVw.WebBrowser)webBrowser1.ActiveXInstance; 3、添加如下成員函數 private void WebBrowser_BeforeNavigate2(object pDisp, ref object URL, ref object Flags,
|
互操作的C#類上需要加上這個設置:
[System.Runtime.InteropServices.ComVisibleAttribute(true)]
並且運行此代碼:
webBrowser1.ObjectForScripting=this;
C#里調用JS方法:
webBrowser1.Document.InvokeScript("jsFunction",newstring[]{‘ssss’});
JS里調用C#方法:
window.external.CSharpFunction(‘呵呵’);
這個方法也有些麻煩的地方, 而且不支持文件的上傳.