Click here to Skip to main content
Licence 
First Posted 19 Oct 2004
Views 231,287
Bookmarked 79 times

UploadFileEx: C#'s WebClient.UploadFile with more functionality

By | 19 Oct 2004 | Article
UploadFile hides some of the things you might need to get your Windows client simulating forms with file input fields. UploadFileEx gives you more control where you need it!

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.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here

About the Author

madmik3



United States United States

Member



Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board. (secure sign-in)
 
Search this forum  
 FAQ
    Noise  Layout  Per page   
  Refresh
GeneralRe: WebClient with cookies now possible. Pinmemberu7pro4:33 2 Mar '07  
GeneralRe: WebClient with cookies now possible. Pinmemberkatokay5:28 2 Mar '07  
QuestionRe: WebClient with cookies now possible. PinmemberNickHD2:28 22 Apr '07  
QuestionRe: WebClient with cookies now possible. PinmemberNooklez23:37 18 Jun '07  
AnswerRe: WebClient with cookies now possible. (Wrong) PinmemberAbsolute Solutions20:46 11 Jul '07  
GeneralPOST data Pinmembermorecraf4:21 1 Mar '06  
GeneralRe: POST data Pinmembersatyajeeth1:01 20 Feb '07  
I managed to get it working for post forms.. modified code below..may be of use to others. Big Grin | :-D
 
Public Function UploadFileEx2(ByVal theReferer As String, ByVal postMethod As String, ByVal uploadfilename As String, ByVal url As String, ByVal fileFormName As String, ByVal contenttype As String, ByVal querystring As System.Collections.Specialized.NameValueCollection, ByVal cookies As CookieContainer) As String
Try
Dim uri As Uri
 
If (fileFormName Is Nothing) OrElse (fileFormName.Length = 0) Then
fileFormName = "file"
End If
If (contenttype Is Nothing) OrElse (contenttype.Length = 0) Then
contenttype = "application/octet-stream"
End If
Dim postdata As String
 

postdata = "?"
If Not (querystring Is Nothing) Then
For Each key As String In querystring.Keys
postdata += key + "=" + querystring.Get(key) + "&"
Next
End If
 

If postMethod = "POST" Then
uri = New Uri(url)
Else
uri = New Uri(url + postdata)
End If
 

 
Dim boundary As String = "----------" + DateTime.Now.Ticks.ToString("x")
Dim webrequest As HttpWebRequest
webrequest = HttpWebRequest.Create(uri)
webrequest.CookieContainer = cookies
webrequest.ContentType = "multipart/form-data; boundary=" + boundary
 
webrequest.Method = postMethod
 
Dim sb As StringBuilder = New StringBuilder
 

If postMethod = "POST" Then
 
For Each key As String In querystring.Keys
sb.Append("--")
sb.Append(boundary)
sb.Append("" & Microsoft.VisualBasic.Chr(13) & "" & Microsoft.VisualBasic.Chr(10) & "")
sb.Append("Content-Disposition: form-data; name=""")
sb.Append(key)
sb.Append("""" & Microsoft.VisualBasic.Chr(13) & "" & Microsoft.VisualBasic.Chr(10) & "")
sb.Append("" & Microsoft.VisualBasic.Chr(13) & "" & Microsoft.VisualBasic.Chr(10) & "")
sb.Append(querystring.Get(key))
sb.Append("" & Microsoft.VisualBasic.Chr(13) & "" & Microsoft.VisualBasic.Chr(10) & "")
Next
 
End If
 

 
sb.Append("--")
sb.Append(boundary)
sb.Append("" & Microsoft.VisualBasic.Chr(13) & "" & Microsoft.VisualBasic.Chr(10) & "")
sb.Append("Content-Disposition: form-data; name=""")
sb.Append(fileFormName)
sb.Append("""; filename=""")
sb.Append(Path.GetFileName(uploadfilename))
sb.Append("""")
sb.Append("" & Microsoft.VisualBasic.Chr(13) & "" & Microsoft.VisualBasic.Chr(10) & "")
sb.Append("Content-Type: ")
sb.Append(contenttype)
sb.Append("" & Microsoft.VisualBasic.Chr(13) & "" & Microsoft.VisualBasic.Chr(10) & "")
sb.Append("" & Microsoft.VisualBasic.Chr(13) & "" & Microsoft.VisualBasic.Chr(10) & "")
Dim postHeader As String = sb.ToString
Dim postHeaderBytes As Byte() = Encoding.UTF8.GetBytes(postHeader)
Dim boundaryBytes As Byte() = Encoding.ASCII.GetBytes("" & Microsoft.VisualBasic.Chr(13) & "" & Microsoft.VisualBasic.Chr(10) & "--" + boundary + "" & Microsoft.VisualBasic.Chr(13) & "" & Microsoft.VisualBasic.Chr(10) & "")
Dim fileStream As FileStream = New FileStream(uploadfilename, FileMode.Open, FileAccess.Read)
Dim length As Long = postHeaderBytes.Length + fileStream.Length + boundaryBytes.Length
webrequest.ContentLength = length
webrequest.Referer = theReferer
Dim requestStream As Stream = webrequest.GetRequestStream
requestStream.Write(postHeaderBytes, 0, postHeaderBytes.Length)
Dim sendBuffer(Math.Min(4096, fileStream.Length)) As Byte
Dim bytesRead As Integer = 0
'Dim r As New BinaryReader(fileStream)
 
Do
bytesRead = fileStream.Read(sendBuffer, 0, sendBuffer.Length)
If bytesRead = 0 Then Exit Do
requestStream.Write(sendBuffer, 0, bytesRead)
Loop
 
requestStream.Write(boundaryBytes, 0, boundaryBytes.Length)
requestStream.Flush()
requestStream.Close()
 
Dim responce As WebResponse = webrequest.GetResponse
Dim s As Stream = responce.GetResponseStream
Dim sr As StreamReader = New StreamReader(s)
Dim buf As String = sr.ReadToEnd
Return sr.ReadToEnd
Catch ex As Exception
MsgBox("Error in uploadfileEx:" & ex.ToString)
Return ""
End Try

 

GeneralClosing Boundary Error PinmemberNick Lucas5:02 16 Dec '05  
GeneralRe: Closing Boundary Error PinmemberKartik Ganesan11:18 29 Nov '06  
GeneralProxy problems PinmemberKriG2:02 23 Nov '05  
Generaldon't know how to resolve this error Pinmemberwarenbe12:57 10 Nov '05  
GeneralRe: don't know how to resolve this error Pinmemberinteresting.com.au20:14 27 Jul '06  
GeneralRe: don't know how to resolve this error Pinmemberwarenbe0:22 28 Jul '06  
GeneralRe: don't know how to resolve this error PinmemberMancrut deeeee19:19 17 Nov '06  
Questioncan we asp file instead of php file Pinmemberpayoshini19:45 23 May '05  
QuestionServer response indication? PinsussAnonymous7:27 16 May '05  
GeneralProgress PinmemberMr Smiley15:33 27 Apr '05  
GeneralRe: Progress Pinmembermadmik34:03 28 Apr '05  
GeneralRe: Progress PinmemberAndreRovani4:39 24 May '05  
GeneralRe: Progress Pinmemberalpha_krone19:45 16 Jul '07  
GeneralGot Error 401.1 from the server. PinmemberAntonio M.M. Neves8:35 21 Apr '05  
GeneralVB.Net revision Pinmembersandeegk7712:49 14 Apr '05  
GeneralWhy I cant execute this using php Pinmemberegoing1:37 11 Apr '05  
GeneralPocketPC Version PinsussSergio ChRoNoN6:33 8 Mar '05  
GeneralRe: PocketPC Version PinsussSergio ChRoNoN9:41 8 Mar '05  

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

Permalink | Advertise | Privacy | Mobile
Web02 | 2.5.120529.1 | Last Updated 20 Oct 2004
Article Copyright 2004 by madmik3
Everything else Copyright © CodeProject, 1999-2012
Terms of Use
Layout: fixed | fluid