If you need to upload a file to an API using a multipart form then you’re generally better off using HttpClient rather than WebClient, unfortunatly however HttpClient isn’t available in SSDT so if you need to upload a file from a script task then you’re stuck with WebClient.
The below code is based on a StackOverflow answer here.
First off I added the below class to my script task.
MultiPartFormUpload.cspublic class MultiPartFormUpload { public class MimePart { NameValueCollection _headers = new NameValueCollection(); byte[] _header; public NameValueCollection Headers { get { return _headers; } } public byte[] Header { get { return _header; } } public long GenerateHeaderFooterData(string boundary) { StringBuilder stringBuilder = new StringBuilder(); stringBuilder.Append("--"); stringBuilder.Append(boundary); stringBuilder.AppendLine(); foreach (string key in _headers.AllKeys) { stringBuilder.Append(key); stringBuilder.Append(": "); stringBuilder.AppendLine(_headers[key]); } stringBuilder.AppendLine(); _header = Encoding.UTF8.GetBytes(stringBuilder.ToString()); return _header.Length + Data.Length + 2; } public Stream Data { get; set; } } public class UploadResponse { public UploadResponse(HttpStatusCode httpStatusCode, string responseBody) { HttpStatusCode = httpStatusCode; ResponseBody = responseBody; } public HttpStatusCode HttpStatusCode { get; set; } public string ResponseBody { get; set; } } public UploadResponse Upload(string url, NameValueCollection requestHeaders, NameValueCollection requestParameters, List<FileInfo> files) { using (WebClient client = new WebClient()) { List<MimePart> mimeParts = new List<MimePart>(); try { foreach (string key in requestHeaders.AllKeys) { client.Headers.Add(key, requestHeaders[key]); } foreach (string key in requestParameters.AllKeys) { MimePart part = new MimePart(); part.Headers["Content-Disposition"] = "form-data; name=\"" + key + "\""; part.Data = new MemoryStream(Encoding.UTF8.GetBytes(requestParameters[key])); mimeParts.Add(part); } foreach (FileInfo file in files) { MimePart part = new MimePart(); string name = file.Extension.Substring(1); string fileName = file.Name; part.Headers["Content-Disposition"] = "form-data; name=\"" + name + "\"; filename=\"" + fileName + "\""; part.Headers["Content-Type"] = "application/octet-stream"; part.Data = new MemoryStream(File.ReadAllBytes(file.FullName)); mimeParts.Add(part); } string boundary = "----------" + DateTime.Now.Ticks.ToString("x"); client.Headers.Add(HttpRequestHeader.ContentType, "multipart/form-data; boundary=" + boundary); long contentLength = 0; byte[] _footer = Encoding.UTF8.GetBytes("--" + boundary + "--\r\n"); foreach (MimePart mimePart in mimeParts) { contentLength += mimePart.GenerateHeaderFooterData(boundary); } byte[] buffer = new byte[8192]; byte[] afterFile = Encoding.UTF8.GetBytes("\r\n"); int read; using (MemoryStream memoryStream = new MemoryStream()) { foreach (MimePart mimePart in mimeParts) { memoryStream.Write(mimePart.Header, 0, mimePart.Header.Length); while ((read = mimePart.Data.Read(buffer, 0, buffer.Length)) > 0) memoryStream.Write(buffer, 0, read); mimePart.Data.Dispose(); memoryStream.Write(afterFile, 0, afterFile.Length); } memoryStream.Write(_footer, 0, _footer.Length); byte[] responseBytes = client.UploadData(url, memoryStream.ToArray()); string responseString = Encoding.UTF8.GetString(responseBytes); return new UploadResponse(HttpStatusCode.OK, responseString); } } catch (Exception ex) { foreach (MimePart part in mimeParts) if (part.Data != null) part.Data.Dispose(); if (ex.GetType().Name == "WebException") { WebException webException = (WebException)ex; HttpWebResponse response = (HttpWebResponse)webException.Response; string responseString; using (StreamReader reader = new StreamReader(response.GetResponseStream(), Encoding.UTF8)) { responseString = reader.ReadToEnd(); } return new UploadResponse(response.StatusCode, responseString); } else { throw; } } } } }
This class can then be used in your standard ScriptMain class like so.
ScriptMain.cspublic void Main() { string filePath = Dts.Variables["User::output_file"].Value.ToString(); string apiId = Dts.Variables["User::apiId"].Value.ToString(); string apiToken = Dts.Variables["User::apiToken"].Value.ToString(); MultiPartFormUpload multiPartFormUpload = new MultiPartFormUpload(); NameValueCollection headers = new NameValueCollection(); headers.Add("auth_id", apiId); headers.Add("auth_token", apiToken); List<FileInfo> files = new List<FileInfo>() { new FileInfo(filePath) }; try { MultiPartFormUpload.UploadResponse response = multiPartFormUpload.Upload("https://api.multipart-form-upload", headers, new NameValueCollection() { }, files); Dts.TaskResult = (int)ScriptResults.Success; } catch (Exception ex) { Dts.TaskResult = (int)ScriptResults.Failure; } }
0 Comments