Okay, I have a problem that has been stumping me for weeks. I have tried many different solutions and this is pretty much my last resort. I have seen a lot of good answers give here so I figured I would give it a try.
First of all, I am using Visual Studio 2005 to write my program. I am using C# .NET as the language. I am running Windows XP Professional with all service packs and updates applied.
Now, I have been trying to write a program that batch uploads pictures to the image hosting service ImageVenue, http://www.imagevenue.com (On a side note, I have tried also with ImageShack but also had the same results). I can't seem to get it right because ImageVenue never returns the linking code to the image. I will post my code as well as some other stuff I have grabbed along the way in hopes that somebody can pick out my error. The code I have written has mostly been borrowed from the web but I have also added to it. I am using a class called MultipartFileUpload to do the uploading and I have written a sort of "driver" program to test the class. I will post the MultipartFileUpload code first.
Here is the code for MultipartFileUpload:
-
using System;
-
using System.Collections.Generic;
-
using System.Text;
-
using System.Collections.Specialized;
-
using System.Net;
-
using System.IO;
-
-
namespace IVUp
-
{
-
public class MultipartFileUpload
-
{
-
private Uri uri = null;
-
private NameValueCollection parameters = null;
-
private NameValueCollection formData = null;
-
private String fileDisplayName = null;
-
private String fileParameterName = null;
-
private FileInfo file = null;
-
private NetworkCredential networkCredential = null;
-
private String boundary = null;
-
private readonly int BUFFER_SIZE = 500;
-
-
#region constructors
-
-
public MultipartFileUpload()
-
{
-
parameters = new NameValueCollection();
-
formData = new NameValueCollection();
-
-
//the boundary signals the we server to look for a new form value or data segment
-
boundary = "----------" + DateTime.Now.Ticks.ToString("x");
-
}
-
-
public MultipartFileUpload(Uri uri) : this()
-
{
-
this.uri = uri;
-
}
-
-
#endregion
-
-
#region getters and setters
-
-
/// <summary>
-
/// the destination of the multipart file upload
-
/// </summary>
-
-
public Uri Uri
-
{
-
get { return this.uri; }
-
-
set { this.uri = value; }
-
}
-
-
/// <summary>
-
/// the parameters to be passed along with the post method — optional
-
/// </summary>
-
-
public NameValueCollection Parameters
-
{
-
get { return this.parameters; }
-
-
set { this.parameters = value; }
-
}
-
-
/// <summary>
-
/// any form data associated with the post method
-
/// </summary>
-
-
public NameValueCollection FormData
-
{
-
get { return this.formData; }
-
-
set { this.formData = value; }
-
}
-
-
/// <summary>
-
/// if your web server requires credentials to upload a file, set them here — optional
-
/// </summary>
-
-
public NetworkCredential NetworkCredential
-
{
-
get { return this.networkCredential; }
-
-
set { this.networkCredential = value; }
-
}
-
-
#endregion
-
-
#region public methods
-
-
/// <summary>
-
/// adds a parameter to the request, if the parameter already has a value,
-
/// it will be overwritten
-
/// </summary>
-
-
/// <param name="name">name of the parameter</param>
-
/// <param name="value">value of the parameter</param>
-
-
public void AddParameter(String name, String value)
-
{
-
if (this.parameters == null)
-
{
-
this.parameters = new NameValueCollection();
-
}
-
this.parameters.Set(name, value);
-
}
-
-
/// <summary>
-
/// adds a form value to the request, if the form field already exists, overwrite it
-
/// </summary>
-
-
/// <param name="name">the name of the form field</param>
-
/// <param name="value">value of the form field</param>
-
-
public void AddFormValue(String name, String value)
-
{
-
if (this.formData == null)
-
{
-
this.formData = new NameValueCollection();
-
}
-
this.parameters.Set(name, value);
-
}
-
-
/// <summary>
-
/// attach a file to the post method, the parameter name and file can not be null
-
/// </summary>
-
-
/// <param name="fileDisplayName">the name of the file as it should appear to the web server</param>
-
/// <param name="parameterName">the parameter that your web server expects to be associated with a file</param>
-
/// <param name="file">the actual file you want to upload</param>
-
/// <exception cref="ArgumentNullException">file can not be null, name of the parameter can’t be null</exception>
-
-
public void AttachFile(String fileDisplayName, String parameterName, FileInfo file)
-
{
-
if(file == null)
-
{
-
throw new ArgumentNullException("file", "You must pass a reference to a file");
-
}
-
if (parameterName == null)
-
{
-
throw new ArgumentNullException("parameterName", "You must provide the name of the file parameter.");
-
}
-
this.file = file;
-
if (this.fileDisplayName == null)
-
{
-
this.fileDisplayName = file.Name;
-
}
-
}
-
-
/// <summary>
-
/// performs the actual upload
-
/// </summary>
-
/// <returns>the response as a string</returns>
-
-
public String UploadFileEx()
-
{
-
//tack on any parameters or just give us back the uri if there are no parameters
-
Uri targetUri = CreateUriWithParameters();
-
HttpWebRequest webrequest = (HttpWebRequest)WebRequest.Create(targetUri);
-
webrequest.Credentials = networkCredential; //fine if it’s null
-
webrequest.ContentType = "multipart/form-data; boundary=" + boundary;
-
webrequest.Method = "POST";
-
-
//encode header
-
String postHeader = CreatePostDataString();
-
byte[] postHeaderBytes = Encoding.UTF8.GetBytes(postHeader);
-
byte[] boundaryBytes = Encoding.ASCII.GetBytes("\r\n–" + boundary + "\r\n");
-
-
//read in the file as a stream
-
FileStream fileStream = file.Open(FileMode.Open, FileAccess.Read);
-
long length = postHeaderBytes.Length + fileStream.Length +boundaryBytes.Length;
-
-
//the request method needs to know how big the file is before we start the upload
-
webrequest.ContentLength = length;
-
Stream requestStream = webrequest.GetRequestStream();
-
-
// Write out our post header
-
requestStream.Write(postHeaderBytes, 0, postHeaderBytes.Length);
-
-
// Write out the file contents
-
byte[] buffer = new byte[BUFFER_SIZE];
-
int bytesRead = 0;
-
while ((bytesRead = fileStream.Read(buffer, 0, buffer.Length)) != 0)
-
{
-
requestStream.Write(buffer, 0, bytesRead);
-
}
-
-
// Write out the trailing boundary
-
requestStream.Write(boundaryBytes, 0, boundaryBytes.Length);
-
WebResponse response = webrequest.GetResponse();
-
StreamReader sr = new StreamReader(response.GetResponseStream());
-
return sr.ReadToEnd(); //response body
-
}
-
-
#endregion
-
-
#region private methods
-
-
/// <summary>
-
/// helper method to tack on parameters to the request
-
/// </summary>
-
/// <returns>Uri with parameters, or the original uri if it’s null</returns>
-
-
private Uri CreateUriWithParameters()
-
{
-
if (uri == null) return null;
-
if (parameters == null || parameters.Count <= 0)
-
{
-
return this.uri;
-
}
-
-
String paramString = "?";
-
foreach (String key in parameters.Keys)
-
{
-
paramString += key + "=" + parameters.Get(key)+"&";
-
}
-
-
paramString = paramString.Substring(0, paramString.Length - 1); //strip off last &
-
return new Uri(uri.ToString() + paramString);
-
}
-
-
/// <summary>
-
/// post data as a string with the boundaries
-
/// </summary>
-
-
/// <returns>a string representing the form data</returns>
-
-
private String CreatePostDataString()
-
{
-
StringBuilder sb = new StringBuilder();
-
for (int i = 0; i < formData.Count; i++)
-
{
-
sb.Append("–" + boundary + "\r\n");
-
sb.Append("Content-Disposition: form-data; name=\"");
-
sb.Append(formData.GetKey(i) + "\"\r\n\r\n" + formData.Get(i) + "\r\n");
-
}
-
-
sb.Append("–" + boundary + "\r\n");
-
sb.Append("Content-Disposition: form-data; name=\"" + fileParameterName + "\";");
-
sb.Append("filename=\"" + fileDisplayName + "\" Content-Type: application/octet-stream\r\n\r\n");
-
return sb.ToString();
-
}
-
-
#endregion
-
}
-
}
-
Here is what I have done for the testing part:
-
using System;
-
using System.Collections.Generic;
-
using System.ComponentModel;
-
using System.Data;
-
using System.Drawing;
-
using System.Text;
-
using System.Windows.Forms;
-
using System.IO;
-
-
namespace IVUp
-
{
-
public partial class Form1 : Form
-
{
-
public Form1()
-
{
-
InitializeComponent();
-
}
-
-
private void button1_Click(object sender, EventArgs e)
-
{
-
//MultipartFileUpload Class Code
-
-
String UploadResults = "";
-
MultipartFileUpload MyMultipart = new MultipartFileUpload();
-
-
Uri MyUri = new Uri("http://imagevenue.com/upload.php");
-
-
MyMultipart.Uri = MyUri;
-
openFileDialog1.ShowDialog();
-
FileInfo MyFile = new FileInfo(openFileDialog1.FileName);
-
//MyMultipart.AddFormValue("hostval", "10");
-
MyMultipart.AttachFile("Test.jpg", "userfile[]", MyFile);
-
//MyMultipart.AddFormValue("userfile[]", "C:\\Test.jpg");
-
MyMultipart.AddFormValue("imgcontent", "notsafe");
-
MyMultipart.AddFormValue("MAX_FILE_SIZE", "");
-
MyMultipart.AddFormValue("action", "1");
-
MyMultipart.AddFormValue("img_resize", "");
-
-
UploadResults = MyMultipart.UploadFileEx();
-
-
richTextBox1.Text = UploadResults;
-
}
-
}
-
}
-
I have been using Ethereal to capture packets to see if something is wrong with the http part of the stuff. Here is what a standard upload from firefox looks like:
POST /upload.php HTTP/1.1
Host: imagevenue.com
User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.5) Gecko/20070713 ImageShackToolbar/4.2.1 Firefox/2.0.0.5
Accept: text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip,deflate
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Keep-Alive: 300
Connection: keep-alive
Referer: http://imagevenue.com/host.php
Cookie: __utmz=122915731.1183006481.1.1.utmccn=(direct)|ut mcsr=(direct)|utmcmd=(none); pval=1185169867; __utma=122915731.858623389.1183006481.1183006481.1 186080644.2; __utmc=122915731
And here is what the stuff from my program has looked like so far:
POST /upload.php?imgcontent=notsafe&MAX_FILE_SIZE=&actio n=1&img_resize= HTTP/1.1
Content-Type: multipart/form-data; boundary=----------8c9a331c0cc2e10
Host: imagevenue.com
Content-Length: 12888
Expect: 100-continue
Connection: Keep-Alive
Any help on this would be greatly appreciated. Thanks.