官方提供的介面說明和樣本是基於java的,卻沒有對具體的header作出更詳細的說明,導致很難使用C#語言轉換,幾經測試,總算找到了個不是太完整的解決方案,代碼如下。
/// <summary> ///POST檔案 /// </summary> /// <param name="url"></param> /// <param name="timeout"></param> /// <param name="fileKeyName">比如DingTalk上傳媒體檔案使用的是media,該值用於服務端接收到資料時讀取該keyname之後相關的資料。</param> /// <param name="fileBuffer">檔案資料</param> /// <param name="fileName">檔案名稱</param> /// <returns></returns> public static string Post(string url, string fileKeyName, byte[] fileBuffer, String fileName, int timeout) { var boundary = SecurityHelper.GenerateRadomStr(); WebClient webClient = new WebClient(); webClient.Headers.Add("Content-Type", string.Format("multipart/form-data; boundary={0}", boundary)); string fileFormdataTemplate = "\r\n--" + boundary + "\r\nContent-Disposition:form-data;name=\"{0}\";filename=\"{1}\"" + "\r\nContent-Type:application/octet-stream" + "\r\n\r\n"; string formDataHeader = String.Format(fileFormdataTemplate, "media", fileName); byte[] formDataHeaderBuffer = Encoding.UTF8.GetBytes(formDataHeader); string begin = $"--{boundary}\r\n"; byte[] beginBuffer = Encoding.UTF8.GetBytes(begin); string end = $"\r\n--{boundary}--\r\n"; byte[] endBuffer = Encoding.UTF8.GetBytes(end); ; byte[] dataStream = new byte[formDataHeaderBuffer.Length + beginBuffer.Length + fileBuffer.Length + endBuffer.Length]; formDataHeaderBuffer.CopyTo(dataStream, 0); beginBuffer.CopyTo(dataStream, formDataHeaderBuffer.Length); fileBuffer.CopyTo(dataStream, formDataHeaderBuffer.Length + begin.Length); endBuffer.CopyTo(dataStream, formDataHeaderBuffer.Length + begin.Length + fileBuffer.Length); var returnBuffer = webClient.UploadData(url, "POST", dataStream); Encoding encode = Encoding.UTF8; string resultJson = encode.GetString(returnBuffer); return resultJson; }
調用的代碼
int timeout = 1000 * 60 * 5;String resultJson = RequestHelper.Post(requestUrl, "media", fileBuffer, fileName, timeout);//media是固定的字串
其中fileBuffer為檔案的位元組流,requestUrl按照介面的方式找接而成https://oapi.dingtalk.com/media/upload?access_token=ACCESS_TOKEN&type=TYPE。
目前測出,type=file時是可行的,type=image時不知為何總是提示【系統繁忙】,還請路過的大家們能夠提供解決方案。
在上傳成功後,需要再下載下來,下載時,由於成功和失敗的返回資料不一樣,所以需要先對前面的若干位元組進行了試探處理,之後再依據試探結果繼續處理,代碼如下
附上讀取媒體檔案的方法#region FetchMediaFile Function /// <summary> /// 擷取媒體檔案 /// </summary> /// <param name="mediaId">媒體檔案的id</param> /// <returns></returns> public static DDMediaFetchResult FetchMediaFile(string mediaId) { DDMediaFetchResult result = null; string apiurl = FormatApiUrlWithToken(Urls.media_get); apiurl = $"{apiurl}&{Keys.media_id}={mediaId}"; WebClient webClient = new WebClient(); var data = webClient.DownloadData(apiurl); int testHeaderMaxLength = 100; var testHeaderBuffer = new byte[(data.Length < testHeaderMaxLength ? data.Length : testHeaderMaxLength)]; Array.Copy(data, 0, testHeaderBuffer, 0, testHeaderBuffer.Length); Encoding encoder = Encoding.UTF8; String testHeaderStr = encoder.GetString(testHeaderBuffer); if (testHeaderStr.StartsWith("--")) {//正常返回資料時,第一行資料為分界線,而分界線必然以"--"開始. var tempArr = testHeaderStr.Split(new String[] { Environment.NewLine }, StringSplitOptions.None); string boundary = tempArr[0] + Environment.NewLine; int boundaryByteLength = encoder.GetBytes(boundary).Length; byte[] destData = new byte[data.Length-boundaryByteLength]; Array.Copy(data, boundaryByteLength, destData, 0, destData.Length); result = new DDMediaFetchResult(); result.ErrCode = DDErrCodeEnum.OK; result.ErrMsg = "OK"; result.Data = destData; const string Content_Length = "Content-Length"; if (webClient.ResponseHeaders == null || (!webClient.ResponseHeaders.AllKeys.Contains(Content_Length))) { result.FileLength = -1; } var lengthStr = webClient.ResponseHeaders[Content_Length]; int length = 0; if (int.TryParse(lengthStr, out length)) { result.FileLength = length; } else { result.FileLength = 0; } const string Content_Type = "Content-Type"; if (webClient.ResponseHeaders == null || (!webClient.ResponseHeaders.AllKeys.Contains(Content_Type))) { result.FileType = "unknown"; } else { result.FileType = webClient.ResponseHeaders[Content_Type]; } } else { string resultJson = encoder.GetString(data); result = DDRequestAnalyzer.AnalyzeResult<DDMediaFetchResult>(resultJson);//將resultJson反序化為DDMediaFetchResult } return result; } #endregion/// <summary> /// 媒體檔案擷取結果 /// </summary> public class DDMediaFetchResult { /// <summary> /// 錯誤碼 /// </summary> public int ErrCode{get;set; /// <summary> /// 錯誤訊息 /// </summary> public string ErrMsg { get; set; }} /// <summary> /// HTTP回應標頭 /// </summary> public Dictionary<string, string> Header { get; set; } /// <summary> /// 擷取的資料 /// </summary> public byte[] Data { get; set; } /// <summary> /// 檔案長度 /// </summary> public int FileLength { get; set; } /// <summary> /// 檔案類型 /// </summary> public String FileType { get; set; } }
將收到的資料存成檔案即可,比如將前面上傳得到的mediaid傳入後,下載得到了下面的圖
附產生隨機串的方法
#region GenerateRadomStr /// <summary> /// 產生隨機字串 /// </summary> /// <param name="length">隨機串的長度</param> /// <returns></returns> public static string GenerateRadomStr(int length = 16) { string chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; string str = ""; Random rad = new Random(); for (int i = 0; i < length; i++) { str += chars.Substring(rad.Next(0, chars.Length - 1), 1); } return str; } #endregion
歡迎打描左側二維碼打賞。
轉載請註明出處。