jueves, 1 de septiembre de 2011

The FtpWebRequest class

Requirement: The client needs us to send two files via FTP during the process of synchronizing the General Ledger between Axapta and their own propriatary system.

Once more axaptapedia.com saves the day. This time pointing us to the FtpWebRequest class in the .NET framework inside Dynamics AX. The Axaptapedia page is complete except for one wafer-thin omission... Exception handling.

Let me save your time and eyes and tell you now that it is of the type Exception::CLRError, and I've also converted the Job to a server static function, below and added the necessary permissions. Here comes the science if you wish to continue:

/// http://www.axaptapedia.com/FtpWebRequest
/// Params:
/// _inputFile:         "C:/tmpServer/test.xml"
/// _destinationFile:   "ftp://123.234.34.45/BD01/test.xml"
/// _user:              "user"
/// _password:          "pass"
/// _useProxy:          false
public client server static str uploadFileFTP(str _inputFile,     str _destinationFile,
                                str _user,          str _password,
                                boolean _useProxy = false)
{
    str                         retVal;
    object                      ftpo;
    object                      ftpResponse;

    InteropPermission           permI         = new InteropPermission(InteropKind::ClrInterop);
    FileIOPermission            permIO        = new FileIOPermission(_inputFile,'r');
    Set                         permissionSet = new Set(Types::Class);

    System.Net.FtpWebRequest    request;
    System.IO.StreamReader      reader;
    System.IO.Stream            requestStream;
    System.Byte[]               bytes;
    System.Net.NetworkCredential credential;
    System.String               xmlContent;
    System.Text.Encoding        utf8;

    System.Net.FtpWebResponse   response;

    System.Exception            netExcepn;
    ;

    try
    {
        // Permissions
        permissionSet.add(permI);
        permissionSet.add(permIO);
        CodeAccessPermission::assertMultiple(permissionSet);

        // Read file
        reader  = new System.IO.StreamReader(_inputFile);
        utf8    = System.Text.Encoding::get_UTF8();
        bytes   = utf8.GetBytes( reader.ReadToEnd() );
        reader.Close();

        // little workaround to get around the casting in .NET
        ftpo    = System.Net.WebRequest::Create(_destinationFile);
        request = ftpo;

        credential = new System.Net.NetworkCredential(_user, _password);
        request.set_Credentials(credential);
        request.set_ContentLength(bytes.get_Length());
        request.set_Method("STOR");

        if (_useProxy)
        {   // "Bypass" a HTTP Proxy (FTP transfer through a proxy causes an exception)
            request.set_Proxy( System.Net.GlobalProxySelection::GetEmptyWebProxy() );
        }

        requestStream = request.GetRequestStream();
        requestStream.Write(bytes,0,bytes.get_Length());
        requestStream.Close();

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

    }
    catch (Exception::CLRError)
    {
        netExcepn = CLRInterop::getLastException();
        error(netExcepn.ToString());
    }
    catch
    {   // Error desconocido / Unknown error
        error("@SYS83461");
    }

    if (response)
    {
        // info(response.get_StatusDescription());
        retVal = response.get_StatusDescription();
    }
    return retVal;
}
A few of my own recommendations

  • As a stinky consultant that works on the client site, in a bank, wearing a tie that sends you screaming out of the door, I have very limited rights to my machine and I can't install services. I can therefore recommend WarFTP as a standalone executable FTP Server for all of your testing needs. Out of the box it comes as pretty locked down so read the faq when you can't work out why the new user you just created can't use the service.
  • Execute on the server. Not only is it going to be faster generating our export file from the General Ledger but we'll have only one source of problems instead of the 'n' client machines out there each with their own firewall or McAfee Fascist settings.
  • Use the following snippet to obtain the executing computer's temporary directory: (isRunningOnServer() ? WinAPIServer::getTempPath() :WinAPI::getTempPath()).

Finally this whole exercise was in my case for naught as we later discovered that the client was using Trivial File Transfer Protocol [1] [2]! I think my next post should be on how to execute a batch file from within Axapta to do all of the above but with a special FTP client...

No hay comentarios:

Publicar un comentario