Monday, June 1, 2015

Microsoft Dynamics AX 2012 Class Libraries (DLLs)

Microsoft Dynamics AX 2012 Class Libraries (DLLs)
 
Purpose: The purpose of this document is to illustrate how to work with class libraries in the context of Microsoft Dynamics AX 2012.
 
Challenge: For the purposes of POC, integration project or development project you may need to consume Microsoft Dynamics AX 2012 Web Services from external class libraries or call external Web Services from Microsoft Dynamics AX 2012 managed code assemblies.
 
Solution: In this walkthrough I'm going to highlight number of ways you can consume Microsoft Dynamics AX 2012 Web Services from external class library using configuration settings in application config file or handled in the application code. Also I will highlight how develop Microsoft Dynamics AX 2012 managed code assemblies and then call external Web Services from there.
 
Walkthrough
 
Calling Microsoft Dynamics AX 2012 Web Service from external Class Library (DLL)
 
First of all I will expose Microsoft Dynamics AX 2012 Web Services via Inbound ports using NET.TCP and HTTP adapters
 
Inbound port (NET.TCP)
 
 
Inbound port (HTTP)
 
 
IIS
 
 
After Web Services have been exposed through Inbound ports in your client application you can Add Service Reference using WSDL URI as shown below
 
Add Service Reference (NET.TCP)
 
 
Add Service Reference (HTTP)
 
 
Added Service Reference will show up in your project as below
 
Solution Explorer (Console App)
 
 
Please note that corresponding Endpoint and Binding details will be added to App.config after you added Service Reference
 
App.config
 
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
    <startup>
        <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
    </startup>
    <system.serviceModel>
        <bindings>
            <netTcpBinding>
                <binding name="NetTcpBinding_AdvancedLedgerEntryService" />
            </netTcpBinding>
        </bindings>
        <client>
            <endpoint address="net.tcp://ax2012r2a:8201/DynamicsAx/Services/AlexServices"
binding="netTcpBinding" bindingConfiguration="NetTcpBinding_AdvancedLedgerEntryService"
contract="ServiceReference1.AdvancedLedgerEntryService" name="NetTcpBinding_AdvancedLedgerEntryService">
                <identity>
                    <userPrincipalName value="admin@Contoso.com" />
                </identity>
            </endpoint>
        </client>
    </system.serviceModel>
</configuration>
 
Now I’ll create a class library project and Add Service Reference too
 
Solution Explorer (Class Library)
 
 
Similarly to above corresponding Endpoint and Binding details will be added to App.config 
 
App.config
 
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
    <system.serviceModel>
        <bindings>
            <netTcpBinding>
                <binding name="NetTcpBinding_AdvancedLedgerEntryService" />
            </netTcpBinding>
        </bindings>
        <client>
            <endpoint address="net.tcp://ax2012r2a:8201/DynamicsAx/Services/AlexServices"
binding="netTcpBinding" bindingConfiguration="NetTcpBinding_AdvancedLedgerEntryService"
contract="ServiceReference1.AdvancedLedgerEntryService" name="NetTcpBinding_AdvancedLedgerEntryService">
                <identity>
                    <userPrincipalName value="admin@Contoso.com" />
                </identity>
            </endpoint>
        </client>
    </system.serviceModel>
</configuration>
 
In fact when leveraging business logic from class library you have to use client application config file instead of original DLL config file. That’s why I will copy Endpoint and Binding details from DLL config file over to client app config file
 
Client application Config file
 
<?xml version="1.0"?>
<configuration>
    <system.serviceModel>
        <bindings>
            <netTcpBinding>
                <binding name="NetTcpBinding_AlexService" />
            </netTcpBinding>
        </bindings>
        <client>
            <endpoint address="net.tcp://ax2012r2a:8201/DynamicsAx/Services/AlexServices"
                binding="netTcpBinding" bindingConfiguration="NetTcpBinding_AlexService"
                contract="AXServiceReference.AlexService" name="NetTcpBinding_AlexService">
                <identity>
                    <userPrincipalName value="admin@Contoso.com" />
                </identity>
            </endpoint>
        </client>
    </system.serviceModel>
</configuration>
 
Now my client application will be well aware about Endpoint and Binding details for Microsoft Dynamics AX 2012 Web Service
 
Alternatively you can handle Endpoint and Binding details for Microsoft Dynamics AX 2012 Web Service directly in client application code as shown below  
 
Client application Code
 
BasicHttpBinding binding = new BasicHttpBinding();
binding.Security.Mode = BasicHttpSecurityMode.TransportCredentialOnly;
binding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Windows;
 
EndpointAddress address = new EndpointAddress("http://ax2012r2a.contoso.com/MicrosoftDynamicsAXAif60/AlexWebServices/xppservice.svc");
 
AlexServiceClient client = new AlexServiceClient(binding, address);
 
CallContext context = new CallContext();
context.Company = "usmf";
 
client.ClientCredentials.Windows.ClientCredential.Domain = "contoso";
client.ClientCredentials.Windows.ClientCredential.UserName = "Admin";
client.ClientCredentials.Windows.ClientCredential.Password = "pass@word1";
 
try
{
    client.method1(context);
}
catch (Exception e)
{
 
}
 
Call external Web Service from Microsoft Dynamics AX 2012 Class Library (DLL)
 
In the second part of the walkthrough I’m going to wrap a business logic calling external Web Service with Microsoft Dynamics AX 2012 managed code assembly
 
First off I’ll create Class Library project with minimalistic implementation for a single class and method which mimic calling external Web Service
 
Class Library  
 
 
As coding is complete I’ll add Class Library project directly into Microsoft Dynamics AX 2012 AOT. Please note that I have Microsoft Dynamics AX 2012 Visual Studio Tools installed to accomplish this: https://technet.microsoft.com/en-us/library/dd309576.aspx
 
My project now will change its icon to Microsoft Dynamics specific one, after that I’ll be able to select auto-deployment options in Project Properties. Specifically I will choose to deploy assembly to Microsoft Dynamics AX 2012 Client (Yes) and Server (Yes)
 
Class Library (Deployment)
 
 
After successful deployment my project will show up in Microsoft Dynamics AX 2012 AOT
 
AOT – C Sharp Projects
 
 
Here’s the implementation of class and method which mimic calling external Web Service from within Microsoft Dynamics AX 2012 managed code assembly
 
Source code
 
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
 
namespace AlexDLL
{
    public class Class1
    {
        public string method1()
        {
            return "External Web Service call";
        }
    }
}
 
Generally it would be a good idea to encapsulate business logic calling external Web Service in a single method in managed code assembly, this way you can simply call a single method in X++ to consume Web Service and obtain the result
 
When deploying assemblies from within Visual Studio you may need to make sure that “Enable the hot-swapping of assemblies for each development session” setting is selected in Microsoft Dynamics AX 2012 Server Configuration Utility in order to avoid deployment errors
 
Microsoft Dynamics AX 2012 Server Configuration Utility
 
 
Before you deploy you will need to Sign the assembly in Project Properties > Signing
 
Create Strong Name Key
 
 
Now we are ready to deploy the assembly
 
Deploy
 
 
Upon successful deployment you will be able to use IntelliSense in X++ and consume elements of managed code assembly namespace just the way you consume native X++ business logic classes
 
X++ code
 
static void DLL(Args _args)
{
    AlexDLL.Class1 class1 = new AlexDLL.Class1();
 
    info(class1.method1());
}
 
The result will look like below
 
Result
 
 
Please learn more about Deploying Managed Code Assemblies here: https://msdn.microsoft.com/en-us/library/gg889192.aspx
 
Summary: In this walkthrough I illustrated how to call Microsoft Dynamics AX 2012 SOAP Web Services from Windows 8 application using JavaScript and shed some light into what's happening behind the scenes when you call Web Service, how request and response look like and what you have to do to successfully call Microsoft Dynamics AX 2012 SOAP-based Web Services.
 
Tags: Microsoft Dynamics AX 2012, Custom Web Services, X++, C#.NET, HTTP, NET.TCP, Config file, Class library, DLL, Endpoint, Binding.
 
Note: This document is intended for information purposes only, presented as it is with no warranties from the author. This document may be updated with more content to better outline the issues and describe the solutions.
 
Author: Alex Anikiev, PhD, MCP

Wednesday, May 6, 2015

Microsoft Dynamics AX 2012 – Calling SOAP Web Services from JavaScript

Microsoft Dynamics AX 2012 – Calling SOAP Web Services from JavaScript
 
Purpose: The purpose of this document is to illustrate how to call Microsoft Dynamics AX 2012 SOAP Web Services from Windows 8 application using JavaScript.
 
Challenge: Application Integration Framework (AIF) supports Web services for Windows Communication Foundation (WCF). In AIF, each document is represented by a service that can be exposed from an integration port. To consume services over the Internet, you must host services on Internet Information Services (IIS). AIF uses standard WCF processing to receive and process SOAP requests. Please find more info on AIF and Services here: https://technet.microsoft.com/en-us/library/gg731810.aspx. For the purposes of POC or app development you may need to consume Microsoft Dynamics AX 2012 SOAP Web Services from Windows 8 application using JavaScript
 
Solution: In this walkthrough I'm going to deploy an instance of Microsoft Dynamics AX 2012 R3 in the Cloud on Windows Azure using Microsoft Dynamics AX Lifecycle Management Services (LCS), write my own Custom WCF Web Service exposing business data and call this SOAP-based Web Service from Windows 8 application using JavaScript WinJS.xhr (XML Http Request) object. Please find more info about asynchronous programming, WinJS promises and xhr (XML Http Request) object here: https://msdn.microsoft.com/en-us/library/windows/apps/br229787.aspx
 
Walkthrough
 
First of all I'll deploy an instance of Microsoft Dynamics AX 2012 R3 using LCS. Please visit http://lcs.dynamics.com to access LCS Cloud service
After successful deployment I'll be able to access my Demo VM on Azure portal
What I'll need to do for my walkthrough is to enable HTTP/HTTPS endpoints for my Demo VM so I can reach out to my Web Service over internet
 
Endpoints
 
 
Please note that enabling HTTP/HTTPS endpoints for Demo VM is suitable for the purposes of POC, but it is not secure and not suitable for production applications accessing Microsoft Dynamics AX 2012. In order to build production application securely accessing Microsoft Dynamics AX 2012 please utilize Windows Azure Service Bus. Please find detailed guidance on how to leverage Windows Azure Service Bus to establish secure cross-domain connection to Microsoft Dynamics AX 2012 here: http://www.microsoft.com/en-us/download/details.aspx?id=38413
 
Continuing in this walkthrough I'll focus on mechanics of what's going on with Web Service request behind the scenes. But before we get there I'll do some necessary plumbing  
 
My plan is to expose custom business data based on newly created table. Please see the structure of my project below
 
Code
 
 
By using my simple WCF Custom Services Class Wizard (http://ax2012aifintegration.blogspot.com/2014/11/microsoft-dynamics-ax-2012-custom-web.html) I quickly created Data contract and Service contract classes to expose necessary business data
 
Data Contract
 
[DataContractAttribute]
public class AlexTableContract
{
    AlexName    Name;
    AlexID      ID;
}
[DataMemberAttribute]
public AlexID ID(AlexID _ID = ID)
{
         ID = _ID;
         return ID;
}
[DataMemberAttribute]
public AlexName Name(AlexName _Name = Name)
{
         Name = _Name;
         return Name;
}
 
Service Contract
 
public class AlexServiceContract
{
}
[AifCollectionTypeAttribute('return', Types::Class, classStr(AlexTableContract)), SysEntryPointAttribute(true)]
public List getList()
{
    AlexTable           alexTable;
 
    AlexTableContract   alexTableContract;
 
    List                list;
 
    list = new List(Types::Class);
 
    while select alexTable
    {
        alexTableContract = new AlexTableContract();
 
        alexTableContract.ID(alexTable.ID);
        alexTableContract.Name(alexTable.Name);
 
        list.addEnd(alexTableContract);
    }
 
    return list;
}
 
Then I will wrap up my classes with Microsoft Dynamics AX Service (AlexService) and execute right click > Add-ins > Register service command for AlexService

At this point I'll populate my table with a few records using Table Browser

Table browser
 
 
Next I'll create Inbound port for newly created Web Service using HTTP adapter
 
Inbound port
 
 
Then I will add AlexService.getList operation to the Web Service
 
Select service operations
 
 
As the next step I'll write a simple Windows Console client application to better understand how my Web Service request looks like behind the scenes when I call my Web Service. As I create new Windows Console application I will need to add Web Service Reference as shown below 
 
Add Service Reference
 
 
The code for the client looks like below
 
Code
 
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using ConsoleApplication1.ServiceReference1;
 
namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
 
            AlexServiceClient client = new AlexServiceClient();
 
            CallContext context = new CallContext();
            context.Company = "usmf";
 
            client.ClientCredentials.Windows.ClientCredential.UserName = "Admin";
            client.ClientCredentials.Windows.ClientCredential.Password = "pass@word1";
 
            AlexTableContract[] list = client.getList(context);
 
            foreach (AlexTableContract item in list)
            {
                Console.WriteLine(item.ID + ": " + item.Name);
            }
 
            Console.ReadLine();
        }
    }
}
 
As the result I'll output the list of values from my table
 
Result
 
 
Now the most interesting part. Before I ran my client program to fetch the data from Microsoft Dynamics AX 2012, I launches Fiddler to listen to HTTP/HTTPS traffic and see HTTP/HTTPS requests and responses taking place. You can download Fiddler from here: http://www.telerik.com/download/fiddler
 
Fiddler
 
 
In Fiddler I can clearly see how HTTP/HTTPS request and response looked like when I execute my client application and called Microsoft Dynamics AX 2012 Web Service
 
Request
 
 
Content-Type: text/xml; charset=utf-8
VsDebuggerCausalityData: uIDPo9P2U4sA1ENFu3GK474gpEsAAAAA7d1xyqrazUe5zAsDszpG8Js/kfbqE3NPrANxMKaGnFUACQAA
Accept-Encoding: gzip, deflate
Authorization: Negotiate TlRMTVNTUAADAAAAGAAYAHQAAABWAVYBjAAAAAAAAABYAAAACgAKAFgAAAASABIAYgAAABAAEADiAQAAFYKY4gYDgCUAAAAP4smxKQqDAj833urXTwSs6kEAZABtAGkAbgBBAFgAMgAwADEAMgBSADIAQQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAK1LD71uLVVMkxHvfFgRwwAQEAAAAAAABOi3kxVIjQAcS5+RmOrRhQAAAAAAIADgBDAE8ATgBUAE8AUwBPAAEAEgBBAFgAMgAwADEAMgBSADIAQQAEABYAYwBvAG4AdABvAHMAbwAuAGMAbwBtAAMAKgBBAFgAMgAwADEAMgBSADIAQQAuAGMAbwBuAHQAbwBzAG8ALgBjAG8AbQAFABYAYwBvAG4AdABvAHMAbwAuAGMAbwBtAAcACABOi3kxVIjQAQYABAACAAAACAAwADAAAAAAAAAAAQAAAAAgAADeJ7ljj7kKuEdzr8/a6bURMeu7wAp6EgJ5THCXwCzf3QoAEAAAAAAAAAAAAAAAAAAAAAAACQA0AEgAVABUAFAALwBhAHgAMgAwADEAMgByADIAYQAuAGMAbwBuAHQAbwBzAG8ALgBjAG8AbQAAAAAAAAAAAAAAAACX0gZZ9yPRi0zt4hbarMLO
Host: ax2012r2a.contoso.com
Content-Length: 595
Expect: 100-continue
 
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/"><s:Header><h:CallContext xmlns:h="http://schemas.microsoft.com/dynamics/2010/01/datacontracts" xmlns:i="http://www.w3.org/2001/XMLSchema-instance"><h:Company>usmf</h:Company><h:Language i:nil="true"/><h:LogonAsUser i:nil="true"/><h:MessageId i:nil="true"/><h:PartitionKey i:nil="true"/><h:PropertyBag i:nil="true" xmlns:a="http://schemas.microsoft.com/2003/10/Serialization/Arrays"/></h:CallContext></s:Header><s:Body><AlexServiceGetListRequest xmlns="http://schemas.microsoft.com/dynamics/2008/01/services"/></s:Body></s:Envelope>
 
 
Please note that POST method was used to call Web Service. Also appropriate envelope was added to the request
 
The response is returned in form of structured XML also wrapped with envelope

Response
 
 
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/"><s:Body><AlexServiceGetListResponse xmlns="http://schemas.microsoft.com/dynamics/2008/01/services"><response xmlns:b="http://schemas.datacontract.org/2004/07/Dynamics.Ax.Application" xmlns:i="http://www.w3.org/2001/XMLSchema-instance"><b:AlexTableContract><b:ID>1</b:ID><b:Name>Alex</b:Name> </b:AlexTableContract><b:AlexTableContract><b:ID>2</b:ID><b:Name>Test><b:Name> </b:AlexTableContract></response></AlexServiceGetListResponse></s:Body></s:Envelope>
 
At this point I have enough knowledge to call my Web Service from Windows 8 application using JavaScript WinJS.xhr object. WinJS is a Windows library for JavaScript which implements Windows look and feel for your apps as well as a lot of useful objects such as xhr (XML HTTP request). Please find more info about WinJS here: https://dev.windows.com/en-us/develop/winjs
 
In order to create my Windows 8 app I'll use JavaScript Hub App template as shown below
 
Hub App (Windows)
 
 
For my app I'll implement a simple HTML page List.html to display the list of records from Microsoft Dynamics AX 2012 after calling Web Service. Here's how related List.js file looks like which implements business logic calling Web Service using WinJS.xhr object 
 
List.js
 
(function () {
    "use strict";
 
    WinJS.UI.Pages.define("/pages/list/list.html", {
        // This function is called whenever a user navigates to this page. It
        // populates the page elements with the app's data.
        ready: function (element, options) {
        }
    });
 
    function doClickSync() {
 
        var data = '<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/"><s:Header><h:CallContext xmlns:h="http://schemas.microsoft.com/dynamics/2010/01/datacontracts" xmlns:i="http://www.w3.org/2001/XMLSchema-instance"><h:Company>usmf</h:Company><h:Language i:nil="true"/><h:LogonAsUser i:nil="true"/><h:MessageId i:nil="true"/><h:PartitionKey i:nil="true"/><h:PropertyBag i:nil="true" xmlns:a="http://schemas.microsoft.com/2003/10/Serialization/Arrays"/></h:CallContext></s:Header><s:Body><AlexServiceGetListRequest xmlns="http://schemas.microsoft.com/dynamics/2008/01/services"/></s:Body></s:Envelope>';
        var options = {
            url: "http://ax2012r3-demo.cloudapp.net/MicrosoftDynamicsAXAif60/AlexWebServices/xppservice.svc",
            type: "post",
            headers: {
                "Content-Type": "text/xml; charset=utf-8",
                "SOAPAction": "http://schemas.microsoft.com/dynamics/2008/01/services/AlexService/getList"
            },
            user: 'Admin',
            password: 'pass@word1',
            data: data
        };
 
        WinJS.xhr(options)
            .done(
            function (request) {
                var dataItems = [];
                var xmlResponse = request.responseXML.documentElement;
 
                var fullNodeList = xmlResponse.getElementsByTagName("b:AlexTableContract");
 
                for (var i = 0; i < fullNodeList.length; i++) {
                    var dataItem = { id: fullNodeList[i].childNodes[0].textContent, name: fullNodeList[i].childNodes[1].textContent };
                    dataItems.push(dataItem);
                }
 
                var dataList = new WinJS.Binding.List(dataItems);
                var alexView = document.getElementById('alexList').winControl;
                alexView.itemDataSource = dataList.dataSource;
            },
            function (error) {
            },
            function (progress) {
            });
    }
 
})();
 
Please note that I included envelope and passed it as data into WinJS.xhr. Also I used post method to call Web Service, explicitly defined SOAP Action, provided authentication details as a part of request (please take into account security concerns when developing your apps, for the purposes of POC and simplicity I just hard-coded authentication details into the request). Finally when I receive asynchronous response I'll need to parse it out using XML DOM model and re-assign the data source for List element in HTML
 
As the result I successfully display the list of records from Microsoft Dynamics AX 2012 in my app
 
Result
 
 
Similarly you can implement not only data retrieval scenarios but also data manipulation scenarios calling Microsoft Dynamics AX 2012 Web Services. For example, creation of Sales order or creation/posting of General journal or Inventory journal
 
Summary: In this walkthrough I illustrated how to call Microsoft Dynamics AX 2012 SOAP Web Services from Windows 8 application using JavaScript and shed some light into what's happening behind the scenes when you call Web Service, how request and response look like and what you have to do to successfully call Microsoft Dynamics AX 2012 SOAP-based Web Services.
 
Tags: Microsoft Dynamics AX 2012, Custom Web Services, Data Contract, Service Contract, X++, Windows 8 App, JavaScript, WinJS, XHR, XML HTTP Request/Response, Fiddler.
 
Note: This document is intended for information purposes only, presented as it is with no warranties from the author. This document may be updated with more content to better outline the issues and describe the solutions.
 
Author: Alex Anikiev, PhD, MCP