FtpWebRequest WebException: "Unable to connect to the remote server"

Owen Blacker picture Owen Blacker · Feb 5, 2013 · Viewed 7.1k times · Source

I have code in a Windows Service that successfully connects to an FTP server when I run it locally through a test harness (with the FTP server being on another machine on the local network).

When I install it in the production hosting environment, though, I get the dreaded WebException "Unable to connect to the remote server". It doesn't seem to matter whether I'm using ACTV or PASV FTP, all I get it this WebException. If I try to FTP from the Windows command line, however, it works perfectly well (so it's not the firewall at fault).

The code I'm using (adapted from How to List Directory Contents with FTP in C#?) reads:

private static readonly string __ftpSourceServer = "ftp://"
  + ConfigurationManager.AppSettings["FtpServer"] + "/";
private static readonly NetworkCredential __ftpCreds = new NetworkCredential(
  ConfigurationManager.AppSettings["Username"],
  ConfigurationManager.AppSettings["Password"]);

// And now the method MediaSyncDaemon.GetFilesToFetch:
bool usePassive = Boolean.TryParse(ConfigurationManager.AppSettings["UsePassive"]
  , out usePassive) && usePassive;

Uri ftpSrv = new Uri(__ftpSourceServer + Uri.EscapeUriString(
  ConfigurationManager.AppSettings["FtpPath"]));
Logger.Debug("Connecting to FTP server at " + ftpSrv + "; PASV? " + usePassive);

FtpWebRequest listRequest = (FtpWebRequest) WebRequest.Create(ftpSrv);
listRequest.Method = WebRequestMethods.Ftp.ListDirectory;
listRequest.Credentials = __ftpCreds;
listRequest.UsePassive = usePassive;
listRequest.UseBinary = false;

using (FtpWebResponse listResponse = (FtpWebResponse) listRequest.GetResponse())
{
    // ReSharper disable AssignNullToNotNullAttribute
    return new StreamReader(listResponse.GetResponseStream())
        .ReadToEnd().Split(new[] { '\n', '\r' },
            StringSplitOptions.RemoveEmptyEntries)
        .Where(s => s.EndsWith(".zip", true, CultureInfo.InvariantCulture))
        .ToList();
    // ReSharper restore AssignNullToNotNullAttribute
}

The exception is thrown at the FtpWebRequest.GetResponse() call in the using line (outside the return statement), with nothing else in the stack trace:

System.Net.WebException: Unable to connect to the remote server
   at System.Net.FtpWebRequest.GetResponse()
   at (that line number in that file)

The only real difference between my test harness (which works) and the production environment (which doesn't) is the presence of a firewall in the production environment — all four servers are on slightly different subnets:

Dev client    10.16.6.155     subnet 255.255.255.128
Dev server    10.16.7.242     subnet 255.255.255.0
Prod client   192.168.102.107 subnet 255.255.255.0
Prod server   192.168.203.110 subnet 255.255.255.0

but the firewall can't be the problem is I can FTP from Prod client to Prod server interactively, just not programmatically.

I've tried changing the bool appSettings value for UsePassive and that makes no difference and, in every case, nothing shows up in the FTP server log (so it's not getting that far).

Now I'm not expecting anyone to be able to debug the hardware infrastructure of my hosting environment, but I'm struggling to think of what else I could vary to get this to work. I've seen it work locally in my test harness, calling the same method. In case it helps, the test harness code reads as follows:

[NUnit.Framework.Test]
public void FtpFileListTest()
{
    ICollection<string> files = MediaSyncDaemon.GetFilesToFetch();
    Assert.IsNotNull(files);
    Assert.Greater(files.Count, 0);
}

Does anyone have any ideas of what else I could try, please?

Thanks!


Update

Having had some suggestions of places to look in the comments, I can update this a little further:

  1. The problem does not appear to be user permissions — the service is running in the context of the Local System account (which has more permissions than Administrator does)

  2. The problem does not appear to be code-access security. I've added a SocketPermission.Demand call to the entry method for this chunk of code:

    System.Security.CodeAccessPermission socketPermission;
    socketPermission = new SocketPermission(NetworkAccess.Connect,
      TransportType.Tcp, ConfigurationManager.AppSettings["FtpServer"], 20);
    socketPermission.Demand();
    socketPermission = new SocketPermission(NetworkAccess.Connect,
      TransportType.Tcp, ConfigurationManager.AppSettings["FtpServer"], 21);
    socketPermission.Demand();
    

    And I'm not seeing any SecurityException being thrown as a result; I'm still getting the same WebException, at the new line number for that same code position.

Does anyone have any further suggestions of what I could try?

Answer

Bluesm picture Bluesm · Aug 1, 2019

I would like to share our problem and solution: We were not able to connect to the FTP server with ftpwebrequest on a corporative PC, but on ours it would work fine. The issue was that ftpwebrequest() was grabbing the proxy configuration that the company’s IT forces on the PC. To resolve this issue, we added (ftpwebrequest object).proxy = null; before connecting.