I've been reading gobs of articles on FTP upload in ASP.NET recently and they all seem to make sense, but every time I've tried implementing them I either get an empty file uploaded, or no file at all. Here are some of the articles I've been reading:
- Managing FTP Transfers from an ASP.NET Web Page By John Peterson
- FileUpload Control Doesn’t Give Full Path….HELP!!!!
- How to: Upload Files with the FileUpload Web Server Control
They're all great articles, but like I said, having issues :(
I know exactly what the problem is but I don't know how to fix it. I can pass the file name from the FileUpload control, but the path does not exist for security concerns. However, the StreamReader object requires the fully qualified path of the file to be uploaded, so how the heck do I get that? I'm at my wits end! >.<
Let's use the example by John Peterson that I linked above. Here's the code:
Protected Sub btnUploadFile_Click(ByVal sender As Object, ByVal e As System.EventArgs)
Dim myFtpWebRequest As FtpWebRequest
Dim myFtpWebResponse As FtpWebResponse
Dim myStreamWriter As StreamWriter
myFtpWebRequest = WebRequest.Create("ftp://ftp_server_name/filename.ext")
myFtpWebRequest.Method = WebRequestMethods.Ftp.UploadFile
myFtpWebRequest.UseBinary = True
myStreamWriter = New StreamWriter(myFtpWebRequest.GetRequestStream())
'IT BREAKS HERE BECAUSE THE CLIENT PATH IS WRONG!!
myStreamWriter.Write(New StreamReader(Server.MapPath("filename.ext")).ReadToEnd)
myStreamWriter.Close()
myFtpWebResponse = myFtpWebRequest.GetResponse()
myFtpWebResponse.Close()
End Sub
See? No data in the uploaded file :(
Now my latest implementation looks like this, but the uploaded file is much larger than the source, and corrupted. Seriously, what the heck am I doing wrong? I've been two LONG days at this, grrr...
Protected Sub btnUploadFile2_Click(ByVal sender As Object, ByVal e As System.EventArgs)
Dim myFtpWebRequest As FtpWebRequest
Dim myFtpWebResponse As FtpWebResponse
filename = Path.GetFileName(FileUpload1.FileName)
myFtpWebRequest = CType(WebRequest.Create(ftpServer + ftpPath + filename), FtpWebRequest)
myFtpWebRequest.Method = WebRequestMethods.Ftp.UploadFile
myFtpWebRequest.UseBinary = True
'NEW APPROACH USING THE STREAM OF THE FILE FROM THE FileUpload Control
'CORRECT BYTE LENGTH - in sourceStream.BaseStream
Dim sourceStream As New StreamReader(FileUpload1.FileContent)
'WRONG BYTE LENGTH - in sourceStream.ReadToEnd()
Dim fileContents As Byte() = Encoding.UTF8.GetBytes(sourceStream.ReadToEnd())
sourceStream.Close()
myFtpWebRequest.ContentLength = fileContents.Length
Dim requestStream As Stream = myFtpWebRequest.GetRequestStream()
requestStream.Write(fileContents, 0, fileContents.Length)
requestStream.Close()
myFtpWebResponse = CType(myFtpWebRequest.GetResponse(), FtpWebResponse)
myFtpWebResponse.Close()
End Sub
Thanks ever so much to Adam Maras for the amazing answer. I'll leave my blunders here for others to benefit who find this thread ;)
The data gets corrupted because you are reading the file as if it was text, but it's not.
Use a
BinaryReader
instead of aStreamReader
so that you can read the data as bytes directly:First of all, you must upload through the web server if you're going to use ASP.NET like this. Without installing a plugin on the client's browser or using an ActiveX control (or similar) you absolutely cannot upload directly from the client machine to the FTP server.
I assume you're uploading binary files; if that's the case, the way you're using
StreamReader
s andStreamWriter
s could be corrupting the binary contents of the file. Instead, we can use theStream.CopyTo
method to move the data verbatim from one stream to the other.I've modified your method to use this pattern instead:
The
FileUpload.SaveAs()
method saves to the Web server's local file system, and can't write to a URI or FTP site. To do that, you'll need to create aWebRequest
.See the MSDN reference for the FileUpload control here: http://msdn.microsoft.com/en-us/library/system.web.ui.webcontrols.fileupload.saveas.aspx
and for the FTP use of a WebRequest here: http://msdn.microsoft.com/en-us/library/ms229715.aspx
Note the example given in the FileUpload documentation saves to c:\temp\uploadedfiles. I'd suggest you use
Path.GetTempFileName()
instead as this is guaranteed to give you a file that can always be written no matter what environment you're under.