I have seen a lot of people confused with the SOAP Action Headers section in WCF Send ports. Their purpose isn’t obvious to those who don’t fully understand BizTalk’s implementation of WCF, or of the WCF based LOB Adapters. In this post I will try to explain what the SOAP Action Headers section is used for and why it is important when calling vanilla WCF services as well as calling on LOB systems which take advantage of adapters that have been built using the WCF LOB Adapter SDK.
First of all, let’s try to understand how a WCF service generates its SOAP Action with a simple example. Open Visual Studio and create a new WCF Service Application project which will create a base template for a WCF Service. This service contains two operations called GetData and GetDataUsingDataContract. Let’s deploy this application to IIS (in a quick and dirty fashion because us developers are lazy) so that we can inspect the SOAP Actions. Right click on the project and choose properties, click on the web tab and choose “Use Local IIS Web Server” and click “Create Virtual Directory”. This effectively creates a virtual directory in IIS using your Visual Studio solution’s build folder for the physical folder location of the web application.
If we now browse to the service and to the wsdl, we will see that the Soap Action value appears to be an amalgamation of the namespace of the service, the name of the interface, and the name of the operations (in this case, the name of the method).
Let’s start playing around a little bit. Let’s change the [ServiceContract] attribute decorating our interface class in the IService.cs file such that it says [ServiceContract(Namespace=http://test.com)] instead. If we rebuilt the project and browse to the wsdl instead we will see the Soap Actions have changed to take the new namespace into account
Let’s take this example a bit further and change the name of the interface from IService1 to ITest. After rebuilding the project, you’ll notice that the wsdl takes that into account as well.
Now for the real important part. What if we wanted to take advantage of C#’s facility to override methods, thus having multiple methods with the same name but with different combinations of request and return types? For the sake of this example, let’s rename the GetDataUsingDataContract method to be called GetData as well and let’s try to build the project. If you try to browse to the wsdl now you will get an error saying “Cannot have two operations in the same contract with the same name, methods GetData and GetData in type WcfService1.ITest violate this rule. You can change the name of one of the operations by changing the method name or by using the Name property of OperationContractAttribute“. Let’s do exactly as the error message suggests and choose to change the operation name on the second GetData method, while leaving the method name intact. We do this by changing the [OperationContract] attribute decorating the second GetData method such that it says [OperationContract(Name=“GetDataUsingDataContract”)] instead. After rebuilding you’ll notice that the wsdl looks exactly like it did in the previous image.
The major takeaway from this is that the Soap Action is an amalgamation of the Namespace property on the ServiceContract attribute decorating the interface class which can be overridden from the default value, the name of the interface itself, and the operation name which defaults it’s value from the method name but can be easily overridden. Thus the Soap Action is an instruction that needs to be passed to the web service application that informs it which method needs to be exercised.
You will have noticed that Microsoft has built a few BizTalk adapters using the WCF framework such as the WCF-SQL adapter and in fact provided the WCF LOB Adapter SDK which allows developers to build their own custom adapters for LOB systems based on the WCF framework. There are some commonalities between all the adapters built on this framework. One is that the SOAP Action can be used to instruct the LOB system what method or operation should be called upon within the target system. Each adapter will actually generate and utilize the SOAP Action value in a slightly different way since the target system’s might not necessarily be SOAP based, but the basic idea is the same as for Vanilla WCF Services in that the SOAP Action is used to instruct the target system which method needs to be exercised.
Back to a real life example, let’s continue using the web service which we have created. Add a new BizTalk project to your solution and do your normal setup tasks (assign a strong named key, set the application name etc…). Right click on the project and choose to Add Generated Items, and then to Consume WCF Service. Choose to use a Metadata Endpoint and paste in the address of the wsdl for the service you have created, and click through the rest of the wizard. You’ll notice that quite a few outputs have been created, including two binding files, one with the word custom in it. Let’s open the BizTalk Administration Console, create an application and import one of the binding files into that application. You should now have a WCF-BasicHTTP based send port (or WCF-Custom if you chose the custom binding file), and if you click on the configure button you will see the below section on the adapter configuration page.
We now have an understanding of what the Soap Action is, and it is very clear that the Action attribute in the SOAP Action Header section reflects the SOAP Actions that were mentioned in our WSDL. What is this section of the configuration page actually used for? It is basically used to say that if a message received by the send port has a BTS.Operation context property value matching one of the Operation Name attributes, then the WCF.Action context property against the message should be set to the corresponding Operation Action attribute.
This seems like a pretty long-winded way to set the WCF.Action property, why shouldn’t you just set that directly in the first place rather than setting the BTS.Operation property? The primary reason for this is decoupling and separation on concerns. The idea is that according to best practice orchestrations should have no idea what transports their logical send ports correspond to, thus setting a property such as WCF.Action would be crossing that line. However setting a property such as BTS.Operation which isn’t transport specific isn’t quite so bad. In fact, every single time you send a message out of your orchestration via a logical send port, you are actually setting the BTS.Operation property against that message to the name of the operation on your logical send port.
So the SOAP Action Header section is really used to map operation names on your orchestration logical send ports to a corresponding SOAP Action so that the transport knows what method it should exercise. It is altogether possible that you might have multiple operations names specified in this section which resolve to the same SOAP Action as different orchestrations might make use of different logical ports and thus have different operation names yet might still want to make use of the same send port.
Another way around this is to remove all the data in the SOAP Action Header section of the configuration page, and instead replace the text with a single SOAP Action value with no surrounding XML tags. What this effectively does is stamp all messages going through this send port with a WCF.Action property value based on that single SOAP Action. You could potentially have multiple send ports, each pointing to the same web service URL but supporting different SOAP Actions and direct relevant messages to the relevant send ports instead.
It is also possible that in a messaging solution you might want to directly set the WCF.Action property in a pipeline component rather than rely on mapping of BTS.Operation to resolve a WCF.Action.
The major takeaway from this is that the SOAP Actions are used to abstract the web service’s operations from it’s implemented methods names and to cater for overriding, and likewise the SOAP Action Header section in the WCF Send ports configuration is used to provide a method of resolving the required SOAP Action without requiring orchestrations to have intrinsic knowledge about what type of transport their logical send ports are to be bound to.