This blog post will be focused on the BizTalk development required to call on a Dynamics AX AIF. Please take a look here if you missed Part 1 which covered the setup work required in Dynamics AX to actually expose a specific AIF to your BizTalk server.
The AIF service we are going to be calling on in this exercise is CustCustomerService.find which is used to retrieve customer details using the customer’s account number as a the search criteria. We’ll set up an orchestration which is activated with a CustomerRequest message, which is then mapped to the AIF request message, the request will be made, and the response will be used to map to a CustomerResponse message. Please keep in mind that for simplicity’s sake, this example will portray all the components being in a single project. I will cover at the end what practices I believe should be applied in a real life application.
After creating a Visual Studio BizTalk project (do all the normal stuff like signing it with a strong name key and setting what application it deploys to etc…) the first thing we will need to do is to create the CustomerRequest and CustomerResponse schemas. I’ll keep it quite simple for this example, see the below screenshots for the schema structure.
The next thing we’ll want to do is to add in the required AX schema files. When calling on a .Find type AIF service, the request message will always be a generic message with a root node named QueryCriteria. This schema exists in the Microsoft.Dynamics.BizTalk.Adapter.Schemas dll, so add a reference to it in your project, you’ll typically find it in the C:Program Files (x86)Microsoft Dynamics AX50Client directory.
You will need to open AX to get the schema for the response message from AX. Theres a few ways you can get to the schema but I’ll give you one method. Once again you want to Application Integration Framework section under the Basic menu option (we covered this in the last blog post but here’s a screenshot to remind you).
You want to navigate to the endpoint menu, click on the Remote endpoint record that you set up as per the previous blog post, and click on Action Policies. You will now have a list of all the AIF services that are exposed to our remote endpoint, click on CustCustomerService.Find and click on parameter schema. This is the complete schema that represents a customer, which you can save and add to your visual studio project.
Next step is to add a map to your project from the CustomerRequest schema to the QueryCriteria schema. You’ll want to map a value of CustTable to the DataSourceName since that’s the name of the table we are querying againt. We want a value of AccountNum in the FieldName element since that is going to be our search criteria. The Operator element should be given a value of Equal since we are trying to find a record where the account number equals the value which we are going to provide. I’ve used String Concatenate functoids to provide values to these three elements. Lastly you will want to map the AccountNumber from your CustomerRequest schema to the QueryCriteria schema’s Value1 element. We’re going to leave Value2 unpopulated since it isn’t applicable in cases where the Operator is set to Equal. Your map should look somewhat like the below.
We’ll now want to add a second map which will be from the AX Customer schema to your CustomerResponse schema. This one is quite straightforward, your end result should look like the below (notice that I am making use of Visual Studio 2010’s relevance tree view feature on the source schema to hide all the elements in the source schema that aren’t relevant to my map, it definitely makes it easier to study maps).
Now that our maps are in place, next step is the orchestration. Again we’ll keep this pretty straightforward. Create an orchestration and declare messages of type CustomerRequest, CustomerResponse, QueryCriteria, and Customer (AX). Create a port type which has a request-response operation on it,one with QueryCriteria as the request and Customer (AX) as the response (lets call this the AX operation). Create one send port of this type (you can set the binding for these ports to be specify-later to keep this exercise simple). Next create a port type which has two one way operations in it, one having CustomerRequest as the request and the second having CustomerResponse as the request. Create a receive and a send port of this type (you can set the binding for these ports to be specify-later to keep this exercise simple).
You should now follow the below steps to get your orchestration to look like the above screenshot.
- Drag a receive shape onto the orchestration designer surface and set the message to be the CustomerRequest message, and set it to be an activating receive. Set the operation to the request on the CustomerRequest operation in your receive port.
- Next, add in a construct shape and set it to construct the QueryCriteria message
- Insert a transform shape into the construct shape and use the CustomerRequest to QueryCriteria map, set up the map parameters appropriately
- Next, insert a message assignment shape. Let’s leave the expression blank for now but we’ll come back to it with some further explanation later
- Next, add a send shape and set the message to be your QueryCriteria message and connect it to the request in the operation on your AX send port
- Next add in a receive shape and set the message to your Customer message and connect it to the response in the operation on your AX send port
- Next add in a construct shape and set it to construct the CustomerResponse message
- Insert a transform shape into the construct shape and use the Customer To CustomerResponse map, set up the map parameters appropriately
- Insert a send shape, set the message to be your CustomerResponse message and set it to the CustomerResponse operation on your one way send port
This all seems pretty straightforward. You might be wondering why we put in the Message Assignment shape in the construct for the QueryCriteria message. This is because when calling Dynamics AX AIF services, you need to set a few properties on your request message that would then get added into the header of the message by the Dynamics AX adapter. Your message assignment should look like the below.
- The SourceEndPoint is equivalent to the Remote Endpoint name that you setup in the part 1 of this blog entry.
- The DestinationEndPoint is equivalent to the Local Endpoint name that you setup in part 1 of this blog entry.
- The Action appears to be (I am not 100% sure of this, but it makes logical sense, please let me know if you believe otherwise) a combination of <the NameSpace of the service>/<the external name of the service>/<the specific operation on the service you are calling on, ex. find / create etc…).
- The MessageID is a UniqueIdentifier for this transaction. I believe that this is intended for correlation purposes but doesn’t serve much purpose for this example since we’ll be using a solicit-response synchronous adapter. Just create a GUID and set it to be the value for the MessageID property.
That is pretty much all there is to the development side of things. You should now be able to deploy the project to your development BizTalk environment. Create a file receive and send port which you will use to receive the CustomerRequest and send the CustomerResponse messages to and bind them to the orchestration. Make sure the the receive pipeline for the receive file location is set to XMLReceive.
Next create a static solicit-response send port and set the adapter type to Microsoft Dynamics AX 2009 adapter. I believe that you must set the Send Pipeline to be XMLTransmit (I will try to set it to PassThroughTransmit on the next opportunity I have to see if this works). In the adapter settings you need to apply settings as below.
There are a few options for the authentication type, I choose host user as we have previously given access to our host user for this remote endpoint while working through part 1 of this blog entry. I would recommend that you read this Technet Article to get a better understanding of AIF security concepts. If you choose host user then you shouldn’t have to fill in any more authentication settings.
Under the connection settings, set the AOS Port appropriately (default in 2712 but if you have multiple AX instances installed on the same server then it might be another port number as in the above screenshot), enter your server’s DNS name in the AOS Server section, and a timout in minutes for synchronous transactions.
You should now bind this send port to the orchestration appropriately. If you drop a message of type CustomerRequest into the file receive location then it should result in the AIF service being called and the response being mapped back to your CustomerRequest type and a file created in the file send location. Well done 🙂
Here’s a list of things I would do differently in a real life application of AX (I wont mention the non-AX related practices that I would do differently).
- I would write a custom pipeline component that promotes the required AX properties to a message instead of writing them in a Message Assignment shape in orchestration. The custom pipeline component would write these properties based on parameters (in which case there would have to be a seperate send port for every AIF since the action property is specific to each AIF) or you could take it one step further and provide a mechanism to dynamically set the Action property (in which case you will only need one send port).
- I would always put AX schemas into an AX specific project, and in fact in a seperate solution and deployed to a seperate BizTalk application. Remember that these are pretty generic services and it is likely that there will be more BizTalk solutions in the future that will need to call on these messages.
- I would create Canonical versions of the AX schemas, and use these in my orchestrations so that they don’t have to be exposed to the actual implemenations. This protects you in case Microsoft releases changes to their components and you wont have to change and redeploy your orchestrations, and of course also protects you in case your company decides to change to use a system other than Dynamics AX in the future. You would of course also need to create maps from the canonical schemas to the AX schemas and vice versa, which you could apply on the send ports. These schemas and maps would be deployed to the same BizTalk application as the AX schemas.
- I would make an orchestration project which contains public multi-part message types and port types based on the canonical schemas mentioned above. I would deploy this to the same BizTalk application as the AX schemas.
- I would create an AX send port(s) in the BizTalk application where the AX schemas were deployed, and set up filters on it such that canonical messages which are representing AX requests are directed here. I would have the canonical->AX maps setup on the outbound maps section of the port and the AX->Canonical maps setup on the inbound maps section of the port. Because we setup subscription filters on this send port(s), there is no need to bind orchestrations to this port(s) and they can use direct binding.
- I would bypass orchestration altogether and implement a messaging type solution unless orchestration was really warranted.