Search code examples
c#.netftpmainframeftpwebrequest

Use C# to FTP file to mainframe including dataset - Translate FTP script to FtpWebRequest code


I use a cmd (Windows) to send file to an IBM Mainframe and works fine it's something like this:

Open abc.wyx.state.aa.bb
User
Pass
lcd c:\Transfer>
Put examplefile 'ABCD.AA.C58FC.ABC1FD.ZP3ABC'
close
bye

I need to convert this to C#. I have been trying using FtpWebRequest but no luck. I cannot figure out how include the dataset I guess. When I run the application I got the following error:

((System.Exception)(ex)).Message "The remote server returned an error: (550) File unavailable (e.g., file not found, no access)." 550 Unable to store The remote server returned an error: (550) File unavailable (e.g., file not found, no access).

((FtpWebResponse)ex.Response).StatusDescription "550 Unable to store /'ABCD.AA.C58FC.ABC1FD.ZP3ABC/examplefile'\r\n"

Here is what I got in C#

string user = "user";
string pwd = "password";

string ftpfullpath = @"ftp://abc.wyx.state.aa.bb//'ABCD.AA.C58FC.ABC1FD.ZP3ABC'/examplefile'";

try
{
     FtpWebRequest ftp = (FtpWebRequest)FtpWebRequest.Create(ftpfullpath);
     ftp.Credentials = new NetworkCredential(user, pwd);

     ftp.KeepAlive = true;
     ftp.UseBinary = false;  //Use ascii.              

     ftp.Method = WebRequestMethods.Ftp.UploadFile;

     FileStream fs = File.OpenRead(inputfilepath);
     byte[] buffer = new byte[fs.Length];
     fs.Read(buffer, 0, buffer.Length);
     fs.Close();

     Stream ftpstream = ftp.GetRequestStream();
     ftpstream.Write(buffer, 0, buffer.Length);
     ftpstream.Close();
}
catch (WebException ex)
{
     String status = ((FtpWebResponse)ex.Response).StatusDescription;
     throw new Exception(status);
}

Solution

  • You didn't specify what platform you run the ftp script at. I assume Windows.

    When you use Windows ftp command put like:

    put localpath remotepath
    

    it results in following call on the FTP server:

    STOR remotefile
    

    Similarly if you use FtpWebRequest with an URL like

    ftp://example.com/remotepath
    

    is results in following (same) call on the FTP server:

    STORE remotepath
    

    Note that the first slash after hostname (example.com) is omitted.


    This means that your ftp script commands:

    Open abc.wyx.state.aa.bb
    ...
    Put examplefile 'ABCD.AA.C5879.ABC123.123ABC'
    

    translate to FtpWebRequest URL like:

    string ftpfullpath = @"ftp://abc.wyx.state.aa.bb/'ABCD.AA.C5879.ABC123.123ABC'";
    

    Both result in this call on the FTP server:

    STOR 'ABCD.AA.C5879.ABC123.123ABC'
    

    Contrary, your ftp code with

    string ftpfullpath = @"ftp://abc.wyx.state.aa.bb//'ABCD.AA.C5879.ABC123.123ABC'/examplefile'";
    

    results in:

    STOR /'ABCD.AA.C5879.ABC123.123ABC'/examplefile'
    

    It does not look correct for mainframe.


    Transcript of a session by my C# code:

    USER user
    331 Password required for user
    PASS password
    230 Logged on
    OPTS utf8 on
    200 UTF8 mode enabled
    PWD
    257 "/" is current directory.
    TYPE A
    200 Type set to A
    PASV
    227 Entering Passive Mode (zzz,zzz,zzz,zzz,193,162)
    STOR 'ABCD.AA.C5879.ABC123.123ABC'
    150 Connection accepted
    226 Transfer OK
    

    Transcript of the session by my ftp script:

    USER user
    331 Password required for user
    PASS password
    230 Logged on
    PORT zzz,zzz,zzz,zzz,193,186
    200 Port command successful
    STOR 'ABCD.AA.C5879.ABC123.123ABC'
    150 Opening data channel for file transfer.
    226 Transfer OK
    QUIT
    221 Goodbye
    

    I've tested this against FileZilla FTP server, so obviously the FTP server responses will differ on the mainframe FTP. But the FTP commands from the client should be the same.