Skip to main content

Dynamics AX 2009: FTP Adapter for AIF

from Markus Nöbauer

The Application Integration Framework in Dynamics AX is an extensible framework for data transportation and reception. It support the separation of transport technology (e.g. MSMQ, XML/SOAP Webservices, Filesystem Share) security aspects (services, permissions, transported data) and data manipulation. Creating new adapters to support other transport technologies is simple. Here is an example to support FTP.

Develop AIF FTP Adapter

  • First, create a new parameter table AifFTPParameters to store FTP server name, user, password and directory (4 strings). Next create a setup form for the AifFTPParameters table and a display menu item. Add an OK command button. Add this code to the buttons clicked event:

    void clicked()
    {;
        super();
        // use the server name as selected value 
        element.closeSelect(Setup_ServerName.text());
    }
    FTP Parameters setup
  • Create a new AifFTPSendAdapter class that implementes the AifSendAdapter interface. You may create empty implementations for begin(), commit(), initialize(), rollback() and terminate(). But you really need to implement the sendMessage() method. I’m using the System.Net Classes to implement the FTP transfer.
     

    public void sendMessage(AifGatewayMessage gatewayMessage)
    {
        System.Text.Encoding encoding;
        System.Byte[] bytes;
        str requestStr = "";
        object ftpo;
        System.Net.FtpWebRequest ftpRequest;
        System.Net.NetworkCredential credential;
        str ftpUser;
        str ftpPass;
        System.IO.Stream requestStream;
        InteropPermission clrPermission =
         new InteropPermission(InteropKind::ClrInterop);
        ;

        clrPermission.assert();
        switch(gatewayMessage.parmEncoding())
        {
            case ‘UTF-8′:
                encoding = System.Text.Encoding::get_UTF8();
                break;
            default:
                throw error("Unsupported Encoding");
        }
        bytes = encoding.GetBytes(gatewayMessage.parmMessageXml());

        requestStr = strfmt(‘ftp://%1′,AifFTPParameters::find().ServerName);
        if(AifFTPParameters::find().Directory)
        {
            requestStr = strfmt(‘%1/%2′,
                                 requestStr,
                                 AifFTPParameters::find().Directory);
        }

        requestStr = strfmt(‘%1/%2%3′,
                              requestStr,
                              gatewayMessage.parmMessageId(),
                              ’.xml’);

        ftpo =  System.Net.WebRequest::Create(requestStr);
        ftpRequest = ftpo;

        ftpUser = AifFTPParameters::find().UserName;
        ftpPass = AifFTPParameters::find().Password;
        //BP deviation documented
        credential = new System.Net.NetworkCredential(ftpUser,ftpPass);
        ftpRequest.set_Credentials(credential);
        ftpRequest.set_ContentLength(bytes.get_Length());
        ftpRequest.set_Method(‘STOR’);

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

        CodeAccessPermission::revertAssert();
    }
  • Create a new AifFTPAdapter class that implements AifIntegrationAdapter. This class is used by the AIF configuration interface in Dynamics AX to identify an outbound adapter and its configuration form.
    public AifIntegrationAdapterType getAdapterType()
    {;
        return AifIntegrationAdapterType::SendOnly;
    }
    public MenuItemNameDisplay getAddressDisplayMenuItem()
    {;
        // the AifFTPParameter forms display menu items name
        return ‘AifFTPParameters’;
    }
    public AifTransportAddress getCanonicalTransportAddress(AifTransportAddress transportAddress)
    {;
        return transportAddress;
    }
    public MenuItemNameDisplay getConfigurationDisplayMenuItem()
    {;
        return ”;
    }
    public LabelString getLabel()
    {;
        return "AIF FTP Adapter";
    }
    public AifReceiveAdapter getReceiveAdapter()
    {;
        return null;
    }
    public AifSendAdapter getSendAdapter()
    {;
        return new AifFTPSendAdapter();
    }
    public boolean isHosted()
    {;
        return true;
    }
    public void validateConfiguration(AifTransportAddress transportAddress,
                                      AifChannelDirection channelDirection)
    {;
        //TODO:Check or throw error
    }
      1. Register FTP Adapter and configure AIF

    1. Go to Basics > Setup > Application Integration Framework.
    2. In Local Endpoints make sure you have an endpoint configured
    3. In Transport Adapters create a new record, select AifFTPAdapter and mark it as active.
    4. In Channels, create a new outbound FTP Channel, provide server name and credentials.
      Mark the channel as active.
      Configure AIF FTP Adapter 
    5. In Services activate the SalesSalesInvoiceService
      Activate SalesSalesInvoiceService 
    6. In Endpoints create a new endpoint. Set the outbound channel to your FTP channel and set the local endpoint. Go to the Constraints tab and set “No Constraints” flag. Mark the endpoint as active.
      Create an endpoint with outbound FTP Click the Action Policies button and add the SalesSalesInvoiceService.read method
      Activate SalesSalesInvoiceService.read
      Click the Data Policies button and use the set button to enable all data fields for transportation.
      Set data policies for invoice
    7. Go to Basic > Inquiries > Batch jobs. Make sure to run a batch job that processes the AIF message send and receive tasks: AIFInboundProcessingService, AIFOutboundProcessingService, AIFGatewaySendService and AIFGatewayReceiveService.
      Setup AIF processing batch jobs
    8. Go to Accounts Receivable > Inquiries > Journals > Invoice. Select an invoice and use the Send Electronically button to put it in the transportation queue.
      Send invoice electronically using AIF
    9. Wait a few miniutes and take a look at your FTP space. There you should see the transmitted invoices as xml file.
      Invoice successfully uploaded

    Popular posts from this blog

    Dynamics Axapta: Sales Orders & Business Connector

    Well, again folllowing my same idea of writting close to nothing and pasting code, I'll paste in some code to create a sales order from some basic data and the invoice it. I'll try to explain more in the future. AxaptaObject axSalesTable = ax.CreateAxaptaObject("AxSalesTable"); AxaptaRecord rcInventDim = ax.CreateAxaptaRecord("InventDim"); AxaptaRecord rcCustTable = ax.CreateAxaptaRecord("CustTable"); rcCustTable.ExecuteStmt("select * from %1 where %1.AccountNum == '" + MySalesOrderObject.CustAccount + "'"); if (MySalesOrderObject.CurrencyCode.Trim().Length == 0) MySalesOrderObject.CurrencyCode = rcCustTable.get_Field("Currency").ToString().Trim(); string sTaxGroup = rcCustTable.get_Field("taxgroup").ToString().Trim(); //set header level fields axSalesTable.Call("parmSalesName", MySalesOrderObject.SalesName.Trim()); axSalesTable.Call("parmCustAccount", M

    Passing values between form and class

    Class name is EmplDuplication and Form is EmplTable . void clicked() {    MenuFunction mf;    args args = new Args();    ;     args.record(EmplTable);     mf = new menufunction(identifierstr(EmplDuplication), MenuItemType::Action); mf.run(args); } Meanwhile, in the main() method of the EmplDuplication class, we need to put this Axapta x++ code to get the datasource: static void main(Args args) {     EmplDuplication EmplDuplication; EmplTable localEmplTable; ;     if(args.record().TableId == tablenum(EmplTable)) localEmplTable = args.record();     ... }