{"id":43,"date":"2010-11-21T21:45:00","date_gmt":"2010-11-21T19:45:00","guid":{"rendered":"http:\/\/dev.bratched.fr\/en\/?p=43"},"modified":"2010-11-21T21:45:00","modified_gmt":"2010-11-21T19:45:00","slug":"uploading-multiple-files-with-c","status":"publish","type":"post","link":"https:\/\/bratched.com\/en\/2010\/11\/21\/uploading-multiple-files-with-c\/","title":{"rendered":"Uploading multiple files with C#"},"content":{"rendered":"<p>Have you ever been in a situation where you needed to upload multiple files to a remote host and pass additional parameters in the request? Unfortunately there\u2019s nothing in the BCL that allows us to achieve this out of the box.<\/p>\n<p>We have the <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/system.net.webclient.uploadfile.aspx\" target=\"_blank\" rel=\"noopener noreferrer\">UploadFile<\/a> method but it is restricted to a single file and doesn\u2019t allow us to pass any additional parameters. So let\u2019s go ahead and write such method. The important part is that this method must comply with <a href=\"http:\/\/www.faqs.org\/rfcs\/rfc1867.html\" target=\"_blank\" rel=\"noopener noreferrer\">RFC 1867<\/a> so that the remote web server can successfully parse the information.<\/p>\n<p>First we define a model representing a single file to be uploaded:<\/p>\n<div id=\"scid:57F11A72-B0E5-49c7-9094-E3A15BD5B5E6:78bcd8da-3282-4afd-91d6-85bdce2c61ae\" class=\"wlWriterSmartContent\" style=\"margin: 0px;padding: 0px;float: none\">\n<pre class=\"lang:default decode:true\">public class UploadFile\n    {\n        public UploadFile()\n        {\n            ContentType = \"application\/octet-stream\";\n        }\n        public string Name { get; set; }\n        public string Filename { get; set; }\n        public string ContentType { get; set; }\n        public Stream Stream { get; set; }\n    }<\/pre>\n<\/div>\n<p><!--more--><\/p>\n<p>And here\u2019s a sample UploadFiles method implementation:<\/p>\n<div id=\"scid:57F11A72-B0E5-49c7-9094-E3A15BD5B5E6:658ffd88-9f06-42c7-a4b4-fd5f34134122\" class=\"wlWriterSmartContent\" style=\"margin: 0px;padding: 0px;float: none\">\n<pre class=\"lang:default decode:true\">public byte[] UploadFiles(string address, IEnumerable&lt;UploadFile&gt; files, NameValueCollection values)\n    {\n        var request = WebRequest.Create(address);\n        request.Method = \"POST\";\n        var boundary = \"---------------------------\" + DateTime.Now.Ticks.ToString(\"x\", NumberFormatInfo.InvariantInfo);\n        request.ContentType = \"multipart\/form-data; boundary=\" + boundary;\n        boundary = \"--\" + boundary;\n\n        using (var requestStream = request.GetRequestStream())\n        {\n            \/\/ Write the values\n            foreach (string name in values.Keys)\n            {\n                var buffer = Encoding.ASCII.GetBytes(boundary + Environment.NewLine);\n                requestStream.Write(buffer, 0, buffer.Length);\n                buffer = Encoding.ASCII.GetBytes(string.Format(\"Content-Disposition: form-data; name=\\\"{0}\\\"{1}{1}\", name, Environment.NewLine));\n                requestStream.Write(buffer, 0, buffer.Length);\n                buffer = Encoding.UTF8.GetBytes(values[name] + Environment.NewLine);\n                requestStream.Write(buffer, 0, buffer.Length);\n            }\n\n            \/\/ Write the files\n            foreach (var file in files)\n            {\n                var buffer = Encoding.ASCII.GetBytes(boundary + Environment.NewLine);\n                requestStream.Write(buffer, 0, buffer.Length);\n                buffer = Encoding.UTF8.GetBytes(string.Format(\"Content-Disposition: form-data; name=\\\"{0}\\\"; filename=\\\"{1}\\\"{2}\", file.Name, file.Filename, Environment.NewLine));\n                requestStream.Write(buffer, 0, buffer.Length);\n                buffer = Encoding.ASCII.GetBytes(string.Format(\"Content-Type: {0}{1}{1}\", file.ContentType, Environment.NewLine));\n                requestStream.Write(buffer, 0, buffer.Length);\n                file.Stream.CopyTo(requestStream);\n                buffer = Encoding.ASCII.GetBytes(Environment.NewLine);\n                requestStream.Write(buffer, 0, buffer.Length);\n            }\n\n            var boundaryBuffer = Encoding.ASCII.GetBytes(boundary + \"--\");\n            requestStream.Write(boundaryBuffer, 0, boundaryBuffer.Length);\n        }\n\n        using (var response = request.GetResponse())\n        using (var responseStream = response.GetResponseStream())\n        using (var stream = new MemoryStream())\n        {\n            responseStream.CopyTo(stream);\n            return stream.ToArray();\n        }\n    }<\/pre>\n<\/div>\n<p>And here\u2019s a sample usage:<\/p>\n<div id=\"scid:57F11A72-B0E5-49c7-9094-E3A15BD5B5E6:43856010-8b13-47e0-af6d-6bf7fc8fe687\" class=\"wlWriterSmartContent\" style=\"margin: 0px;padding: 0px;float: none\">\n<pre class=\"lang:default decode:true\">using (var stream1 = File.Open(\"test.txt\", FileMode.Open))\n    using (var stream2 = File.Open(\"test.xml\", FileMode.Open))\n    using (var stream3 = File.Open(\"test.pdf\", FileMode.Open))\n    {\n        var files = new[] \n        {\n            new UploadFile\n            {\n                Name = \"file\",\n                Filename = \"test.txt\",\n                ContentType = \"text\/plain\",\n                Stream = stream1\n            },\n            new UploadFile\n            {\n                Name = \"file\",\n                Filename = \"test.xml\",\n                ContentType = \"text\/xml\",\n                Stream = stream2\n            },\n            new UploadFile\n            {\n                Name = \"file\",\n                Filename = \"test.pdf\",\n                ContentType = \"application\/pdf\",\n                Stream = stream3\n            }\n        };\n\n        var values = new NameValueCollection\n        {\n            { \"key1\", \"value1\" },\n            { \"key2\", \"value2\" },\n            { \"key3\", \"value3\" },\n        };\n\n        byte[] result = UploadFiles(\"http:\/\/localhost:1234\/upload\", files, values);\n    }<\/pre>\n<\/div>\n<p>In this example we are uploading 3 values and 3 files to the remote host.<\/p>\n<p>Next time I will show how to improve this code by adding an asynchronous version using the TPL library in .NET 4.0.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Have you ever been in a situation where you needed to upload multiple files to a remote host and pass additional parameters in the request? Unfortunately there\u2019s nothing in the BCL that allows us to achieve this out of the box. We have the UploadFile method but it is restricted to a single file and [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[263,265],"tags":[275,302,304,305,322],"aioseo_notices":[],"_links":{"self":[{"href":"https:\/\/bratched.com\/en\/wp-json\/wp\/v2\/posts\/43"}],"collection":[{"href":"https:\/\/bratched.com\/en\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/bratched.com\/en\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/bratched.com\/en\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/bratched.com\/en\/wp-json\/wp\/v2\/comments?post=43"}],"version-history":[{"count":0,"href":"https:\/\/bratched.com\/en\/wp-json\/wp\/v2\/posts\/43\/revisions"}],"wp:attachment":[{"href":"https:\/\/bratched.com\/en\/wp-json\/wp\/v2\/media?parent=43"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/bratched.com\/en\/wp-json\/wp\/v2\/categories?post=43"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/bratched.com\/en\/wp-json\/wp\/v2\/tags?post=43"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}