BizTalk and WCF, Consuming a WCF Service, Part 3 – Building the BizTalk Solution
The first post looked at the RandomPresent WCF service and looked at design considerations, hosting and testing.
The second post touched on how to consume the WCF service from BizTalk, using the BizTalk WCF Service Consuming Wizard.
The business want to send to each customer, a random Christmas present with their order. To achieve this, the RandomPresent WCF service will be called by BizTalk and it will return a random present XML, wrapped in a SOAP envelope. The present response needs to be appended to the order, so the guys in the warehouse can add the present to the shipment.
It’s a matter of combining the original order and the response from the web service.
I’ll start with an overview of the single orchestration driving this process, since all other artefacts hang off this.
In the end, I created a new orchestration from scratch and didn’t use the one generated for me by the BizTalk WCF Service Consuming Wizard:
I will summarise the flow here and call out some interesting bits!:
- A map on my receive port converts the external format PO to the canonical version (check out my blog post here on the canonical messaging pattern). The canonical message has an element called “Status” that is assigned the value “NEW” in the map. This element is mapped to a property called “POStatus” of type MessageContextPropertyBase. So, as you can guess, I had to create a property schema which I added to my internal schemas project (it contains just this one property). The type MessageContextPropertyBase identifies “POStatus” as a context property that can be written to the context of a message and, as will be discussed, this is what I want to achieve for the purposes of routing and to prevent my orchestration from being caught in an endless activation loop.
- The canonical PO is written to the MessageBox and an instance of the orchestration fires up ; the orchestration subscribes to messages of type canonical PO and also on the “POStatus” promoted property: it is activated when the status is “NEW” only. The reason for this additional subscription on “Status” is because on completion, the orchestration will write the modified canonical PO to the MessageBox and an infinite activation loop will occur if orchestrations are activated only on publishing of a canonical PO message type (not good!). Of course, there are other ways of working around this: I think this is why, in some solutions I have seen, solutions have more than one canonical schema with a different namespace to differentiate them – this seems a mad way of getting around the “activation infinite loop” issue though, since this introduces the overhead of maintaining two canonical schemas and also the design principle of a canonical messaging pattern is that there is only “source of truth”.
- Note that I have designed my orchestration such that it only works with internal solution type messages only (not on the original, external, versions received). This protects the orchestration from changes to the format of the external PO which might require changes and redeployment of the orchestration.
- Next I create a request message for the RandomPresent WCF service… I have created a C# classes project that contains a C# class representation of the request schema: I created the class using Xsd.exe, by pointing Xsd.exe at my schema. I instantiate an instance of the request message in a Construct Message shape using the New keyword. Another way of creating a message in an orchestration is to create a map for this purpose. There is a serious caveat to instantiating a message using the New keyword however: it is vital that changes to the schema are reflected in the class representation (maybe this could be achieved in a Visual Studio “post build event” on the schemas project). As has happened to me in the past, if you assign a message created from your schema (via a map) to an (outdated) message created from a class (e.g. in a Construct Message shape), any missing elements will be silently lost in the output message… For some reason, creating a new message in an orchestration is a torturous process, it seems to me!
- A multipart message map combines the canonical and RandomPresent XML into a new instance of a canonical PO. This map will be discussed further in the “Maps” section below.
- Finally I set the “POStatus” context property to “PROCESSED” in a Message Assignment shape and write the new canonical message to the MessageBox. The final Send Shape initializes a correlation set but not for the purposes of supporting an asynchronous process, but for routing purposes: the correlation set contains just the “POStatus” context property and initializing this in the Send Shape causes the property to become promoted, enabling it to be used for routing. Setting this context property to different statuses on completion of processing is my way of preventing an endless activation loop, as discussed in point 1.
(Note the lack of error handling – this will be the subject of my next post).
The BizTalk WCF Service Consuming Wizard created the necessary schemas for me to communicate with the RandomPresent service however I deleted the RandomPresentService_schemas_microsoft_com_2003_10_Serialization.xsd schema (as discussed in part 2, I haven’t found a use for this schema yet). I also typically rename the service schema filename to something shorter and more descriptive.
If my solution modifies messages and/or involves an orchestration, I create 2 schema projects: an internal schemas project and an external schemas project, as is the case here.
Finally, a quick look at the map used to combine the canonical PO and the RandomPresent XML into a new instance of a canonical PO:
Typically, I use an inline XSLT template in my map for tasks such as these – I find it too frustrating and time consuming using functoids.
As mentioned in this previous blog post, I write my XSLT in a separate file and import it’s contents into my map.
This is the XSLT used:
So I hope you enjoyed this tour. In part 4 of this series, I will show how error handling has been implemented in the solution.
When the solution has been completed, I will make it available for download.