Uploading files using HTTPWebRequest

I want to upload a file but can't use html input file control as I don't have any html page in my application. I am into a situation where i want to utilize all the power of HTTP protocols and internet media types like POST and multipart/form-data respectively without using any html control. This situation is not very rare and most likely you will face it while creating an automatic batch file upload utility where this is no chance of manual intervention hence no possibility of using html input file control.

Since I am using .NET, I can use low level HTTPWebRequest to upload files to webserver. This class helps simulate manual upload using ContentType=multipart/form-data. multipart/form-data can be used for forms that are presented using representations other than HTML (spreadsheets, Portable Document Format, etc), and for transport using other means than electronic mail or HTTP.

An important aspect of uploading files is the way web request is structured where every form value has to start with --{boundary} and full web reqeust has to end with --{boundary}--. This can be seen by debugging the request using any web request debugging tools like Fiddler while uploading through html input file control. We will have to immitate the same request format in order for it to be accepted by web server. Let's quickly mention some of the important parts of this request that we need to set in order to successfully upload a file.

  • ContentType: Multipart/form-data
  • Request Method: Post
  • Content-Disposition: form-data
  • Boundary: Guid

The reason to use multipart MIME type is that its is used by file upload which has a more complicated than a simple post. For a detailed explanation you can read the RFC2388 - Returning Values from Forms: multipart/form-data. For boundary we can use Guid as this is value that should not occur in any of the form value.

The funciton UploadFile() mentioned below uploads a file along with 2 other form values using the parameters mentioned above. Apart from them, HTTPWebRequest.Headers can also be used to supply credentials if our server requires authentication.

Request: (UploadFile.aspx)

Private Sub UploadLocalFile()

Dim objWebReq As HttpWebRequest
Dim memStream As MemoryStream = Nothing
Dim writer As StreamWriter = Nothing
Dim newLine As String = vbCrLf
Dim fileContent As Byte() = Nothing
Dim fileText As String = Nothing
Dim rStream As Stream = Nothing
Dim webResponse As HttpWebResponse = Nothing
Dim stReader As StreamReader = Nothing
Dim output As String = Nothing

Try

Dim boundary As String = Guid.NewGuid().ToString().Replace("-", String.Empty)
Dim obj As Object = HttpWebRequest.Create("http://localhost:3860/ReceiveFile.aspx")

objWebReq = CType(obj, HttpWebRequest)

objWebReq.ContentType = "multipart/form-data; boundary=" + boundary
objWebReq.Method = "POST"
objWebReq.Headers.Add("loginName", "{username}")
objWebReq.Headers.Add("loginPassword", "{password}")

memStream = New MemoryStream(100240)
writer = New StreamWriter(memStream)

'Feed ID
writer.Write("--" + boundary + newLine)
writer.Write("Content-Disposition: form-data; name=""{0}""{1}{2}", "FeedID", newLine, newLine)
writer.Write("10250")
writer.Write(newLine)

'Feed Category
writer.Write("--" + boundary + newLine)
writer.Write("Content-Disposition: form-data; name=""{0}""{1}{2}", "FeedCategory", newLine, newLine)
writer.Write("Automotive")
writer.Write(newLine)

'XML File
writer.Write("--" + boundary + newLine)
writer.Write("Content-Disposition: form-data; name=""{0}""; filename=""{1}""{2}", "XMLfile", "C:\Users\Irfan\Desktop\feed-automotive.xml", newLine)
writer.Write("Content-Type: text/xml " + newLine + newLine)
writer.Write(File.ReadAllText("C:\Users\Irfan\Desktop\feed-automotive.xml"))
writer.Write(newLine)

writer.Write("--{0}--{1}", boundary, newLine)

writer.Flush()

objWebReq.ContentLength = memStream.Length
rStream = objWebReq.GetRequestStream()
memStream.WriteTo(rStream)
memStream.Close()

webResponse = objWebReq.GetResponse()
stReader = New StreamReader(webResponse.GetResponseStream())
stReader.ReadToEnd()
output = stReader.ReadToEnd()

Response.Write(output)

Catch ex As Exception

Response.Write(ex.Message)

End Try

End Sub

Response: (ReceiveFile.aspx)

Private Sub ReceiveFile()

Dim reader As System.IO.StreamReader = Nothing

Try

If Not Reqeust.Files.Count > 0 AndAlso Not Request.Files("XMLFile") Is Nothing Then
reader = New System.IO.StreamReader(Request.Files("XMLFile").InputStream)
System.IO.File.WriteAllText("c:\feed.xml", reader.ReadToEnd())
Else
Response.Write("No feed file received in the request.")
End If

Catch ex As Exception
Response.Write(ex.Message)
End Try

End Sub

2 comments:

Anonymous said...

Brilliant. What I Was Needing...

Anonymous said...

this has been incredibly useful to me. thanks a lot, nice work!

Post a Comment