Click here to Skip to main content
Email Password   helpLost your password?

Introduction

Okay, so you like the idea behind WebClient's UploadFile function, but you can't get it to do all the things you want? That's were I was at a week ago. This is what I learned in the past week. UploadFile seems good enough on the surface but you can run into some tricky things fast, like if you have some cookies to manage or you want to specify the content type, or change the name of the file input in the form? Well, this function will take care of those problems and should make simulating a web form with input type=file as easy as pi, er.. pie. Under the hood is a HttpWebRequest version of UploadFile that you could use to add additional functionality.

For example...

You would like to simulate this web form from your C# application:

<form action ="http://localhost/test.php" method = POST>
<input type = text name = uname>
<input type = password name =passwd>
<input type = FILE name = uploadfile>
<input type=submit>
</form>

You could run UploadFileEx like this:

CookieContainer cookies = new CookieContainer();
//add or use cookies

NameValueCollection querystring = new NameValueCollection();
querystring["uname"]="uname";
querystring["passwd"]="snake3";
string uploadfile;// set to file to upload

uploadfile = "c:\\test.jpg";

//everything except upload file and url can be left blank if needed

string outdata = UploadFileEx(uploadfile, 
     "http://localhost/test.php","uploadfile", "image/pjpeg", 
     querystring,cookies);

So on to the code...

So, this is UploadFileEx:

public static string UploadFileEx( string uploadfile, string url, 
    string fileFormName, string contenttype,NameValueCollection querystring, 
    CookieContainer cookies)
{
    if( (fileFormName== null) ||
        (fileFormName.Length ==0))
    {
        fileFormName = "file";
    }

    if( (contenttype== null) ||
        (contenttype.Length ==0))
    {
        contenttype = "application/octet-stream";
    }


    string postdata;
    postdata = "?";
    if (querystring!=null)
    {
        foreach(string key in querystring.Keys)
        {
            postdata+= key +"=" + querystring.Get(key)+"&";
        }
    }
    Uri uri = new Uri(url+postdata);


    string boundary = "----------" + DateTime.Now.Ticks.ToString("x");
    HttpWebRequest webrequest = (HttpWebRequest)WebRequest.Create(uri);
    webrequest.CookieContainer = cookies;
    webrequest.ContentType = "multipart/form-data; boundary=" + boundary;
    webrequest.Method = "POST";


    // Build up the post message header

    StringBuilder sb = new StringBuilder();
    sb.Append("--");
    sb.Append(boundary);
    sb.Append("\r\n");
    sb.Append("Content-Disposition: form-data; name=\"");
    sb.Append(fileFormName);
    sb.Append("\"; filename=\"");
    sb.Append(Path.GetFileName(uploadfile));
    sb.Append("\"");
    sb.Append("\r\n");
    sb.Append("Content-Type: ");
    sb.Append(contenttype);
    sb.Append("\r\n");
    sb.Append("\r\n");            

    string postHeader = sb.ToString();
    byte[] postHeaderBytes = Encoding.UTF8.GetBytes(postHeader);

    // Build the trailing boundary string as a byte array

    // ensuring the boundary appears on a line by itself

    byte[] boundaryBytes = 
           Encoding.ASCII.GetBytes("\r\n--" + boundary + "\r\n");

    FileStream fileStream = new FileStream(uploadfile, 
                                FileMode.Open, FileAccess.Read);
    long length = postHeaderBytes.Length + fileStream.Length + 
                                           boundaryBytes.Length;
    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[checked((uint)Math.Min(4096, 
                             (int)fileStream.Length))];
    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 responce = webrequest.GetResponse();
    Stream s = responce.GetResponseStream();
    StreamReader sr = new StreamReader(s);

    return sr.ReadToEnd();
}

This might help too..

You can handle the post in various ways but this is the PHP file I wrote to test:

<?php

print_r($_REQUEST);

$uploadDir = '%SOMEPATH';
$uploadFile = $uploadDir . $_FILES['userfile']['name'];
print "<PRE>";
if (move_uploaded_file($_FILES['userfile']['tmp_name'], $uploadFile))
{
    print "File is valid, and was successfully uploaded. ";
}
else
{
    print "Possible file upload attack!  Here's some debugging info:\n";
    print_r($_FILES);
}
print "</PRE>";
?>

Credits...

I found most of this out by trial and error searching the web. One major source of this information was this article.

You must Sign In to use this message board.
 
 
Per page   
 FirstPrevNext
QuestionDoes not work for me, where is my problem?
Siedlerchr
3:33 13 Nov '09  
Hi, first thanks for this code, this is exactly what I need.


But there seems to be a problem, becaus as respone I only get the code of the upload-form and the file has not beeen uploaded to the server.


I have a html-form with a file upload, the file is the only parameter.

 uploadfile = @"C:\_User\CHRS\fehlerworkflow.jpg";

//everything except upload file and url can be left blank if needed

string outdata = UploadFileEx(uploadfile,
"http://siedlerchr.bplaced.net/xxxFormular.html", "uploaded", "image/pjpeg",
querystring, cookies);

So when I run the code, everything seems to be fine, but as Response I only get the code of the html upload-form and the file has not been uploaded to the server!
I don't know why!

It would be great if you can help me or say me where my problem is

Here is the input line of the form:
<input name="uploaded" type="file" />


This form calls the upload.php script, where the file should be moved:

<?php
$target = "upload/";
$target = $target . basename( $_FILES['uploaded']['name']) ;

if(move_uploaded_file($_FILES['uploaded']['tmp_name'], $target))
{
echo "The file ". basename( $_FILES['uploadedfile']['name']). " has been uploaded";
}
else {
echo "Sorry, there was a problem uploading your file.";
}
?>

Generalcancel uploading
djdane
8:16 13 May '09  
Hi all!

When I try to divide the file in small chunks and doing something simple as:



// Write out the file contents
while (byteCounter < fileData.Length)
{
if (byteCounter + chunkSize <= fileData.Length)
requestStream.Write(fileData, byteCounter, chunkSize);

if (backgorundWorker.CancellationPending)//or other implementation of cancel
{
webrequest.Abort();
requestStream.Close();
}
}


It keeps throwing exception on requestStream.Close() and keeps blocking the next upload - stream is actually not closed.

Is there any proper way to close the stream to avoid this?

Thanks!
GeneralThanks
shahid.here
5:30 29 Apr '09  
It was very useful thanks man
GeneralNice but
sabrown100
5:42 24 Dec '08  
you forgot to close the stream.
QuestionSending POST request to aspx pages [modified]
cinni
1:38 4 Dec '08  
Hi madmik3,

Really brilliant article. It helped me a lot to learn.
It works fine with PHP pages to upload files.

But i m facing problem to upload file to server by making a HTTPWebRequest to aspx pages. Please give me your suggestions on posting files to aspx pages.

Thanks in Advance

Lead a few, Follow one....Love all, Hate none....

modified on Friday, December 5, 2008 1:04 AM

GeneralUpload string + file + string
Travelster6611
2:25 19 Oct '08  
Could this be modified to do a post that requires some POST strings, the file, but then more strings afterwards? I have a website with a very funky post that request 2 string, a file, then 4 more strings. I can't figure out how to do this. I've look at dozens of great samples, like the one above, but can't find how to this what that funky website wants.

Cheers,
Glenn
Generalform data and file upload
syed wasif ali
22:21 27 Jul '08  
Hi thanks for the article.it helps me big time.I need a bit more help in this regard.
you are using query string to send form fields..Since the form i want to simulate has too many fields so i cant send them as query string. So i have to add both form fields and upload file in the request stream.Please help me out to make body part of request stream
Many thanks

wasif

Generalmore files not only one file to upload
kappos
3:23 12 Jun '08  
Hello,
first is an wonderful code snipped.
but i have a problem, I need to post 5 files and not only one.
Can anyone help me how does it work?

My code:

sb.Append("--");
sb.Append(boundary);
sb.Append("\r\n");
sb.Append("Content-Disposition: form-data; name=\"");
sb.Append(fileFormName);
sb.Append("\"; filename=\"");
//sb.Append(Path.GetFileName(uploadfile));
sb.Append("\"");
sb.Append("
\r\n");
sb.Append("
Content-Type: ");
sb.Append(contenttype);
sb.Append("
\r\n");
sb.Append("
\r\n");

///
sb.Append("
--");
sb.Append(boundary);
sb.Append("
\r\n");
sb.Append("
Content-Disposition: form-data; name=\"");
sb.Append(fileFormName);
sb.Append("\"; filename=\"");
sb.Append(Path.GetFileName(uploadfile));
sb.Append("\"");
sb.Append("
\r\n");
sb.Append("
Content-Type: ");
sb.Append(contenttype);
sb.Append("
\r\n");
sb.Append("
\r\n");

string postHeader = sb.ToString();
byte[] postHeaderBytes = Encoding.UTF8.GetBytes(postHeader);




Felix
GeneralGracias excelente solucion
Member 3104789
5:29 10 Jun '08  
de verdad esta solucion es muy util para realizar muchos procesos de envio via web se agradece al autor!! saludos kedoz
GeneralAs another commenter pointed out it's better to close the stream after you're done
dolzenko
9:01 1 Jun '08  
Here's small patch. Aside from that great job, thank you!
BEFORE:
		while ((bytesRead = fileStream.Read(buffer, 0, buffer.Length)) != 0)
requestStream.Write(buffer, 0, bytesRead);

// Write out the trailing boundary
AFTER:
		while ((bytesRead = fileStream.Read(buffer, 0, buffer.Length)) != 0)
requestStream.Write(buffer, 0, bytesRead);
fileStream.Close(); // ! ADDED
// Write out the trailing boundary

GeneralAny one know how to decode this type of post
smesser
12:19 3 Jan '08  
I want to be able to decode a multipart post with out using a PHP or .ASPX page.

Any one know of any reference material or sample projects?
QuestiongetResponse like a web browser?
Enderwiggin
11:44 14 Dec '07  
Hello... I've been playing around with the code for a while trying to get it to retrieve a responses the same way as a web browser, by that I mean, waiting for responses and retrieving them in the same way a web browser would... is there any way to do this?
GeneralWhy it freezes sometimes at requestStream.Write(buffer, 0, bytesRead);?
staryon
8:31 14 Nov '07  
I have tried changing the timeout with no luck. It will just hangs there
forever.

This class may work fine for 2 hours and suddenly have this problem.

Please help...

GeneralThanks
creatorulcom
13:11 5 Oct '07  
Very good article, it helped me a lot.
Many thanks to the author.

Regards,
Bogdan

-Creator-

QuestionWebException
tobi_z
13:49 7 Sep '07  
Hi
when I try to upload a file, I always get a Webexception at 1:40 minutes at this code:
"requestStream.Write(buffer, 0, bytesRead);"
I changed the Buffer size and tried it with different files, but the bug is always the same

Can you tell me why this bug appears and can you fix it?
GeneralHow to send a file a attachment
PhBV
3:50 3 Sep '07  
Hello,

The UploadFileEx works fine for the first file I have ti upload but the Web server is waiting for another file a attachment (Thy talk about DIME).
Somebody could tell me how I could ride on it whit this solution ?

Tnahk's a lot for help

PhBV
GeneralParse error in PHP page
EdYellowMan
5:20 22 May '07  
Hi,

The C# code works fine but the sr.ReadToEnd() return this:
Parse error: syntax error, unexpected T_STRING in C:\php\upload2.php on line 10

I'm very unexperienced with PHP. Anybody an idea how I can solve this?

Thanks!

Pete
GeneralGreat Job!
kkkwkk
5:11 17 May '07  
Thanks for sharing Smile
GeneralGet error in Tomcat
franciscomesa
5:00 28 Apr '07  
I'm using the UploadFileEx, post version, and get an exception in Tomcat. Stream ended unexpectedly. I see that the length is ok, I send all packets, but, seems server don't get it. I use the 8080 port.

Any idea?
GeneralRe: Get error in Tomcat
craighack2
18:36 4 Jun '09  
I meet the same problem with Tomcat.
After reading the introduction of upload file standard,
it seems to require to do the following change to this line of code.

byte[] boundaryBytes =
Encoding.ASCII.GetBytes("\r\n--" + boundary + "\r\n");

byte[] boundaryBytes =
Encoding.ASCII.GetBytes("\r\n--" + boundary + "--\r\n");


Hope that other guys with the same problem can this thread to solve the problem.
Generalerrors
Aaron Sulwer
7:39 9 Aug '06  
when i post my file to the webserver (https) i am getting an error that i cannot resolve.

Error: Cannot find bean: "Uploadbean" in any scope

any ideas on what would cause this error?
GeneralIO.Exception, Cannot close stream until all bytes are written
interesting.com.au
21:15 27 Jul '06  
We had problems sending files larger then 7 Mb or so. The HttpWebRequest has a Timeout property, which defaults to 100000 ms, we upped that and it now seems to be working for larger files.
GeneralPlease Close() your files when done with them!!!
Furroy
5:45 19 Jul '06  
Worked great, after I added a mess of stream.Close() calls!

GeneralDid not work for me
MRKKO
7:26 17 May '06  
For some reason, the component would not work for me. I did find a more flexible solution, in the form of a cheap .NET component that allows you to navigate to pages, and interact with forms. It allows for multipart form post, and file upload, handling cookies and redirects and proxies automatically. It's pretty nifty.

You can find it over at http://foxtrot-xray.com/web-robot

GeneralRe: Did not work for me
Mystic_
4:59 20 May '06  
solution u mentioned costs but i want to develop this solution my self. its a kind of study project.


Last Updated 20 Oct 2004 | Advertise | Privacy | Terms of Use | Copyright © CodeProject, 1999-2010