使用.NET发布多个文件和表单值(控制台应用程序)

我想在一个 HTTP请求中将多个文件和表单变量POST到CGI脚本。 我相信这需要一个带有multipart/form-data编码的HTTPpost。 这是一个发送所需信息的示例HTML表单; 我需要通过应用程序发送相同的信息:

 

请注意,该应用程序是一个C#.NET GUI(或控制台)应用程序,而不是ASP.Net应用程序。

我去年根据我发现的一些代码做了这个。 它完全支持您想要的文件和值。

这是一个名为HttpForm的类:

 public class HttpForm { private Dictionary _files = new Dictionary(); private Dictionary _values = new Dictionary(); public HttpForm(string url) { this.Url = url; this.Method = "POST"; } public string Method { get; set; } public string Url { get; set; } //return self so that we can chain public HttpForm AttachFile(string field, string fileName) { _files[field] = fileName; return this; } public HttpForm ResetForm(){ _files.Clear(); _values.Clear(); return this; } //return self so that we can chain public HttpForm SetValue(string field, string value) { _values[field] = value; return this; } public HttpWebResponse Submit() { return this.UploadFiles(_files, _values); } private HttpWebResponse UploadFiles(Dictionary files, Dictionary otherValues) { var req = (HttpWebRequest)WebRequest.Create(this.Url); req.Timeout = 10000 * 1000; req.Accept = "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"; req.AllowAutoRedirect = false; var mimeParts = new List(); try { if (otherValues != null) { foreach (var fieldName in otherValues.Keys) { var part = new MimePart(); part.Headers["Content-Disposition"] = "form-data; name=\"" + fieldName + "\""; part.Data = new MemoryStream(Encoding.UTF8.GetBytes(otherValues[fieldName])); mimeParts.Add(part); } } if (files != null) { foreach (var fieldName in files.Keys) { var part = new MimePart(); part.Headers["Content-Disposition"] = "form-data; name=\"" + fieldName + "\"; filename=\"" + files[fieldName] + "\""; part.Headers["Content-Type"] = "application/octet-stream"; part.Data = File.OpenRead(files[fieldName]); mimeParts.Add(part); } } string boundary = "----------" + DateTime.Now.Ticks.ToString("x"); req.ContentType = "multipart/form-data; boundary=" + boundary; req.Method = this.Method; long contentLength = 0; byte[] _footer = Encoding.UTF8.GetBytes("--" + boundary + "--\r\n"); foreach (MimePart part in mimeParts) { contentLength += part.GenerateHeaderFooterData(boundary); } req.ContentLength = contentLength + _footer.Length; byte[] buffer = new byte[8192]; byte[] afterFile = Encoding.UTF8.GetBytes("\r\n"); int read; using (Stream s = req.GetRequestStream()) { foreach (MimePart part in mimeParts) { s.Write(part.Header, 0, part.Header.Length); while ((read = part.Data.Read(buffer, 0, buffer.Length)) > 0) s.Write(buffer, 0, read); part.Data.Dispose(); s.Write(afterFile, 0, afterFile.Length); } s.Write(_footer, 0, _footer.Length); } var res = (HttpWebResponse)req.GetResponse(); return res; } catch (Exception ex) { Console.WriteLine(ex.Message); foreach (MimePart part in mimeParts) if (part.Data != null) part.Data.Dispose(); return (HttpWebResponse)req.GetResponse(); } } private class MimePart { private NameValueCollection _headers = new NameValueCollection(); public NameValueCollection Headers { get { return _headers; } } public byte[] Header { get; protected set; } public long GenerateHeaderFooterData(string boundary) { StringBuilder sb = new StringBuilder(); sb.Append("--"); sb.Append(boundary); sb.AppendLine(); foreach (string key in _headers.AllKeys) { sb.Append(key); sb.Append(": "); sb.AppendLine(_headers[key]); } sb.AppendLine(); Header = Encoding.UTF8.GetBytes(sb.ToString()); return Header.Length + Data.Length + 2; } public Stream Data { get; set; } } } 

你可以像这样使用它:

 var file1 = @"C:\file"; var file2 = @"C:\file2"; var yourUrl = "http://yourdomain.com/process.php"; var httpForm = new HttpForm(yourUrl); httpForm.AttachFile("file1", file1).AttachFile("file2", file2); httpForm.setValue("foo", "some foo").setValue("blah", "rarrr!"); httpForm.Submit(); 

请让我知道这对你有没有用。

我去年必须在一个项目上做同样的事情。 经过一番环顾,我发现了这个:

使用HTTPWebrequest上传文件(multipart / form-data)

那里的第二个答案应该是你正在寻找的东西。 当我试图这样做时,我遇到了一些麻烦,让这个确切的方法工作。 问题是C#.NET在POST中不支持多个键/值对。 因此,您必须自己构建HTTP请求内容标头。 我相信上面链接中的答案将其直接写入请求流。 我能够转换下面链接中找到的代码来构建标头,然后将字节写入请求流。

http://code.activestate.com/recipes/146306-http-client-to-post-using-multipartform-data/

我的代码看起来类似于以下内容(为了便于阅读,我必须在下面对其进行修改,因为很多内容被抽象为整个项目的一部分,因此它可能在语法上不完美)。

  public void BuildHeader(string contentType, string filename) { if ((contentType == null) || (contentType.Length == 0)) { contentType = "application/octet-stream"; } // Create the boundary string for the POST message header string boundary = "----------" + DateTime.Now.Ticks.ToString("x"); // Build up the POST message header StringBuilder sb = new StringBuilder(); // The specific format used can be found in the HTTP protocol specs. // The 'name' variable indicates the field-name, and the last variable // added to the string before another boundary is the value for that field. sb.Append("--"); sb.Append(boundary); sb.Append("\r\n"); sb.Append("Content-Disposition: form-data; name=\""); sb.Append("path"); sb.Append("\""); sb.Append("\r\n\r\n"); sb.Append(fileName); sb.Append("--"); sb.Append(boundary); sb.Append("\r\n"); sb.Append("Content-Disposition: form-data; name=\""); sb.Append("contents"); sb.Append("\"; fileName=\""); sb.Append("abc"); sb.Append("\""); sb.Append("\r\n"); sb.Append("Content-Type: "); sb.Append(contentType); sb.Append("\r\n"); sb.Append("\r\n"); using (Stream fileStream = new FileStream(fileName, FileMode.Open, FileAccess.Read)) { // Add the file contents to the POST message byte[] buffer = new Byte[checked((uint)Math.Min(4096, (int)fileStream.Length))]; int bytesRead = 0; while ((bytesRead = fileStream.Read(buffer, 0, buffer.Length)) != 0) { sb.Append(ASCIIEncoding.ASCII.GetString(buffer)); } // Get the byte array of the POST message, and its length string totalContents = sb.ToString(); byte[] totalUpload = Encoding.UTF8.GetBytes(totalContents); int length = totalUpload.Length; } } 

请注意,这仅为上载单个文件准备标头。