Zero size files uploaded with FTP FileUpload
Asked Answered
A

3

1

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:

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

enter image description here

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 ;)

Aforetime answered 12/10, 2011 at 18:4 Comment(3)
@Jim: Well how can I do that when the server doesn't have access to the client-side file path? The FileUpload Control doesn't support this at least.Aforetime
Did you try saving the file from the file upload first then try sending it to the ftp server?Concentration
@Concentration No, because you ought to be able to send it directly to FTP. Going through the web server just seems ridiculous. If that's the only way, I have no idea. I'm just trying to troubleshoot this piece by piece, but it's driving me crazy.Aforetime
R
1

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 StreamReaders and StreamWriters could be corrupting the binary contents of the file. Instead, we can use the Stream.CopyTo method to move the data verbatim from one stream to the other.

I've modified your method to use this pattern instead:

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

    Dim myFileStream As Stream = FileUpload1.FileContent
    myFtpWebRequest.ContentLength = myFileStream.Length

    Dim requestStream As Stream = myFtpWebRequest.GetRequestStream()
    myFileStream.CopyTo(requestStream)
    requestStream.Close()

    myFtpWebResponse = CType(myFtpWebRequest.GetResponse(), FtpWebResponse)
    myFtpWebResponse.Close()
End Sub
Reversion answered 13/10, 2011 at 22:52 Comment(1)
OH MY GOSH!! IT WORKED!! I had to modify it a bit because you were writing in C# style, but with VB, lol. Seriously, my brain was completely fried. I'm eternally grateful. Thank you so very very much!! :)Aforetime
A
1

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 a WebRequest.

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.

Alexander answered 12/10, 2011 at 18:8 Comment(3)
So it does. Well as you can see in my code, one of my attempts wrote to the FTP server, but didn't actually write the data. I've already looked at both pages you linked previously. I can't get the code to work using the WebRequest article, but I'll give it yet another look. Would still appreciate some code (or edit mine) if you would be so kind. Thanks :)Aforetime
From what I can tell your Attempt #3 didn't actually write the file locally. Add a File1.SaveAs( // temp. file // ) and you should be good to go.Alexander
I tried your suggestions, but still no data in my uploaded file :( Please see my updates and screenshot in my post. I appreciate your help very much :)Aforetime
R
1

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 StreamReaders and StreamWriters could be corrupting the binary contents of the file. Instead, we can use the Stream.CopyTo method to move the data verbatim from one stream to the other.

I've modified your method to use this pattern instead:

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

    Dim myFileStream As Stream = FileUpload1.FileContent
    myFtpWebRequest.ContentLength = myFileStream.Length

    Dim requestStream As Stream = myFtpWebRequest.GetRequestStream()
    myFileStream.CopyTo(requestStream)
    requestStream.Close()

    myFtpWebResponse = CType(myFtpWebRequest.GetResponse(), FtpWebResponse)
    myFtpWebResponse.Close()
End Sub
Reversion answered 13/10, 2011 at 22:52 Comment(1)
OH MY GOSH!! IT WORKED!! I had to modify it a bit because you were writing in C# style, but with VB, lol. Seriously, my brain was completely fried. I'm eternally grateful. Thank you so very very much!! :)Aforetime
K
1

The data gets corrupted because you are reading the file as if it was text, but it's not.

Use a BinaryReader instead of a StreamReader so that you can read the data as bytes directly:

Dim fileContents As Byte()
Using sourceStream As New BinaryReader(FileUpload1.FileContent)
  fileContents = sourceStream.ReadBytes(Int32.MaxValue)
End Using
Kiushu answered 13/10, 2011 at 23:32 Comment(2)
Where are you using BinaryReader in the above code? I see only StreamReader . can you please elaborate?Harrovian
@Eyalk: I corrected the code, thanks for spotting that. It was supposed to be a BinaryReader in the code all along, as it is using the ReadBytes method. There is no such method in the StreamReader class.Kiushu

© 2022 - 2024 — McMap. All rights reserved.