I'm gonna talk about a new feature in Dynamics AX 2009 (Dynamics AX "5.0") which is the really powerful possibility we have now about calling/consuming external Web Services or even WCF Services from our X++ code.
So, in Dynamics AX 4.0, we could execute external Web Services thanks to the AIF outbound web service adapters, but we couldn't really consume those external Web Services from our X++ code... You can read a pretty good posting about that matter (AX 4.0 AIF and external Web Services) here:
But the good news are that in AX "5.0", we are able to consume Web-Services and WCF Services from our X++ code almost like if I were consuming it from Visual Studio and a .NET program!!. 🙂
So, guess the first thing we need to do that..., we need a Web-Service!, or even better, a WCF Service!!. I have developed a pretty simple WCF Service using Visual Studio 2008 (in C#).
It is a basic WCF Service about Stock Exchange, so when I provide a stock company Symbol (like MSFT), it would return the company name (like "Microsoft"). Of course, this Service's business logic is quite dumb, it should access to a database, but in this case I'm checking just about "MSFT" case. But, it is alright as I need any Web Service.
The WCF Service C# code is the following:
|WCF Service Contract Interface:|
|WCF Service Implementation class:|
public class StockExchangeService : IStockExchangeService
I have deployed this WCF Service in a regular IIS Web Server, and tested from a simple .NET WinForms App, just to check it was working ok. If you need help/info about developing and deploying a WCF Service on IIS, take a look at this article:
How to: Host a WCF Service in IIS: http://msdn2.microsoft.com/en-us/library/ms733766.aspx
OK!, so we have our external WCF Service up and running and we want to consume it from our X++ code within Dynamics AX "5.0", right?.
First thing we need to do is to add a WCF Service Reference to AX development environment, just like if we were doing a "Add Service Reference" from Visual Studio. To do so (at least with current BETA AX "5.0" version) we need to go (within AX client) to the menu "Tools-->Development Tools-->Application Integration Framework-->Add Service Reference", then we see a pretty simple window for that purpose:
We have to type in all the WCF service info, basically, the URI address (in my case it was http://dynamicsvpc.contosoent.com/ExternalWCFWebService/StockExchangeService.svc?wsdl) and a Service reference name/namespace I want, like "StockExchangeWcfService". Then, press over "OK" button, and, yes!, we'll have all the proxy artifacts we could need to consume that WCF Service!.
If you want to check about that WCF Service Reference to make sure it has been properly created, you can go to the menu "Basic-->Setup-->Application Integration Framework-->Service References" and you'll see a Window like the following where you can check it:
Yo can even configure the WCF Service when pressing the "Configure Service" button. And guess what is opened up?, yes!, exactly the same WCF Configuration Tool we can use from Visual Studio 2008! :-), from there we could configure WCF client end-points, changing the binding type (by default, in AX "5.0" CTP3, it is using wsHttpBinding binding, so it is secured by default based on Windows security and we have Service authentication and messages Encryption "for granted"), and so on...:
We could use another Binding like "basicHttpBinding" like if it were a basic Web Service (WS-I Basic Profile), etc., but no need to change it now, ok?
If you'd want to change any of those parameters, beware that you should change it first on the WCF Service side, because it has to match with it.
Great!, so it is ready for us, now let's go to the X++ editor and write some code to consume it!.
First of all, we create a X++ class to encapsulate my Service proxy calls, I always like to do it in this way, even in .NET. This kind of classes are called "Service-Agents", so if in the future something about the Service has changed, you should change it just within your "Service Agent" class. That is the purpose of ENCAPSULATION.
This is my X++ "Service Agent" class within AOT:
And my X++ code implementing the GetCompanyNameByStockSymbol():
public static str GeCompanyNameByStockSymbol(str stockSymbol)
// Call the WCF method.
I have highlighted in bold letters the most important code lines, I mean, the WCF Service proxy object variable, when instantiating the WCF Service class and, of course, when calling the "GeCompanyNameByStockSymbol()" Service method.
NOTE: In AX 2009 CTP3, it generated the same public class name that you have in your .NET WCF Service. But in the RTM version (AX 2009 Release), it seems it generates a class with the name of the interface plus the postfix "Client", in this case "IStockExchangeServiceClient" instead "StockExchangeService". Underneath, it is using an internal class which is kind of ".NET WCF Client way", called "StockExchangeServiceClient", but you don't need to use this one.
So, for instance, this is the code I was using in CTP3, you can compare it with the one (up above) that works with AX 2009 Release version (RTM):
// Call the WCF method.
proxy = new StockExchangeWcfService.StockExchangeService();
That's it, really simple!, those are the most important steps we gotta make (beware we have not finished yet... keep on reading... ;-)).
So, just to test our "Service Agent" class, we create a new Job, like the following:
static void CallExternalWcfService(Args _args)
stockSymbol = "MSFT";
And if we just run this Job, guess what... We'll get a cute error!!, something like:
|"Stack trace: Unhandled exception 9 was encountered."|
Yep, not very descriptive, right?. :-), ok, but then, we may get these other errors:
"Clr object is not initialized"
OK, this is because the proxy artifacts (Service Reference) generated by AX "5.0", is using "CLR-Interop" underneath, and therefore, our X++ execution should be made within the AOS Server context. Because of we were calling that class from a Job, by default, it was trying to execute that class within the AX client context instead of the AOS Server context...
So, no problem, let's fix it!, what we gotta do is to specify that our "Service Agent" class should always be executed within the AOS Server. :-). To do so, we just go to the class properties and change the "RunOn" property to "Server", instead of "Called from" (default value) or "Client", which are not right in this case.
And, yeah!, it works now!! 🙂
"Microsoft" is the value returned by my WCF Service when I provide "MSFT" as the stock company Symbol.
Of course, you should try now to consume more complicated WCF Services, like getting data subsets (you'll have to check data conversions, etc.), and so on..