Briefly this is what I do:
All FTP actions are carried out in a separate thread.
After doing some CWD and file listing with the FTPConnection instance (ftpClient), I do the following:
ftpClient.BytesTransferred += OnBytesTransferred;
ftpClient.DownloadStream(dataStream,FileName);
dataStream is a MemoryStream with capacity 10000.
FileName is a valid file name in the current working directory.
Size of file is 31.7 MB
there is a lock around ftpClient.BytesTransferred+=... and ftpClient.DownloadStream.
I have put a try-catch around it all.
No exceptions thrown, only hang.
Method listing:
protected override void ProcessFtpFileRequest(IFtpConnection ftpClient, FtpSession.ReportProgress progressReporter)
{
// Call base first.
base.ProcessFtpFileRequest(ftpClient, progressReporter);
try
{
var dataStream = WritableStream;
_fileSize = !SimpleMode ? ftpClient.GetSize(FileName) : 1024;
if (dataStream == null) return;
if (progressReporter != null)
progressReporter.Invoke(FileName, 0, 0);
lock (dataStream)
{
ProgressReporter = progressReporter;
var cwd = ftpClient.ServerDirectory;
ftpClient.BytesTransferred += OnBytesTransferred;
ftpClient.DownloadStream(dataStream, FileName);
}
}
catch (FTPException e)
{
DiagLog.ErrorFormat("{0} download error {1} ({2})", FileName, e.Message, e.ReplyCode);
FtpResult = e.ReplyCode == 550 ? FtpBackgroundWorkerResult.FileNotFound : FtpBackgroundWorkerResult.FileTransferFailed;
}
catch (IOException ioe)
{
DiagLog.ErrorFormat("{0} download IOException {1}", FileName, ioe.Message);
FtpResult = FtpBackgroundWorkerResult.FileTransferFailed;
}
finally
{
// Remember to remove event listner so FTP connection can be
// properly garbaged collected.
ftpClient.BytesTransferred -= OnBytesTransferred;
var res = FriendlyFtpResult(FtpResult);
DiagLog.DebugFormat("{0} {1} ({2} bytes)", string.IsNullOrEmpty(res) ? "Downloaded" : "Failed to download", FileName, _fileSize);
ProgressReporter = null;
}
}
ftpClient is of type IFtpConnection. The implementation of this interface inherits FTPConnection or SecureFTPConnection, and the interface will give access to all methods of FTPConnection or SecureFTPConnection as if they were directly addressed.
At least, that is my idea.