I want to POST multiple files and form variables to a CGI script, all in one HTTP request. I believe this requires a HTTP post with multipart/form-data
encoding. Here is a sample HTML form that sends the required information; I need to send the same information through the application:
<form action="/process.php" enctype="multipart/form-data" method="post">
<input type="text" name="foo" value="bar">
<input type="text" name="blah" value="baz">
<input type="file" name="file1">
<input type="file" name="file2">
<input type="file" name="file3">
</form>
Please note that the application is a C# .NET GUI (or console) application, not an ASP.Net application.
I did this last year based upon some code that I found. It supports exactly what you want, both files and values.
Here is the class called HttpForm
:
public class HttpForm {
private Dictionary<string, string> _files = new Dictionary<string, string>();
private Dictionary<string, string> _values = new Dictionary<string, string>();
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<string, string> files, Dictionary<string, string> 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<MimePart>();
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; }
}
}
You can use it like this:
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();
Let me know if it works for you.