Tag Archives: AIF

AX 2009 – AIF Generation resets Web.config – Resolution


I have a scenario where i have multiple AIF Services on one machine connecting to different AOS’s

Which means every time I generate the service, the web.config file resets itself. Which means the value of BUSINESS_CONNECTOR_CONFIGURATION is blank.

That makes me Unhappy.

So that made me go digging into the service generation classes, so that I can edit the code that will make me happy. Turns out the first time the web.config file is created (I still need to work out on where the first one is created from), it saves it to the folder : C:\Program Files\Microsoft Dynamics AX\50\Application\Appl\AX_MYAPPLICATION_2009\ServiceGeneration

So the next time you generate the service, it uses this file as a master template. YES… master template. Check the code at: Classes\AifServiceConfigGenerator\getConfigFile

So when you know your appsettings, edit this web.config. Next time you generate the service, the BUSINESS_CONNECTOR_CONFIGURATION stays what it is.

This means that if you have multiple AIF sites for the same AOS, then you probably should use a UNC path to the appsettings, so that you dont have to change it on some other machines.

Advertisements

Ax 2012 AIF Calling the CustCustomerService.Create method from WCF


The CustCustomerService (External name CustomerService) can be used to create a customer in Ax through AIF.
When using the http adapter and consuming this service in a .Net Application, this is a tried and tested way to do it.
Notice the DirPartyTable assignment in the code. You do not need to specify the DirParty member, but that is where the customer name is held in Ax 2012

static void WebServiceTest()
{
    using (Ax2012WebService.CustomerServiceClient custClient = new Ax2012WebService.CustomerServiceClient())
    {
        var context = new Ax2012WebService.CallContext() { Company = "ceu" };
        var customers = new Ax2012WebService.AxdCustomer
            {
                CustTable = new Ax2012WebService.AxdEntity_CustTable[] 
                    { 
                        new Ax2012WebService.AxdEntity_CustTable() 
                        { 
                            CustGroup="10", 
                            TaxGroup="CA", 
                            DirParty = new Ax2012WebService.AxdEntity_DirParty_DirPartyTable[1] 
                            {
                                new Ax2012WebService.AxdEntity_DirParty_DirOrganization() 
                                    { LanguageId = "en-us", Name = "SS 001" }
                            }
                        }
                    }
            };
        custClient.create(
            context,
            customers
            );
    }
}

Dynamics Ax 2012 – AIF Import CSV File – Part 3: Import CSV file using AIF


This is the final part to the serieds of Importing CSV files via AIF

Part 1: Consume Web Service
Part 2: Create Item from File adapter 
Part 3: Import CSV file with items Through AIF

In the past posts I consumed a webservice InventItemService and created items in the Released products. This was used as a proof of what should happen when the data is sent to Ax. Part 2 looked at doing the same thing using the File system adapter. here we created an XML file, added the item id’s and then put the file in the folder, the batch did its magic and added the items to the Released Products list

A certain drawback to the that was we had to create the XML files manually, or use an external transformer to do it. AX 2012 has a new feature where we can add transformation Libraries in the form of Either XSLT or .Net libraries.

We will be taking the Inbound port created in Part 2 of this series, and add a transformation library, and instead of dropping an XML file into the inbound directory, we will drop a CSV file

A good read about the process I am about to show is: About the AIF Pipeline [AX 2012]

Create Transformation Library

In Order to create a transformation library, we need to implement an interface found in Microsoft.Dynamics.IntegrationFramework
This DLL can be found in the directory: C:\Program Files\Microsoft Dynamics AX\60\Client\Bin\ 
More information about the Transformation can be found at: Walkthrough: Creating a .NET Assembly Transform [AX 2012]

What we need to do is create a Visual studio project, of a Class Library type

Create Class Library

Add a reference to the Microsoft.Dynamics.IntegrationFramework.Dll using the link above, and create a new class which implements the interface ITransform found in Microsoft.Dynamics.IntegrationFramework.Transform.ITransform

Then create a method which implements the method Transform. This method takes in 3 parameters

1. input (System.IO.Stream) : This is the input stream which is be the file itself
2. output (System.IO.Stream marked as out): This is the output stream that will be returned back to AX. We need to populate this stream
3. configuration (string): This is a custom configuration string that can be added to the port and can be used by the transformation. in this case we will not be using it.

At this stage the class should look like this:

public class LoonItemTransform : Microsoft.Dynamics.IntegrationFramework.Transform.ITransform
{
	public void Transform(System.IO.Stream input, System.IO.Stream output, string configuration)
	{
	    //Need to populate the oputput stream here
	    throw new NotImplementedException();
	}
}

Okay So we have a transformation Library, now we need to add code to read the data from the CSV file, which will be sent in the input stream as a parameter.
The CSV file we are going to add has 2 fields, the itemId and the name.
The Itemd also doubles up as the Product
The code should look like this, Its just reading a file and splitting the line contents.

public class LoonItemTransform : Microsoft.Dynamics.IntegrationFramework.Transform.ITransform
{
    public void Transform(System.IO.Stream input, System.IO.Stream output, string configuration)
    {
        StreamReader sreader = new StreamReader(input);
        string[] dataArray;

        string lineIn = sreader.ReadLine();

        while (lineIn != null)
        {
            dataArray = lineIn.Split(','); //0 is itemid, 1 is name

            lineIn = sreader.ReadLine();
        }
        sreader.Close();

        //Create XML for items

        //Serialize item data to xml string

        //Create Envelope and add header information, and add item data

        //serilalize data to outputstream
    }
}

So at this stage we have the data from our CSV file.We now need to somehow create an XML file similar to the one we created in Part 2. For this we will taking help of the XSD files we had take earlier and I will show you how to create a .Net class out of it. We will add these classes into the Library, and populate it. Serializing these classes will give us the XML file desired.

Creating Classes from XSD

What we did in the previous part was create an XML file that conforms to a certain XSD file. There are 3 XSD files in total that we used for creating the XML file. What we well do is create classes using the XSD files, populate them using the CSV file and serialize them.Upon serialization we will get the same output as the previous post.

In our Visual studio project we will first create 2 folders (to separate the objects generated into 2 different namespaces) ItemXSD and SharedXSD

Open the Visual studio command prompt and navigate to the directory where the XSD files were saved.

For the first instance, we need to create classes for the InventItemService. This XSD (item.xsd) is dependant on the SharedTypes.xsd We will specify both these XSD files and pass it to the XSD.exe command.

In the terminal type the following command:

xsd Item.xsd SharedTypes.xsd /classes /namespace:LooneyTrans.ItemXSD

This creates a file Item_SharedTypes.cs. Place this file in the folder ItemXSD of the project
Note: If you are creating the project in VB .Net, you can use the options in XSD.exe to output a vb file instead

Now create the code for the Envelope

xsd Message.xsd /classes /namespace:LooneyTrans.SharedXSD

Place the output file Message.cs in the folder SharedXSD of the project.

After doing so we should be able to access the object AxdEntity_InventTable, just like we did in Part 1 using web services.
We need to extend this one to adding an envelope which sets the Action for the document. The code should now look like this

public class LoonItemTransform : ITransform
{
    public void Transform(System.IO.Stream input, System.IO.Stream output, string configuration)
    {
        StreamReader sreader = new StreamReader(input);
        string[] dataArray;

        string lineIn = sreader.ReadLine();
        //InventTable collection
        List<ItemXSD.AxdEntity_InventTable> inventTables = new List<ItemXSD.AxdEntity_InventTable>();
        //List<ItemXSD.AxdEntity_InventTable> inventTables = new List<ItemXSD.AxdEntity_InventTable>();
        /*
         There seems to be an issue with the code formatting by wordpress here. Replace 'LT' by the less than sign, and 'GT' by greater than sign. The invent table collection should be
         List'LT'ItemXSD.AxdEntity_InventTable'GT' inventTables = new List'LT'ItemXSD.AxdEntity_InventTable'GT'();
        */
        while (lineIn != null)
        {
            dataArray = lineIn.Split(','); //0 is itemid, 1 is name
            //Create inventTable for each line
            ItemXSD.AxdEntity_InventTable inventTable = new ItemXSD.AxdEntity_InventTable();
            inventTable.ItemId = dataArray[0];
            inventTable.Product = dataArray[0];
            inventTable.NameAlias = dataArray[1];
            //Insert inventTable to collection
            inventTables.Add(inventTable);

            lineIn = sreader.ReadLine();
        }
        sreader.Close();

        ItemXSD.AxdItem item = new ItemXSD.AxdItem();
        item.InventTable = inventTables.ToArray();

        //Serialize item data to xml string
        StringWriter stringWriterItems = new StringWriter();
        System.Xml.Serialization.XmlSerializer serializer = new System.Xml.Serialization.XmlSerializer(typeof(ItemXSD.AxdItem));
        serializer.Serialize(stringWriterItems, item);

        //Put it inside the envelope
        SharedXSD.EnvelopeType envelope = new SharedXSD.EnvelopeType();
        SharedXSD.HeaderType header = new SharedXSD.HeaderType()
                                        {
                                            MessageId = Guid.NewGuid().ToString("B"),
                                            Action = @"http://schemas.microsoft.com/dynamics/2008/01/services/ItemService/create"
                                        };
        envelope.Header = header;
        SharedXSD.BodyType bodyType = new SharedXSD.BodyType();

        //Load item data xml string into an XML Document
        XmlDocument xmlDocumentItems = new XmlDocument();
        xmlDocumentItems.LoadXml(stringWriterItems.ToString());

        //Set the body to the Item XML Document
        bodyType.MessageParts = xmlDocumentItems.DocumentElement;
        envelope.Body = bodyType;

        //serilalize to outputstream
        System.Xml.Serialization.XmlSerializer mainSerializer = new System.Xml.Serialization.XmlSerializer(typeof(SharedXSD.EnvelopeType));
        mainSerializer.Serialize(output, envelope);
    }
}

We now need to compile the project and load the resulting DLL into AX.

Loading the Transformation Library

Going back to the Previous post where we created the Inbound port using the File System Adapter, we need to tell it to use our transformation library. To do so, first deactivate the port, and then set the Inbound Transforms to true.

Set Inbound transforms

From the inbound transform screen, we need to add the Library to the Main Transformation Library. Click the Manage Transformsand add the Library that we created and give it a name and description. Note that you need to set a class on the Manage transforms. This means that we can have more than one transform method in the class library and create a record for each of those.

Create Manage Transforms

We just added our transformation to the main repository and need to reference it in the Inbound transforms for this port

Create Inbound Transform

Notice that the configuration is a text field which can be loaded from a file. This is the text that is passed onto the Transform method created earlier.

After activating this, we should be ready to drop our file and start out batch job
So the File we are passing in look like this:

SS001,SS1ItemName
SS002,SS2ItemName

After dropping the File into the Inbound directory, the batch picks it up and pushes it into the Message Queue.

Item waiting in Queue

As you can see the message that has been created by the transformation Library is similar to the one we used in the Previous post.
When running the batch job again, this queue is processed and the items are pushed into the Released Product table

Result: Items SS001 and SS002 added to Released Products

This concludes the series of Importing a CSV file into AX using the File System Adapter. (*tears of joy rolling out now*)

Dynamics Ax 2012 – AIF Import CSV File – Part 2: Create Item from File adapter


This is part 2 of the series Import CSV file using AIF in AX 2012.

This is a continuation of Part 1, where we consumed the InventItemService.create to add items to the released products in Ax.

Part 1: Consume Web Service
Part 2: Create Item from File adapter
Part 3: Import CSV file with items Through AIF

Clean up: If you did try the previous post, the you would want to delete item SS001 from the release products.

Create inbound port

We will create a new Inbound port of type “File system adapter”

Inbound port setup

So now we need to create the document and then add it to the inbound folder

To create the file, we will need to First grab the schema file for inventItemService, and then wrap it around a Envelope, add a header to define what service this is calling.

Sounds like an awful lot indeed and hope i can make this look easier than what it is.

We need 3 schemas in total

To grab the InventItemService schema, open the AOT/Forms/AifService. This form lists all the available services

View Services

Open this form to reveal the schema:

Invent Item Service

We can now view our schema now and save it. Note the External name and Namespace as we will be using this later on in our Envelope

InventItemService schema

Save this File as InventItemService.xsd

You will see that within this schema is an import “SharedTypes.xsd”. To retrieve this file, click on the “View imported Schemas” from the above screen and save it as SharedTypes.xsd

Now we need the schema which has the Envelope defined. This is defined in a file called Message.xsd which can be found at the following location

C:\Program Files\Microsoft Dynamics AX\60\Server\bin\Application\Share\Include\

Now we can create our XML file to import using the AIF File system adapter

I have added 2 Items to the import SS001 and SS002. Both these items are existing products that have not yet been released.

The XML File will need to look like:

<?xml version="1.0"?>
<Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://schemas.microsoft.com/dynamics/2011/01/documents/Message">
  <Header>
    <MessageId>{46b5e41d-821b-4b20-831d-960c0fcceb1e}</MessageId>
    <Action>http://schemas.microsoft.com/dynamics/2008/01/services/ItemService/create</Action>
  </Header>
  <Body>
    <MessageParts>
      <Item xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://schemas.microsoft.com/dynamics/2008/01/documents/Item">
        <SenderId xsi:nil="true" />
        <InventTable class="entity">
          <_DocumentHash xsi:nil="true" />
          <AltConfigId xsi:nil="true" />
          <AltInventColorId xsi:nil="true" />
          <AltInventSizeId xsi:nil="true" />
          <AltItemId xsi:nil="true" />
          <BatchNumGroupId xsi:nil="true" />
          <BOMCalcGroupId xsi:nil="true" />
          <BOMUnitId xsi:nil="true" />
          <CommissionGroupId xsi:nil="true" />
          <CostGroupId xsi:nil="true" />
          <DefaultDimension xsi:nil="true" />
          <Intracode xsi:nil="true" />
          <InventFiscalLIFOGroup xsi:nil="true" />
          <ItemBuyerGroupId xsi:nil="true" />
          <ItemId>SS001</ItemId>
          <ItemPriceToleranceGroupId xsi:nil="true" />
          <NameAlias>SS1ItemName</NameAlias>
          <OrigCountryRegionId xsi:nil="true" />
          <OrigCountyId xsi:nil="true" />
          <OrigStateId xsi:nil="true" />
          <PackagingGroupId xsi:nil="true" />
          <PBAInventItemGroupId xsi:nil="true" />
          <PrimaryVendorId xsi:nil="true" />
          <ProdGroupId xsi:nil="true" />
          <ProdPoolId xsi:nil="true" />
          <Product>SS001</Product>
          <projCategoryId xsi:nil="true" />
          <PropertyId xsi:nil="true" />
          <ReqGroupId xsi:nil="true" />
          <SerialNumGroupId xsi:nil="true" />
          <StandardConfigId xsi:nil="true" />
          <StandardInventColorId xsi:nil="true" />
          <StandardInventSizeId xsi:nil="true" />
          <WMSPalletTypeId xsi:nil="true" />
        </InventTable>
        <InventTable class="entity">
          <_DocumentHash xsi:nil="true" />
          <AltConfigId xsi:nil="true" />
          <AltInventColorId xsi:nil="true" />
          <AltInventSizeId xsi:nil="true" />
          <AltItemId xsi:nil="true" />
          <BatchNumGroupId xsi:nil="true" />
          <BOMCalcGroupId xsi:nil="true" />
          <BOMUnitId xsi:nil="true" />
          <CommissionGroupId xsi:nil="true" />
          <CostGroupId xsi:nil="true" />
          <DefaultDimension xsi:nil="true" />
          <Intracode xsi:nil="true" />
          <InventFiscalLIFOGroup xsi:nil="true" />
          <ItemBuyerGroupId xsi:nil="true" />
          <ItemId>SS002</ItemId>
          <ItemPriceToleranceGroupId xsi:nil="true" />
          <NameAlias>SS2ItemName</NameAlias>
          <OrigCountryRegionId xsi:nil="true" />
          <OrigCountyId xsi:nil="true" />
          <OrigStateId xsi:nil="true" />
          <PackagingGroupId xsi:nil="true" />
          <PBAInventItemGroupId xsi:nil="true" />
          <PrimaryVendorId xsi:nil="true" />
          <ProdGroupId xsi:nil="true" />
          <ProdPoolId xsi:nil="true" />
          <Product>SS002</Product>
          <projCategoryId xsi:nil="true" />
          <PropertyId xsi:nil="true" />
          <ReqGroupId xsi:nil="true" />
          <SerialNumGroupId xsi:nil="true" />
          <StandardConfigId xsi:nil="true" />
          <StandardInventColorId xsi:nil="true" />
          <StandardInventSizeId xsi:nil="true" />
          <WMSPalletTypeId xsi:nil="true" />
        </InventTable>
      </Item>
    </MessageParts>
  </Body>
</Envelope>

The Items have been added to the Body element of the Envelope

The important part of the envelope is the Header where we define the Action. The action is the Service and the method we are targeting this document for. In this example, this document is targeted to the ItemService and the method is create. The ItemService is the External name of the InventItemService service we exposed for this adapter.

We need to drop this into the designated folder for the inbound and start the batch.

AIF requires 4 batch tasks to be started for this, as defined in: Walkthrough: Exchanging documents by using the file system adapter [AX 2012]

Create a Batch and add the following 4 classes as a batch task: AifGatewayReceiveServiceAifGatewaySendServiceAifInboundProcessingService, and AifOutboundProcessingService.

Set the Batch job to Waiting status, and wait for the batch to Run. You will want to make the batch run twice, the first time it runs the AifGateway adds the file to the Queue, the second time the batch runs, the AifInboundProcessing service will process the file and add the items to the Released products table.

The Queue can be seen at » System Administration > Periodic > Services and Application Integration Framework > Queue Manager

Also keep an eye on the Exceptions (found in the same menu) for any errors.

So after running the Batch for the first time, the Queue should be populated and be ready to be processed

Queue manager

Running the Batch again the items are added the “Released Products” list

Result: Items SS001 and SS002 added to Released Products

To wrap Part 2 up, we created an Inbound File system adapter and assigned the InventItemService.Create method to it. We then extracted our XSD, and with the help of an XML editor we created the file which we then placed into the folder for AX to upload.

Creating the XML file is cumbersome, and what I will like to do is to import a CSV file and use a .Net library to convert it to the XML file Dynamics AX wants.This new transformation in AX 2012 opens a world of possibilities to customize our input files and keep everything within AX and not have to use an external application to do that for us.

Dynamics Ax 2012 – AIF Import CSV File – Part 1: Consume Web service


I will start a series for AIF 2012 to use the Inbound port file adapter settings structured:

Part 1: Consume Web Service
Part 2: Create Item from File adapter
Part 3: Import CSV file with items Through AIF

The aim is to start from a web service to consume an AIF service, and then move that to a file system adapter. I will that take that a step further by adding a .Net transformation library so that we can import a CSV file to do the same. All throughout the process, there will be no change done within Dynamics Ax itself.

The service I am going to consume throughout the series is the InventItemService , and i will create an item.

With AX2012, we need to create a product and then release it. So for this demonstration, I will assume that the Products have been created, but have not been released yet.The AIF webservice InventItemService.create will do this for us.

Create and Consume web service:

I have found consuming AIF as web services easier than File adapter, which is why I start with this and then move this over to the File adapter.

Setting the AIF HTTP port to expose the InventItemService.Create:

Add InventItemService.create to the port

Once the Inbound port is activated, we can consume this in Visual studio. I shall create a Console application, and hard code the items to be created.

In Visual studio, add the service reference using the URI field of the Inbound Port.

static void Main(string[] args)
{
	//Initialise the Service
	using (LoonItemService.ItemServiceClient client = new LoonItemService.ItemServiceClient())
	{
		//Initizlise parameters used for the create method
		LoonItemService.CallContext callContext = new LoonItemService.CallContext() { Company = "ceu" };
		LoonItemService.AxdItem axdItem = new LoonItemService.AxdItem();

		LoonItemService.AxdEntity_InventTable inventTable = new LoonItemService.AxdEntity_InventTable();
		inventTable.ItemId = "SS001";
		inventTable.NameAlias = "SS001NAMEAlias";
		inventTable.Product = "SS001";

		List lstInventTable = new List();
		lstInventTable.Add(inventTable);
		axdItem.InventTable = lstInventTable.ToArray();

		//Call the AIF create method
		var result = client.create(callContext, axdItem);

		//Display the result
		foreach (var item in result)
		{
			foreach (var data in item.KeyData)
			{
				Console.WriteLine(string.Format("{0} : {1}", data.Field, data.Value));
			}
		}
	}
}

For a more detailed process on how to use the inventItemService.create look at this link: How to create an item using ItemServices and EcoResProductServices in AX 2012
On Running the code above, the Item is displayed in the Console, and if you check AX, the item SS001 is now a part of the Released products.

Item SS001 added to the released products

This is what we will replicate across to the File System adapter. in Part 2 and 3