If you ever need to consume a SOAP web service from Dynamics 365 for Finance and Operations, the first step you should take is asking the people responsible for that web service to create a REST version. If that’s not possible this post is for you.
I’ll use this SOAP web service I found online at http://www.dneonline.com/calculator.asmx for the example, it’s a simple service-calculator with four methods to add, substract, multiply or divide two integers.
Consuming a SOAP service in .NET
Let’s start with the basics. How do we consume a SOAP web service in Visual Studio? Easy peasy. Just add a service reference to your project:
And point it to the web service of your choice:
This will add the reference to the project:
With that done we can create an instance of the web service’s client and call one of it’s methods:
3 + 6 = 9, it looks like it’s working.
Consuming a SOAP service in Dynamics 365 for Finance and Operations
To consume the web service on FnO create a new project in Visual Studio, right click on References and add the service reference:
Hmmm… nope, it can’t be done, no service reference option.
Consuming a SOAP service in Dynamics 365 for Finance and Operations (I hope…)
The problem is that we cannot add a service reference in Visual Studio on 365 dev boxes.
What do the docs say about this? Well, like in AX2012 we need to create a .NET class library that will consume that web service, then add the reference to our DLL on 365 and call the service methods from a client object. All right!
There it is. A reference to our class library and a runnable class that will do the job:
Let’s run it!
An exception of type ‘System.
InvalidOperationException’ occurred in System.ServiceModel.dll but was not handled in user code
Additional information: Could not find default endpoint element that references contract ‘AASSOAPCalculatorService.
CalculatorSoap’ in the ServiceModel client configuration section. This might be because no configuration file was found for your application, or because no endpoint element matching this contract could be found in the client element.
Contract? What contract? I know nothing about a contract. Nobody told me about any contract! What does the Wikipedia say about SOAP?
Soap is the term for a salt of a fatty acid or for a variety of cleansing and lubricating products produced from such a substance.
Oops wrong soap…
SOAP provides the Messaging Protocol layer of a web services protocol stack for web services. It is an XML-based protocol consisting of three parts:
an envelope, which defines the message structure and how to process it
a set of encoding rules for expressing instances of application-defined datatypes
a convention for representing procedure calls and responses
The envelope is the contract. A data contract is an agreement between a service and a client that abstractly describes the data to be exchanged. That contract.
Consuming a SOAP service in Dynamics 365 for Finance and Operations (I promise this is the good one)
If we check the class library there’s a file called app.config:
In this file we can see the endpoint the DLL is using. This is fixed (hardcoded) and in case there’s a test endpoint and a production endpoint we should change the address accordingly and have two different DLLs, one for each endpoint. We can also see the data contract being used by the service, the one called AASSOAPCalculatorService.CalculatorSoap. Because #MSDyn365FO is a web-based ERP we could solve this by adding the system.serviceModel node in the web.config file of the server, right? (app.config for desktop apps, web.config for web apps). Yes, but this would be useless as we have no access to the production environment to do this, and it will be impossible to do in the sandbox Tier-2+ environments when the self-service environments start to roll out.
So, what do we do? Easy, ChannelFactory<T> to the rescue! The ChannelFactory<T> allows us to create an instance of the factory for our service contract and then creates a channel between the client and the service. The client being our class in D365and the service the endpoint (obviously).
Then we do the following:
The BasicHttpBinding object can be a BasicHttpsBinding if the web service is running on HTTPS. The endpoint is the URL of the web service. Then we instantiate a service contract from our class with the binding and enpoint and create the channel. Now we can call the web service methods and…
It’s working! And it’s even better, if there’s different endpoints for a test and prod web service we just have to parametrize them!
But really, don’t use SOAP services, go with the REST.