Click here to Skip to main content
15,891,692 members
Articles / Programming Languages / C#
Article

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

Rate me:
Please Sign up or sign in to vote.
4.81/5 (33 votes)
19 Oct 20041 min read 434.9K   4.6K   87   81
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:

HTML
<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:

C#
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:

C#
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
<?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


Written By
United States United States
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
BugUsing this code gave me 400 Bad request (malformed multipart POST) errors [Solved] Pin
Member 1027044710-Oct-13 10:22
Member 1027044710-Oct-13 10:22 
QuestionThanks for nice code but Length = 'requestStream.Length' threw an exception of type 'System.NotSupportedException' Pin
Milind_Morey9-Jul-13 3:16
professionalMilind_Morey9-Jul-13 3:16 
Questionthanx Pin
Member 980996929-Apr-13 7:26
Member 980996929-Apr-13 7:26 
Questionhelp, In VB.NET ?? Pin
mikrophun1-Jul-12 23:15
mikrophun1-Jul-12 23:15 
Hi madmik3,

i try to write your code in VB.NET, I'm using converter and modified some line with the result that as below, the code run fine and nothing error. but the file failed to upload (the folder still empty). I'm wondering where the problem occur..

VB
Imports System
Imports System.Web
Imports System.Collections.Specialized
Imports System.Text
Imports System.Net
Imports System.IO

Public Class Form1

    Public Shared Function UploadFileEx(uploadfile As String, url As String, fileFormName As String, contenttype As String, querystring As NameValueCollection, cookies As CookieContainer) As String
        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 querystring IsNot Nothing Then
            For Each key As String In querystring.Keys
                postdata += key + "=" + querystring.[Get](key) + "&"
            Next
        End If
        Dim uri As New Uri(url + postdata)


        Dim boundary As String = "----------" + DateTime.Now.Ticks.ToString("x")
        Dim webrequest__1 As HttpWebRequest = DirectCast(WebRequest.Create(uri), HttpWebRequest)
        webrequest__1.CookieContainer = cookies
        webrequest__1.ContentType = "multipart/form-data; boundary=" + boundary
        webrequest__1.Method = "POST"


        ' Build up the post message header
        Dim sb As 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")

        Dim postHeader As String = sb.ToString()
        Dim postHeaderBytes As Byte() = Encoding.UTF8.GetBytes(postHeader)

        ' Build the trailing boundary string as a byte array
        ' ensuring the boundary appears on a line by itself
        Dim boundaryBytes As Byte() = Encoding.ASCII.GetBytes("\r\n--" + boundary + "\r\n")

        Dim fileStream As New FileStream(uploadfile, FileMode.Open, FileAccess.Read)
        Dim length As Long = postHeaderBytes.Length + fileStream.Length + boundaryBytes.Length
        webrequest__1.ContentLength = length

        Dim requestStream As Stream = webrequest__1.GetRequestStream()

        ' Write out our post header
        requestStream.Write(postHeaderBytes, 0, postHeaderBytes.Length)

        ' Write out the file contents
        Dim buffer As Byte() = New [Byte](CUInt(Math.Min(4096, CInt(fileStream.Length))) - 1) {}
        Dim bytesRead As Integer = 0
        While (InlineAssignHelper(bytesRead, fileStream.Read(buffer, 0, buffer.Length))) <> 0
            'sbyte* buffer2 = { 44, 43, 42, 0};
            'String str = new String(buffer2);
            'Console.WriteLine("ISI: " + bytesRead)
            requestStream.Write(buffer, 0, bytesRead)
        End While
        'Console.ReadKey()  'biar consolnya langsung nutup/close

        ' Write out the trailing boundary
        requestStream.Write(boundaryBytes, 0, boundaryBytes.Length)
        requestStream.Flush()
        Dim responce As WebResponse = webrequest__1.GetResponse()
        Dim s As Stream = responce.GetResponseStream()
        Dim sr As New StreamReader(s)

        Return sr.ReadToEnd()
    End Function

    Private Shared Function InlineAssignHelper(Of T)(ByRef target As T, value As T) As T
        target = value
        Return value
    End Function

    Private Sub btnUpload_Click(sender As System.Object, e As System.EventArgs) Handles btnUpload.Click
        Dim cookies As New CookieContainer()
        'add or use cookies

        Dim querystring As New NameValueCollection()

        ' simulate this form 
        '<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>


        querystring("uname") = ""
        querystring("passwd") = ""

        Dim uploadfile As String
        ' set to file to upload
        uploadfile = "D:\nisa.jpg"

        Dim ret As [String] = UploadFileEx(uploadfile, "http://192.168.56.2/webtest/test.php", "file", "image/jpg", querystring, cookies)
        Console.WriteLine(ret)
        'Console.ReadKey()
    End Sub
End Class

AnswerRe: help, In VB.NET ?? Pin
danglez8326-Sep-13 5:43
danglez8326-Sep-13 5:43 
Questionany version in ASPX of PHP file ? Pin
kiquenet.com12-Dec-11 9:51
professionalkiquenet.com12-Dec-11 9:51 
QuestionNot ok for videos file upload Pin
KKKT24-Jul-11 23:42
KKKT24-Jul-11 23:42 
GeneralHCG Ultra Pin
rmronimolic15-Jun-10 20:50
rmronimolic15-Jun-10 20:50 
QuestionDoes not work for me, where is my problem? Pin
Siedlerchr13-Nov-09 2:33
Siedlerchr13-Nov-09 2:33 
Generalcancel uploading Pin
djdane13-May-09 7:16
djdane13-May-09 7:16 
GeneralRe: cancel uploading Pin
killix14-May-10 0:00
killix14-May-10 0:00 
GeneralThanks Pin
shahid.here29-Apr-09 4:30
shahid.here29-Apr-09 4:30 
GeneralNice but Pin
sabrown10024-Dec-08 4:42
sabrown10024-Dec-08 4:42 
QuestionSending POST request to aspx pages [modified] Pin
Cinni4-Dec-08 0:38
Cinni4-Dec-08 0:38 
GeneralUpload string + file + string Pin
Travelster661119-Oct-08 1:25
Travelster661119-Oct-08 1:25 
Generalform data and file upload Pin
syed wasif ali27-Jul-08 21:21
syed wasif ali27-Jul-08 21:21 
Generalmore files not only one file to upload Pin
kappos12-Jun-08 2:23
kappos12-Jun-08 2:23 
GeneralGracias excelente solucion Pin
Member 310478910-Jun-08 4:29
Member 310478910-Jun-08 4:29 
GeneralAs another commenter pointed out it's better to close the stream after you're done Pin
dolzenko1-Jun-08 8:01
dolzenko1-Jun-08 8:01 
GeneralAny one know how to decode this type of post Pin
Steve Messer3-Jan-08 11:19
Steve Messer3-Jan-08 11:19 
QuestiongetResponse like a web browser? Pin
Enderwiggin14-Dec-07 10:44
Enderwiggin14-Dec-07 10:44 
QuestionWhy it freezes sometimes at requestStream.Write(buffer, 0, bytesRead);? Pin
LEM314-Nov-07 7:31
LEM314-Nov-07 7:31 
GeneralThanks Pin
bogdandanielb5-Oct-07 12:11
bogdandanielb5-Oct-07 12:11 
QuestionWebException Pin
tobi_z7-Sep-07 12:49
tobi_z7-Sep-07 12:49 
QuestionHow to send a file a attachment Pin
PhBV3-Sep-07 2:50
PhBV3-Sep-07 2:50 

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

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