Thursday, November 5, 2015

BizTalk 2010 integrating with SAP using a custom web service instead of the WCF-SAP LOB adapter part 1

There are a lot of experts blogging about interfacing BizTalk with SAP using the WCF-SAP LOB Adapter. Off the top of my head, two come to mind, Sandro Pereira and Kent Weare. They have numerous posts on installing the adapter, configuring the adapter, and receiving/sending XML IDocs.

In this post, I'm going to detail a scenario where we didn't use the BizTalk WCF-SAP LOB Adapter. Instead BizTalk was used to integrate with a custom web service created in SAP to pull information. Part 1 will cover consuming the WSDL and creating the send port. Part 2 will be calling the web service and wrap up.

To start off, I have very little knowledge or experience working in SAP. I primarily rely on an SAP team to understand the inter workings of that system. I make that point to set the stage in that this post is primarily BizTalk related. Creating and configuring SAP to expose a web service is outside the scope of this post.

So why no WCF-SAP LOB Adapter? I actually discussed the options with the SAP team, and together we decided the better option was to try and develop a custom web service on the SAP side. I'll probably get some dissension from the BizTalk community for designing the solution this way, but I'm not going to go into all the details of the reasoning here. Suffice to say, it was the better option for this particular process.

The specific interface I'll discuss is a synchronous web service call from BizTalk to SAP for currency exchange data. Below are the steps I took to get BizTalk configured to interface with a custom SAP web service. I'm including some of the problems that I encountered along the way.

Step 1: Consuming the WSDL

Just like most of the other web services I've worked on, I started off with trying to consume the WSDL provided by the SAP team. From a development perspective, the tool used to consume that WSDL is the "BizTalk WCF Service Consuming Wizard" found in Visual Studio when selecting "Add Generated Items". There are two benefits of using this. The first is to get a working schema of the data being messaged. The second benefit is the binding file that is created by the wizard (I'll discuss this file later on).

One difference from other web service WSDL's I've worked with, a file was provided instead of a URL. No problem, the wizard can handle that:

I then added the WSDL file provided by the SAP team:

After hitting the "next" button, and clicking "Finish", I received the following error:

I have encountered the dreaded "Object reference not set to an instance of an object" error other times when using the BizTalk WCF consuming wizard. If you notice, the wizard expects an .xsd file as well as the .wsdl file. However, if an .xsd file isn't available, how do you get around this issue? In this case, the schema was provided within the wsdl, however, sometimes the targetNamespace in the in the schema record of the wsdl is missing. Sure enough when I opened it up, it was that exact problem:

After inserting a temporary targetNamespace in the .wsdl file and re-running the wizard, it was able to successfully create the .xsd from the WSDL:

Here is an expanded view of the xsd created. Remember, this is a synchronous web service, so there is both a request and response message:

Step 2: Creating the send port

In addition to the xsd, the wizard also creates another resource that is of some use. In particular, the files ending in BindingInfo.xml. These files can be used to generate a configured WCF send port in BizTalk Administrator. In general, I tend to use the file ending in Custom.BindingInfo.xml because it gives you more flexibility in configuring the binding when it is created.

To import the binding file, first open up BizTalk administrator. You can then "right click" on the applicable application you want to import the binding into. This will give you an option to "Import" the "Bindings":

After selecting the correct binding file:

The application should import the appropriate binding information and create the send port. However, in this case, no port was created. So I opened up the zfi_exchange_rate_pull2_Custom.BindingInfo.xml file to see what it contained:

So why is the SendPortCollection record empty? In this case, the BizTalk WCF Service Consuming Wizard must have had some issues with the WSDL file. That means I had to go and create the send port manually. As previously stated, I try to use the WCF-Custom send port whenever possible. Here are some of the steps I took when creating the send port:

To create the send port, I needed some assistance from the WSDL file. Specifically, I looked for the location attribute in the soap:address section of the file:

The location attribute is what you need to use for the address URI property in the send port:

The second property of importance on the send port is the Action property under the SOAP Action header area. That value I pulled from the soap:operation element under the wsdl:operation record of the wsdl:

Here is what the send port looks like with the SOAP Action Header filled:

The last piece to configuring the send port was under the "Binding" tab. When selecting a WCF-Custom Send Port, you need to manually configure the binding as well. The first step is to select the Binding Type. In this instance, I used the "customBinding". In addition, I had to go into the "messageVersion" property under the textMessageEncoding extension and change the value to "Soap11":

All other send port properties I left defaulted. In the next post, I'll explain how I went about testing the web service. I'll also touch on how this interface may impact future design decisions.