Thursday, July 28, 2016

AX 2009/2012 FTP operations

Here is a class that I wrote to perform operations via FTP file transfer

There is an interface to:
  • Upload a file
  • Upload text as a file
  • Rename file
  • Delete file
  • Get a list of files from an FTP server
  • Download file
The class is tested to work on the client and on the server (batch)

Everything is based on the .NET class FtpWebRequest




HOW TO USE


Lud_FtpClient ftpClient = Lud_FtpClient::construct("FTP URL", "user", "pwd");
;
ftpClient.uploadText("text you want to upload", "FC/test.txt");

ftpClient.uploadFile(@"c:\IFRToolLog.txt", "FC/IFRToolLog.txt");

ftpClient.getFileList("", "xml");

ftpClient.downloadFile("/assets/ISB_PAGE 36.pdf", @"\\192.168.100.44\temp\test.pdf");

ftpClient.deleteFile("/images.jpg");

Code sample:

void downloadFile(str fileUrl, str destination)
{
    System.Object               ftpo;
    System.Object               ftpResponse;
    System.Net.FtpWebRequest    request;
    System.IO.Stream            responseStream;
    System.IO.StreamReader      reader;
    System.IO.FileStream        writeStream;

    System.String               xmlContent;
    System.Net.FtpWebResponse   response;

    System.Byte[]               buffer;
    int                         bufferLenght = 2048;
    int                         bytesRead;
    ;

    new InteropPermission(InteropKind::ClrInterop).assert();

    try
    {
        ftpo = System.Net.WebRequest::Create("ftp://" + ftpUrl + (strEndsWith(ftpUrl, "/") ? fileUrl : "/" + fileUrl));
        request = ftpo;

        // se vengono fatte chiamate consecutive ricreando sempre le credential ogni tanto va in errore (Bad request)
        // per evitare il problema keepAlive = false, ma così va più lento. Con questo hack se la classe non viene ricreata
        // ogni volta dovrebbe andare meglio
        if(!credential)
        {
            credential = new System.Net.NetworkCredential(username, password);
            request.set_Credentials(credential);
            request.set_KeepAlive(false);
        }
        else
        {
            request.set_Credentials(credential);
            request.set_KeepAlive(true);
        }

        request.set_Method("RETR");
        // "Bypass" a HTTP Proxy (FTP transfer through a proxy causes an exception)
        request.set_Proxy( System.Net.GlobalProxySelection::GetEmptyWebProxy() );
        ftpResponse = request.GetResponse();
        response = ftpResponse;
        responseStream = response.GetResponseStream();

        buffer = new System.Byte[bufferLenght]();
        writeStream = new System.IO.FileStream(destination, System.IO.FileMode::Create);
        bytesRead = responseStream.Read(buffer, 0, bufferLenght);

        while (bytesRead > 0)
        {
            writeStream.Write(buffer, 0, bytesRead);
            bytesRead = responseStream.Read(buffer, 0, bufferLenght);
        }
        writeStream.Close();

        response.Close();

    }
    catch(Exception::CLRError)
    {
        throw error(this.getClrErrorMessage());
    }

    CodeAccessPermission::revertAssert();
}

4 comments:

Unknown said...

Hello Ludo, have you tried webrequest in batch mode in AX? If you have, can you share it to me? I have tried to do the webrequest in batch mode in AX2009 but experienced error about the method is needed to run in client mode.

Ludovico Mattiuzzo said...

Yes, I regularly use this in batch mode. Where do you get this error?

Unknown said...

I got the error in batch mode, the error message is The server-side impersonated (RunAs) session tried to invoke a method that is available for client-side processing only. I think maybe System.Net.WebRequest cannot be executed in batch mode.

Trinh said...

Thanks a lot Ludo. You saved my life :)