本文主要是介绍C# HttpWebRequest 上传文件 (调用ArcGIS Rest API上传SOE文件),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
缘起
想做一个SOE自动上传的小工具,查了查相关的ArcGIS Rest API,使用C#中的HttpWebRequet实现,k看GitHub上别人用Python实现的很简单,自己用C#搞了一天了没搞明白,记录一下采坑的过程。
相关资料
- ArcGIS Rest API Upload SOE:传送门
- C# Upload File:参考链接1、参考链接2、
- HttpClient实现方法:参考链接
PostMan测试
使用PostMan测试Form-data,参考链接
代码实现
-
HttpWebRequest
private bool UploadSoe(string userName, string password, string soeFilePath, string ip = "localhost", string port = "6080") {bool bIsSuccess = false;//构造请求参数string token = GetToken(userName, password, ip, port);string boundary = CreateFormDataBoundary();byte[] postDataBytes = null;using (var postStream = new MemoryStream()){//写入表单参数string formDataTemplate = "--{0}\r\nContent-Disposition: form-data; name=\"{1}\"\r\n\r\n{2}\r\n";string fromData1 = string.Format(formDataTemplate, boundary, "f", "json");var dataFormdataBytes1 = Encoding.UTF8.GetBytes(fromData1);string formData2 = string.Format(formDataTemplate, boundary, "token", token);var dataFormdataBytes2 = Encoding.UTF8.GetBytes(formData2);//写入文件头部信息string fileFormdataTemplate = "--{0}\r\nContent-Disposition: form-data; name=\"{1}\"; filename=\"{2}\"\r\nContent-Type: {3}\r\n\r\n";string soeFileName = System.IO.Path.GetFileName(soeFilePath);string fileHeader = string.Format(fileFormdataTemplate, boundary, "itemFile", soeFileName, "application/octet-stream");byte[] headerbytes = System.Text.Encoding.UTF8.GetBytes(fileHeader);//写入文件流byte[] fileBytes = null;using (FileStream fs = new FileStream(soeFilePath, FileMode.Open)){fileBytes = new byte[fs.Length];fs.Read(fileBytes, 0, fileBytes.Length);fs.Close();}//写入结尾string sEndBoundary = "\r\n--" + boundary + "--\r\n";var endBoundaryBytes = Encoding.UTF8.GetBytes(sEndBoundary);postStream.Write(dataFormdataBytes1, 0, dataFormdataBytes1.Length);postStream.Write(dataFormdataBytes2, 0, dataFormdataBytes2.Length);postStream.Write(headerbytes, 0, headerbytes.Length);postStream.Write(fileBytes, 0, fileBytes.Length);postStream.Write(endBoundaryBytes, 0, endBoundaryBytes.Length);postStream.Position = 0;postDataBytes = new byte[postStream.Length];postStream.Read(postDataBytes, 0, postDataBytes.Length);postStream.Close(); }//创建Httphelper对象HttpHelper http = new HttpHelper();//创建Httphelper参数对象HttpItem item = new HttpItem(){URL = string.Format("http://{0}:{1}/arcgis/admin/uploads/upload", ip, port),Method = "POST",ContentType = string.Format("multipart/form-data; boundary={0}", boundary),PostDataType = Sys.PostDataType.Byte,PostdataByte = postDataBytes};//请求的返回值对象HttpResult result = http.GetHtml(item);if (result.StatusCode == System.Net.HttpStatusCode.OK){string html = result.Html;var jsonObj = JsonHelper.GetDynamicObjFromString(html);if (jsonObj.status.ToString() == "success"){bIsSuccess = true;}}return bIsSuccess; }private static string CreateFormDataBoundary() {return "----" + DateTime.Now.Ticks.ToString("x"); }private string GetToken(string userName, string password, string ip = "localhost", string port = "6080") {//创建Httphelper对象HttpHelper http = new HttpHelper();//创建Httphelper参数对象HttpItem item = new HttpItem(){URL = string.Format("http://{0}:{1}/arcgis/admin/generateToken", ip, port),//URL 必需项 Method = "post",//URL 可选项 默认为Get ContentType = "application/x-www-form-urlencoded",//返回类型 可选项有默认值Postdata = string.Format("username={0}&password={1}&client=requestip&expiration=90&f=json", userName, password),//Post要发送的数据};//请求的返回值对象HttpResult result = http.GetHtml(item);//从苏飞论坛或者Github获取,也可以自己用HttpWebRequest//获取请请求的Htmlstring html = result.Html;//获取请求的Cookievar jsonObj = JsonHelper.GetDynamicObjFromString(html);var token = jsonObj.token;return token.ToString(); }
-
HttpClient
private async void UploadSoe1(string userName, string password, string soeFilePath, string ip = "localhost", string port = "6080") {string token = GetToken(userName, password, ip, port);string soeFileName = Path.GetFileName(soeFilePath);using (FileStream stream = new FileStream(soeFilePath, FileMode.Open))using (HttpClient client = new HttpClient()){MultipartFormDataContent content = new MultipartFormDataContent();content.Add(new StringContent("pjson"), "f");content.Add(new StringContent(token), "token");content.Add(new StreamContent(stream){Headers ={ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("application/octet-stream")}}, "itemFile", soeFileName);string url = string.Format("http://{0}:{1}/arcgis/admin/uploads/upload", ip, port);var response = await client.PostAsync(url, content);string resultContent = await response.Content.ReadAsStringAsync();}}
采坑小记
使用HttpWebRequest时需要自行构造body,这块相比HttpClient麻烦一点,这块要注意构造请求体是字符串的顺序,依次往requestStream中写入
-
构造boundary信息
private static string CreateFormDataBoundary() {return "----" + DateTime.Now.Ticks.ToString("x"); }
-
构造请求参数的相关信息
string formDataTemplate = "--{0}\r\nContent-Disposition: form-data; name=\"{1}\"\r\n\r\n{2}\r\n"; string fromData1 = string.Format(formDataTemplate, boundary, "f", "json"); var dataFormdataBytes1 = Encoding.UTF8.GetBytes(fromData1);
-
构造上传文件的相关信息
string fileFormdataTemplate = "--{0}\r\nContent-Disposition: form-data; name=\"{1}\"; filename=\"{2}\"\r\nContent-Type: {3}\r\n\r\n"; string soeFileName = System.IO.Path.GetFileName(soeFilePath); string fileHeader = string.Format(fileFormdataTemplate, boundary, "itemFile", soeFileName, "application/octet-stream"); byte[] headerbytes = System.Text.Encoding.UTF8.GetBytes(fileHeader);
-
添加换行
byte[] bytes = Encoding.UTF8.GetBytes("\r\n");
-
添加结尾信息
string sEndBoundary = "--" + boundary + "--\r\n"; var endBoundaryBytes = Encoding.UTF8.GetBytes(sEndBoundary);
最后依次写入:
Stream requestStream = request.GetRequestStream();requestStream.Write(dataFormdataBytes1, 0, dataFormdataBytes1.Length);requestStream.Write(dataFormdataBytes2, 0, dataFormdataBytes2.Length);//这块我有两个参数,没有封装函数,直接重复代码写了两遍requestStream.Write(headerbytes, 0, headerbytes.Length);requestStream.Write(fileBytes, 0, fileBytes.Length);byte[] bytes = Encoding.UTF8.GetBytes("\r\n");requestStream.Write(bytes, 0, bytes.Length);requestStream.Write(endBoundaryBytes, 0, endBoundaryBytes.Length);
总结
如果对.Net Framework的版本没有要求的话(可以使用4.5及以上版本)建议使用HttpClient实现,毕竟HTTPWebRequest是很久之前的类,调用起来构造比较麻烦。
这篇关于C# HttpWebRequest 上传文件 (调用ArcGIS Rest API上传SOE文件)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!