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 }
View Code
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 控件来实现这些高级调用。操作方法如下: 1、在 windows/system32 目录下找到 shdocvw.dll 这个动态库,将其添加到引用中 2、在 Form1_Load 中添加如下语句
SHDocVw.WebBrowser wb = (SHDocVw.WebBrowser)webBrowser1.ActiveXInstance; wb.BeforeNavigate2 += new DWebBrowserEvents2_BeforeNavigate2EventHandler(WebBrowser_BeforeNavigate2);
3、添加如下成员函数
private void WebBrowser_BeforeNavigate2(object pDisp, ref object URL, ref object Flags, ref object TargetFrameName, ref object PostData, ref object Headers, ref bool Cancel) { string postDataText = System.Text.Encoding.ASCII.GetString(PostData as byte[]); }
完成上述3步后,你post 数据时, 就会响应 BeforeNavigate2 事件,postDataText 中就是你post的数据。你也可以修改PostData,对这些数据进行转换或加密。
|
感觉会比较麻烦, 其实还有一种方法,就是利用WebBrowser的DocumentText属性注入脚本(执行脚本), 然后利用Ajax的方式和web服务器进行交互. 之后利用JS和C#互操作来完成相应的功能.
互操作的C#类上需要加上这个设置:
[System.Runtime.InteropServices.ComVisibleAttribute(true)]
并且运行此代码:
webBrowser1.ObjectForScripting=this;
C#里调用JS方法:
webBrowser1.Document.InvokeScript("jsFunction",newstring[]{‘ssss’});
JS里调用C#方法:
window.external.CSharpFunction(‘呵呵’);
这个方法也有些麻烦的地方, 而且不支持文件的上传.
|