简体   繁体   English

尝试上传到FTP:System.Net.WebException:系统错误

[英]Attempting to upload to FTP: System.Net.WebException: System error

I have an API that takes in XML and ultimately uploads files based on information in the XML. 我有一个接受XML的API,并最终根据XML中的信息上传文件。 The uploads are on a schedule (also from XML), and I have tested everything surrounding it and know it works. 上传是按计划进行的(也来自XML),我已经测试了周围的所有内容,并且知道它可以工作。

I am getting an error about 40% of the time on the first file that I attempt to upload in each time cycle (time cycle = 45 minutes for some files, 30 minutes for others). 在每个时间周期内尝试上载的第一个文件时,大约40%的时间出现错误(某些文件的时间周期= 45分钟,其他文件的时间周期= 30分钟)。

Here is my code for the upload: 这是我上传的代码:

try {
    LoggerFTP.Log("Uploading file: " + filename, false);

    // Create the request.
    FtpWebRequest request = (FtpWebRequest)WebRequest.Create(appSettingsFTP.ftpUrl + @"/" + filename);
    request.Method = WebRequestMethods.Ftp.UploadFile;
    request.Timeout = 6000000; //set to 100 minutes
    //request.Timeout = -1; //set to infinite

    // Add the login credentials.
    request.Credentials = new NetworkCredential(appSettingsFTP.ftpLogin, appSettingsFTP.ftpPassword);

    // Grab the file contents.
    StreamReader sourceStream = new StreamReader(appSettingsFTP.uploadFileDirectory + filename);
    byte[] fileContents = Encoding.UTF8.GetBytes(sourceStream.ReadToEnd());
    sourceStream.Close();
    request.ContentLength = fileContents.Length;

    // Copy the file contents to the outgoing stream.
    Stream requestStream = request.GetRequestStream();
    requestStream.Write(fileContents, 0, fileContents.Length);
    requestStream.Close();

    FtpWebResponse response = (FtpWebResponse)request.GetResponse();
    //Logger.Log(filename.ToString() + " " + "Upload Complete, Status: " + response.StatusCode + " " + response.StatusDescription, false);
    //Took response.StatusDescription out because it appears to be creating extra line feeds.
    LoggerFTP.Log(filename.ToString() + " " + "Upload Complete, Status: " + response.StatusCode, false);
}
catch (Exception ex) {
    LoggerFTP.Log(ex.ToString(), false);
}

I have researched the issue and saw something online about it potentially being a speed thing. 我已经研究了这个问题,并在网上看到了一些可能是速度问题的信息。 Like, there is a timeout. 就像有一个超时。 But I have my timeout set to 100 minutes for my FtpWebRequest, so it can't possibly be that? 但是我将FtpWebRequest的超时设置为100分钟,所以可能不是吗? I don't know. 我不知道。 This is also running as a service so it is hard to test this aspect of the code. 它也作为服务运行,因此很难测试代码的这一方面。

Here is the exception that is getting logged in my logger (e.ToString): 这是我的记录器(e.ToString)中记录的异常:

System.Net.WebException: System error. ---> System.Net.InternalException: System error.
   at System.Net.PooledStream.PrePush(Object expectedOwner)
   at System.Net.ConnectionPool.PutConnection(PooledStream pooledStream, Object owningObject, Int32 creationTimeout, Boolean canReuse)
   at System.Net.FtpWebRequest.FinishRequestStage(RequestStage stage)
   at System.Net.FtpWebRequest.SyncRequestCallback(Object obj)
   at System.Net.FtpWebRequest.RequestCallback(Object obj)
   at System.Net.CommandStream.Dispose(Boolean disposing)
   at System.IO.Stream.Close()
   at System.IO.Stream.Dispose()
   at System.Net.ConnectionPool.Destroy(PooledStream pooledStream)
   at System.Net.ConnectionPool.PutConnection(PooledStream pooledStream, Object owningObject, Int32 creationTimeout, Boolean canReuse)
   at System.Net.FtpWebRequest.AttemptedRecovery(Exception e)
   at System.Net.FtpWebRequest.SubmitRequest(Boolean async)
   --- End of inner exception stack trace ---
   at System.Net.FtpWebRequest.GetRequestStream()
   at CPMainSpringAPIExportsSC.UploadFTP.FTPUploadMethod(String viewname, String filename)

I am getting exactly the same stack trace in an SSIS package attempting to FTP over SSL. 我在尝试通过SSL进行FTP的SSIS包中得到了完全相同的堆栈跟踪。 It works great without SSL, but as soon as I enable SSL, it blows up. 如果没有SSL,它会很好用,但是一旦启用SSL,它就会崩溃。

    System.Net.WebException: System error. --->
    System.Net.InternalException: System error.    at
    System.Net.PooledStream.PrePush(Object expectedOwner)    at
    System.Net.ConnectionPool.PutConnection(PooledStream pooledStream, Object owningObject, Int32 creationTimeout, Boolean canReuse)    at
    System.Net.FtpWebRequest.FinishRequestStage(RequestStage stage)    at
    System.Net.FtpWebRequest.SyncRequestCallback(Object obj)    at
    System.IO.Stream.Close()    at
    System.Net.ConnectionPool.Destroy(PooledStream pooledStream)    at
    System.Net.ConnectionPool.PutConnection(PooledStream pooledStream, Object owningObject, Int32 creationTimeout, Boolean canReuse)    at
    System.Net.FtpWebRequest.AttemptedRecovery(Exception e)    at
    System.Net.FtpWebRequest.SubmitRequest(Boolean async)
    --- End of inner exception stack trace ---    at
    System.Net.FtpWebRequest.CheckError()    at
    System.Net.FtpWebRequest.GetRequestStream()    at
    ST_0ff7348de65a468bb358ab0206e3721f.ScriptMain.Main() in c:\Users\Stephens\AppData\Local\Temp\Vsta\e664c8a71bb647ff9e9dc6ac32d7b615\ScriptMain.cs:line 155 at 
    System.Net.FtpWebRequest.CheckError()    at
    System.Net.FtpWebRequest.GetRequestStream()    at
    ST_0ff7348de65a468bb358ab0206e3721f.ScriptMain.Main() in c:\Users\Stephens\AppData\Local\Temp\Vsta\e664c8a71bb647ff9e9dc6ac32d7b615\ScriptMain.cs:line 155

Because the error is so generic, I decided to look at the .NET source to see if I can catch a clue about what is breaking. 由于该错误是如此普遍,因此我决定查看.NET源代码,以了解是否可以了解中断的线索。 If you go here: 如果您去这里:

http://labs.developerfusion.co.uk/SourceViewer/browse.aspx?assembly=SSCLI&namespace=System.Net#{%22pageClientState%22%3A%22type-2844%2Ccsharp%22} http://labs.developerfusion.co.uk/SourceViewer/browse.aspx?assembly=SSCLI&namespace=System.Net#{%22pageClientState%22%3A%22type-2844%2Ccsharp%22}

and skip down to line 281, you will see the definition for internal void PrePush(object expectedOwner) which is what is executing when the exception happens. 并跳至第281行,您将看到内部void PrePush(object ExpectedOwner)的定义,该定义在发生异常时正在执行。 Here is what it looks like: 看起来像这样:

    internal void PrePush(object expectedOwner)
    {
        lock (this) {
            //3 // The following tests are retail assertions of things we can't allow to happen.
            if (null == expectedOwner) {
                if (null != m_Owner && null != m_Owner.Target)
                    throw new InternalException();
                // new unpooled object has an owner
            }
            else {
                if (null == m_Owner || m_Owner.Target != expectedOwner)
                    throw new InternalException();
                // unpooled object has incorrect owner
            }

            m_PooledCount++;

            if (1 != m_PooledCount)
                throw new InternalException();
            // pushing object onto stack a second time
            if (null != m_Owner)
                m_Owner.Target = null;
        }
    }

Eventually I discovered that FtpWebRequest only supports explicit FTP (port 21) and not implicit FTP (port 990). 最终,我发现FtpWebRequest仅支持显式FTP(端口21),而不支持隐式FTP(端口990)。 This was definitively stated here: 明确地在这里指出:

Does .NET FtpWebRequest Support both Implicit (FTPS) and explicit (FTPES)? .NET FtpWebRequest是否支持隐式(FTPS)和显式(FTPES)?

Anyway, in my case, it was a firewall issue. 无论如何,就我而言,这是一个防火墙问题。 Originally we configured for implicit FTP, which was ports 989, 990, 49152-65535 (per the vendor's tech staff). 最初,我们为隐式FTP配置了端口989、990、49152-65535(根据供应商的技术人员)。 I checked with my network guy and we opened up ports 20, 21, 989, 990 and 40000-655535 for explicit and things worked like a champ afterwards. 我检查了我的网络人员,并打开了端口20、21、989、990和40000-655535,明确了这些内容,然后事情就如冠军一般了。

However, in your case, you appear to have some connection pool excitement going on. 但是,就您而言,似乎似乎有些连接池令人兴奋。 There is a good post on this subject here: 这里有关于这个主题的好文章:

How to improve the Performance of FtpWebRequest? 如何提高FtpWebRequest的性能?

You might want to take a look at mucking around with your connection pool set up and see if you can make some progress. 您可能想看看设置连接池的过程,看看是否可以取得一些进展。 Hope this helps! 希望这可以帮助!

Regards, 问候,

Stuart 斯图尔特

我知道这是一个老话题,但是对于任何有相同问题的人,缺少的代码是:

            request.EnableSsl = false;

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM