Fixing - System.Net.WebException: The remote serve

2019-02-13 15:22发布

问题:

I created FTP code to transfer files. This code works fine except that it sometimes causes an error 500. The exact error is -

Error: System.Reflection.TargetInvocationException: Exception has 
been thrown by the target of an invocation. 
---> System.Net.WebException: The remote server returned an error: 
(500) Syntax error, command unrecognized.
   at System.Net.FtpWebRequest.CheckError()
   at System.Net.FtpWebRequest.SyncRequestCallback(Object obj)
   at System.Net.CommandStream.Abort(Exception e)
   at System.Net.FtpWebRequest.FinishRequestStage(RequestStage stage)
   at System.Net.FtpWebRequest.GetRequestStream()
   at ST_772dn22cj49ndfddatee.csproj.ScriptMain.Main()
   --- End of inner exception stack trace --- 

I noticed that the error occurs when the biggest file is loaded, ie about 290 KB. All other files are less than this and i get no exception for them. I don't know why this happens. Can someone tell me why ?

As an aside, in case you notice some room for improvement in my code or logical error, then please mention that as well. I am not really looking for code reviews, but its welcome.

public void Main()
{

    Boolean conditions = true;

    if(conditions == true)
    {
    string fileLocation = "my windows directory";
    string fileName = "fileName.extension";

    string ftpFolder = @"/ftpFolder/";
    Boolean ftpMode = true; //passive or active. True = passive 
    string ftpPassword = "password";
    int ftpPort = 21;// the default
    string ftpServerName = "server name";
    string ftpUserName = "user name";

    //Create an object to communicate with the server.
    string ftpRequestString = "ftp://" + ftpServerName + ":" 
    + ftpPort + ftpFolder + fileName; 

    try{

    FtpWebRequest request = 
    (FtpWebRequest)WebRequest.Create(ftpRequestString);
    request.Method = WebRequestMethods.Ftp.UploadFile;

    request.Credentials = new NetworkCredential(ftpUserName, ftpPassword);

    //Set mode
    if(ftpMode == true){
        request.UsePassive = true;
    }

    //Copy the file to the request.

    string filePath = @fileLocation + "\\" + fileName;
    StreamReader sourceStream = new StreamReader(filePath);
    byte[] fileContents = Encoding.UTF8.GetBytes(sourceStream.ReadToEnd());
    sourceStream.Close();
    request.ContentLength = fileContents.Length;

    Stream requestStream = request.GetRequestStream();
    requestStream.Write(fileContents, 0, fileContents.Length);
    requestStream.Close();

    FtpWebResponse response = (FtpWebResponse)request.GetResponse();

    response.Close();

    }
     catch (WebException ex)
     {
        MessageBox.Show(ex.Message);

     }//try-catch

    }

}//main

回答1:

On reading your question I was suspicious this has to do with (or could be corrected by) setting the KeepAlive to false. Looking on SO - this question references the same problem and points to it as well: https://stackoverflow.com/a/2071374/1803682

Try setting:

request.KeepAlive = false;

With KeepAlive set to false your connection will be closed at the end of each request. If you are transmitting a lot of files this could be an issue - as it takes time to resend credentials, etc. The upside is you recreate the connection in a known / initial state which should solve your problem (even if it is not the root cause).

To see what is going on, if you can enable detailed logging on your server you should see the last command issued before seeing this error returned. This should give you a better idea of what is up. Found this thread saying much the same thing.

Update:

If I had read to the bottom of the link I posted myself I could have answered even better, the command probably being reissued is some part of the login process (i.e. USER username) and this is your likely issue:

The reason the creadentials may no longer be valid is that the WebRequest uses a lease that expires after a certain amount of time. If you don't explicitly instantiate the lease and define its timeouts, the FtpWebRequest appears to use default timeout values. I believe what's happening is that when the lease expires the FtpWebRequest will then try to log on again.

So looking here with the right search:

yields that the default timeout waiting for requests is not infinite as specified but actually 10000 ms. Which seems a pretty big discrepancy. So you can also try setting:

request.Timeout = -1;

And see if it corrects your error.


Really don't think this could be your issue so moving it to the bottom:

Also - check that your request.ReadWriteTimeout is appropriate for the speed you see for the larger file. The default is 5 minutes which would be pretty long for 290k, so I expect this is not the source of your error. Also - I would expect a connection closed error if this was the problem.



回答2:

I too encountered the same exception with FTPWebRequest within a custom MSBuild task... luckily the task exposed a setting UsePassive="false" (which sets the UsePassive property on the FTPWebRequest object). Changing the value to "true" fixed the problem. Hope this helps!

  • (Set UsePassive to) false if the client application's data transfer process listens for a connection on the data port; otherwise, true if the client should initiate a connection on the data port. The default value is true.
  • Setting the UsePassive property to true sends the "PASV" command to the server. This command requests the server to listen on a data port and to wait for a connection rather than initiate one upon receipt of a transfer command.
  • If UsePassive is set to true, the FTP server may not send the size of the file, and download progress can always be zero. If UsePassive is set to false, a firewall can raise an alert and block the file download.


回答3:

For any one else that has this issue and the above does not seem to work, I found that when I hit the above error, it was to do with my Username or password. I am sure there are quite a few people who copy and paste from Excel into SQL, so because of this, SQL picked up that my username/password had a carriage return line feed(When you push enter).

My code actually picked up the username as "Myusername & vbcrlf".

Hope this helps someone, if they have the same problem.

Cheers!