Interrupted FtpWebRequest upload stream

  • Thread starter Thread starter Guest
  • Start date Start date
G

Guest

VS 2005 Team Dev. SP1

When an upload using ftpWebRequest fails because of a lost connection, I
want to be able to use GetSize and then reposition the source file stream and
try again where it left off using the "Append" this time.

The problem is the crazy connection is left open to the FTP server even
though KeepAlive is false, until about 4 minutes later when it times out. I
verified that the connection is open with the FTP server. Until the
connection is closed, the partial file doesn't show up on the destination
server. How can you either force the connection to close or force the
partial file to show up on the destination server? If I terminate the app
instead of continuing on with the retry, the connection is closed.

Thanks,
Dean
 
Hi Dean,

Have you tried to call FtpWebRequest.GetRequestStream().Close when the
connection was lost?


Sincerely,
Walter Wang ([email protected], remove 'online.')
Microsoft Online Community Support

==================================================
Get notification to my posts through email? Please refer to
http://msdn.microsoft.com/subscriptions/managednewsgroups/default.aspx#notif
ications. If you are using Outlook Express, please make sure you clear the
check box "Tools/Options/Read: Get 300 headers at a time" to see your reply
promptly.

Note: The MSDN Managed Newsgroup support offering is for non-urgent issues
where an initial response from the community or a Microsoft Support
Engineer within 1 business day is acceptable. Please note that each follow
up response may take approximately 2 business days as the support
professional working with you may need further investigation to reach the
most efficient resolution. The offering is not appropriate for situations
that require urgent, real-time or phone-based interactions or complex
project analysis and dump analysis issues. Issues of this nature are best
handled working with a dedicated Microsoft Support Engineer by contacting
Microsoft Customer Support Services (CSS) at
http://msdn.microsoft.com/subscriptions/support/default.aspx.
==================================================

This posting is provided "AS IS" with no warranties, and confers no rights.
 
Calling GetRequestStream().Close after a lost connection gives the following
error:

Cannot re-call BeginGetRequestStream/BeginGetResponse while a previous call
is still in progress.


Here's my code:

while (attempts < 5)

try
{
// create ftpWebRequest object here

byte[] fileContents;

using (FileStream sourceStream = new FileStream("C:\myfile.exe",
FileMode.Open, FileAccess.Read))
{
int bytesRead;
fileContents = new byte[sourceStream.Length];

do
{
bytesRead = sourceStream.Read(fileContents, 0, 4096);
}
while (bytesRead != 0);
}

using (Stream ftpStream = request.GetRequestStream())
{
ftpStream.Write(fileContents, 0, fileContents.Length);
ftpStream.Close(); // <----- causes the upload to take place
}

using (FtpWebResponse response = (FtpWebResponse) request.GetResponse())
{
if ((int)response.StatusCode == 226 || (int)response.StatusCode ==
227)
{
response.Close();
return true; // 226 and 227 means success
}
else
errorMessage = response.StatusDescription;

response.Close();
return false;
}
}
catch (Exception e)
{
++attempts;

// I want to close or kill the old connection here.
// What happens: when an exception occurrs because
// of a lost connection, the current request gets in
// a bad state and can't be controlled. It will die
// after the destination server times it out.

continue; // retry
}
} // end while

Walter,
I've tried the MaxIdleTime and ConnectionLeaseTimeout ServicePoint
properties but they didn't help.

If you don't know how to handle a hung request object, please help me get an
answer from someone who does.

I tried ignoring the old connection by just creating a new connection and
then re-trying. If the new attempt succeeds, the file is successfully on the
destination server. But because the old hung connection is still alive at
the destination server, when it times out, the FTP server takes that partial
(failed) file (doing a dir on the server shows the bad file is there and has
a temporary name) and overwrites the new good complete file I just uploaded.

Having that old hung request out there will keep you from correcting a
failed upload until the hung connection is closed.

- Dean
 
Hi Dean,

I have done some test on my side and I think the server is really
responsible to release the connection, there's really not much we can do
from the client side.

Here's my test configuration/steps:

1) I downloaded a ftp server Serv-U from http://www.serv-u.com and
installed on system B, to ease test, I enabled anonymous user to read/write
files on the ftp server

2) On my system A, I created following test program:

============

using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Net;
using System.Threading;

namespace ConsoleApplication3
{
class Program
{
static void Main(string[] args)
{
UploadFile(@"f:\test.exe", "ftp://serverB/test.exe", 5000);
Console.WriteLine("Press ENTER");
Console.ReadLine();
}

static bool IsFtpFileExists(string remoteUri, out long remFileSize)
{
FtpWebRequest request =
(FtpWebRequest)WebRequest.Create(remoteUri);
FtpWebResponse response;

request.Method = WebRequestMethods.Ftp.GetFileSize;
try
{
response = (FtpWebResponse)request.GetResponse();
remFileSize = response.ContentLength;
return true;
}
catch (WebException we)
{
response = we.Response as FtpWebResponse;
if (response != null && response.StatusCode ==
FtpStatusCode.ActionNotTakenFileUnavailable)
{
remFileSize = 0;
return false;
}
throw;
}
}

static void UploadFile(string localFile, string remoteUri, int
attempts)
{
FileInfo fi = new FileInfo(localFile);
long remFileSize = 0;
FtpWebRequest request = null;
while (--attempts >= 0)
{
try
{
request = (FtpWebRequest)WebRequest.Create(new
Uri(remoteUri));
request.Timeout = 3000;
if (IsFtpFileExists(remoteUri, out remFileSize))
{
Console.WriteLine("File already exists, RESUME");
request.Method = WebRequestMethods.Ftp.AppendFile;
}
else
{
Console.WriteLine("File not already exists,
UPLOAD");
request.Method = WebRequestMethods.Ftp.UploadFile;
}
request.ContentLength = fi.Length - remFileSize;
request.UsePassive = false;

using (Stream requestStream =
request.GetRequestStream())
{
using (FileStream fs = File.Open(localFile,
FileMode.Open))
{
fs.Seek(remFileSize, SeekOrigin.Begin);
const int BUFFER_SIZE = 8192;
byte[] buffer = new byte[BUFFER_SIZE];
int readBytes = 0;
do
{
readBytes = fs.Read(buffer, 0, BUFFER_SIZE);
requestStream.Write(buffer, 0, readBytes);
System.Threading.Thread.Sleep(500);
} while (readBytes != 0);
}
}
Console.WriteLine("Done");
using (FtpWebResponse response =
(FtpWebResponse)request.GetResponse())
{
Console.WriteLine(response.StatusCode);
}
break;
}
catch (WebException we)
{
Console.WriteLine(we.Message);
Thread.Sleep(500);
}
}
}
}
}


============

3) Run this test program, it will start upload file f:\test.exe to the ftp
server; while it's transfering, disable the network connection "Local Area
Connection" to simulate a connection broken error; and re-enable it again
after some time. From the ftp server, serv-u administrator shows there's a
connection keeps open.

4) Terminate the test program, the connection still opens on the server.

5) Now use another ftp client to test this behavior, you will find the
connection is also kept open on the ftp server. Also, in this case, serv-U
actually don't use temporary file, therefore you can see the target file
exists but while the orphan connection keeps open, you cannot delete or
overwrite file -- it's locked by the thread receiving the file on the ftp
server.

Since using a commercial ftp client also shows behavior, I think we really
cannot do much from client-side. It's totally controlled by the ftp server,
the server decides when to times out and dropps the orphan connection.


Regards,
Walter Wang ([email protected], remove 'online.')
Microsoft Online Community Support

==================================================
When responding to posts, please "Reply to Group" via your newsreader so
that others may learn and benefit from your issue.
==================================================

This posting is provided "AS IS" with no warranties, and confers no rights.
 
Hi Dean,

In my last reply to your post, I described my research result and it seems
the orphan connection to the ftp server is really up to the server to close
it in some circumstances. After the connection is the broken, the previous
FtpWebRequest and its related stream objects are in an inconsistent state
and will not be able to recover correctly. At this stage, only the server
could decide when to drop the broken connection.

Please feel free to let me know if you have any concerns or anything
unclear, thanks.

Best regards,
Walter Wang
MSDN Managed Newsgroup Support
 
Dean, I know it's been a while, but I'm seeing the exact same behavior and I also get the "Cannot re-call BeginGetRequestStream/BeginGetResponse" error when I try the retry.

Any help in pointing me in the right direction would be appreciated.

Trent
 
Back
Top