Multipart Form Post in C#
来源:互联网 发布:sybase数据库 编辑:程序博客网 时间:2024/06/02 04:01
I recently had to access a web API through C Sharp that required a file upload. This is pretty easy if you have an HTML page with a form tag and you want a user to directly upload the file.
<form method="POST" action="http://localhost/" enctype="multipart/form-data">File : <input type="file" name="content" size="38" /><br /><input type="hidden" name="id" value='fileUpload' /> </form>
However, this is not always a reasonable path to take. Sometimes you may be wanting to access a file that is already in a system and you don’t want a new upload. If you are accessing an external API, this is probably always the case. Unfortunately, building this post using C# is not quite as straightforward. I first tried using the WebClient UploadFile method, but it didn’t fit my needs because I wanted to upload form values (id, filename, other API specific parameters) in addition to just a file.
So, I needed to roll my own form post. Here is the Multipart Form RFC and the W3C Specification for multipart/form data. After reading these links and searching some forums, here is what I came up with.
Note: If anyone is interested in this code in Visual Basic, reader Mike Ferreira converted the code into VB.Net in a comment below.
// Implements multipart/form-data POST in C# http://www.ietf.org/rfc/rfc2388.txt// http://www.briangrinstead.com/blog/multipart-form-post-in-cpublic static class FormUpload{ private static readonly Encoding encoding = Encoding.UTF8; public static HttpWebResponse MultipartFormDataPost(string postUrl, string userAgent, Dictionary<string, object> postParameters) { string formDataBoundary = String.Format("----------{0:N}", Guid.NewGuid()); string contentType = "multipart/form-data; boundary=" + formDataBoundary; byte[] formData = GetMultipartFormData(postParameters, formDataBoundary); return PostForm(postUrl, userAgent, contentType, formData); } private static HttpWebResponse PostForm(string postUrl, string userAgent, string contentType, byte[] formData) { HttpWebRequest request = WebRequest.Create(postUrl) as HttpWebRequest; if (request == null) { throw new NullReferenceException("request is not a http request"); } // Set up the request properties. request.Method = "POST"; request.ContentType = contentType; request.UserAgent = userAgent; request.CookieContainer = new CookieContainer(); request.ContentLength = formData.Length; // You could add authentication here as well if needed: // request.PreAuthenticate = true; // request.AuthenticationLevel = System.Net.Security.AuthenticationLevel.MutualAuthRequested; // request.Headers.Add("Authorization", "Basic " + Convert.ToBase64String(System.Text.Encoding.Default.GetBytes("username" + ":" + "password"))); // Send the form data to the request. using (Stream requestStream = request.GetRequestStream()) { requestStream.Write(formData, 0, formData.Length); requestStream.Close(); } return request.GetResponse() as HttpWebResponse; } private static byte[] GetMultipartFormData(Dictionary<string, object> postParameters, string boundary) { Stream formDataStream = new System.IO.MemoryStream(); bool needsCLRF = false; foreach (var param in postParameters) { // Thanks to feedback from commenters, add a CRLF to allow multiple parameters to be added. // Skip it on the first parameter, add it to subsequent parameters. if (needsCLRF) formDataStream.Write(encoding.GetBytes("\r\n"), 0, encoding.GetByteCount("\r\n")); needsCLRF = true; if (param.Value is FileParameter) { FileParameter fileToUpload = (FileParameter)param.Value; // Add just the first part of this param, since we will write the file data directly to the Stream string header = string.Format("--{0}\r\nContent-Disposition: form-data; name=\"{1}\"; filename=\"{2}\"\r\nContent-Type: {3}\r\n\r\n", boundary, param.Key, fileToUpload.FileName ?? param.Key, fileToUpload.ContentType ?? "application/octet-stream"); formDataStream.Write(encoding.GetBytes(header), 0, encoding.GetByteCount(header)); // Write the file data directly to the Stream, rather than serializing it to a string. formDataStream.Write(fileToUpload.File, 0, fileToUpload.File.Length); } else { string postData = string.Format("--{0}\r\nContent-Disposition: form-data; name=\"{1}\"\r\n\r\n{2}", boundary, param.Key, param.Value); formDataStream.Write(encoding.GetBytes(postData), 0, encoding.GetByteCount(postData)); } } // Add the end of the request. Start with a newline string footer = "\r\n--" + boundary + "--\r\n"; formDataStream.Write(encoding.GetBytes(footer), 0, encoding.GetByteCount(footer)); // Dump the Stream into a byte[] formDataStream.Position = 0; byte[] formData = new byte[formDataStream.Length]; formDataStream.Read(formData, 0, formData.Length); formDataStream.Close(); return formData; } public class FileParameter { public byte[] File { get; set; } public string FileName { get; set; } public string ContentType { get; set; } public FileParameter(byte[] file) : this(file, null) { } public FileParameter(byte[] file, string filename) : this(file, filename, null) { } public FileParameter(byte[] file, string filename, string contenttype) { File = file; FileName = filename; ContentType = contenttype; } }}
Here is the code to call the MultipartFormDataPost function with multiple parameters, including a file.
// Read file dataFileStream fs = new FileStream("c:\\people.doc", FileMode.Open, FileAccess.Read);byte[] data = new byte[fs.Length];fs.Read(data, 0, data.Length);fs.Close(); // Generate post objectsDictionary<string, object> postParameters = new Dictionary<string, object>();postParameters.Add("filename", "People.doc");postParameters.Add("fileformat", "doc");postParameters.Add("file", new FormUpload.FileParameter(data, "People.doc", "application/msword")); // Create request and receive responsestring postURL = "http://localhost";string userAgent = "Someone";HttpWebResponse webResponse = FormUpload.MultipartFormDataPost(postURL, userAgent, postParameters); // Process responseStreamReader responseReader = new StreamReader(webResponse.GetResponseStream());string fullResponse = responseReader.ReadToEnd();webResponse.Close();Response.Write(fullResponse);
- Multipart Form Post in C#
- Java, Multipart form POST
- Multipart/form-data POST
- c# 模拟post发送 multipart/form-data,json格式数据
- android向服务器上传multipart/form-data文件(upload using multipart post using httpclient in android)
- C#模拟提交表单 post-带附件的表单[multipart/form-data]
- C#中HttpWebRequest用Post提交Content-Type: multipart/form-data; boundary=
- C#中HttpWebRequest用Post提交Content-Type: multipart/form-data; boundary=
- C#模拟提交表单 post-带附件的表单[multipart/form-data]
- C#中HttpWebRequest用Post提交Content-Type: multipart/form-data;
- java 用 post multipart/form-data
- Multipart/form-data POST文件上传详解
- Multipart/form-data POST文件上传详解
- Multipart/form-data POST文件上传详解
- Multipart/form-data POST文件上传详解
- Multipart/form-data POST文件上传分析
- Multipart/form-data POST文件上传详解
- Multipart/form-data POST文件上传详解
- 利用Terracotta同步tomcat的Web应用的Session
- android进程间通信
- linux服务器(二)之linux服务器配置文件详解
- WebApi系列~在WebApi中实现Cors访问
- gdb调试core dump文件
- Multipart Form Post in C#
- 软考--软件设计师历年真题知识点选择题汇总
- linux 目录结构
- Lvs下使用Docker扩容实验
- WebApi系列~QQ互联的引入(QConnectSDK)
- 对待二手车过户要理性
- 线程池的应用(缓存的处理思想)
- 3、IOS开发之瀑布流实现
- WebApi系列~通过HttpClient来调用Web Api接口