Hi
We're using FTPWebRequest to upload a file, and we're seeing an exception:
System.ArgumentOutOfRangeException: Number must be either non-negative and less than or equal to Int32.MaxValue or -1.
Parameter name: millisecondsTimeout
at System.Threading.WaitHandle.WaitOne(Int32 millisecondsTimeout, Boolean exitContext)
at System.Net.ConnectionPool.PutConnection(PooledStream pooledStream, Object owningObject, Int32 creationTimeout)
at System.Net.FtpWebRequest.FinishRequestStage(RequestStage stage)
at System.Net.FtpWebRequest.GetRequestStream()
at FTPManager.TryUploadFile(String url, String local) in C:\xxx\FTPManager.cs:line 159
The TryUploadFile method is:
protected bool TryUploadFile(string url, string local)
{
FtpWebRequest ftp = (FtpWebRequest)WebRequest.Create(url);
ftp.Credentials = new NetworkCredential(Properties.Settings.Default.FtpUser, Properties.Settings.Default.FtpPassword);
ftp.Method = WebRequestMethods.Ftp.UploadFile;
ftp.UseBinary = true;
ftp.UsePassive = Properties.Settings.Default.FtpPassive;
ftp.KeepAlive = false;
ftp.Timeout = 1000; // 1 sec
try
{
using (FileStream fs = File.OpenRead(local))
{
using (Stream rs = ftp.GetRequestStream()) /////// line 159 ///////
{
byte[] buf = new byte[1024];
int i;
while ((i = fs.Read(buf, 0, buf.Length)) > 0)
rs.Write(buf, 0, i);
}
}
FtpWebResponse resp = (FtpWebResponse)ftp.GetResponse();
resp.Close();
return true;
}
catch (WebException ex)
{
return false;
}
}
Using Reflector to look at the System.Net code narrows down the PutConnection call (that appears in the stack trace) to here in FinishRequestStage:
if (((stage == RequestStage.ReleaseConnection) || (requestStage == RequestStage.ReleaseConnection)) && (connection != null))
{
try
{
if (this.m_Exception != null)
{
connection.Abort(this.m_Exception);
}
else if (this.m_FtpWebResponse.IsFromCache && !this.KeepAlive)
{
connection.Quit();
}
}
finally
{
if (Logging.On)
{
Logging.PrintInfo(Logging.Web, this, "", SR.GetString("net_log_releasing_connection", new object[] { ValidationHelper.HashString(connection) }));
}
this.m_ConnectionPool.PutConnection(connection, this, this.RemainingTimeout); /////// here ///////
if (this.m_Async && (this.m_RequestCompleteAsyncResult != null))
{
this.m_RequestCompleteAsyncResult.InvokeCallback();
}
}
}
I think the problem is that this can be executed when the connection is being released as the result of a WebException timeout exception. The WebException is stored by SetException and thrown later by CheckError, and this processing is happening in between. When there has been a timeout, RemainingTimeout is negative, hence the final error.
Of course, there is some network issue that causes the timeout in the first place, but I'm catching the WebException for just that purpose.
Any thoughts welcome
David