I was recently in New Zealand speaking to a couple user groups and I presented a “data enrichment” pattern that leveraged Microsoft’s Workflow Services. This Workflow used the BizTalk Adapter Pack to get data out of SQL Server and then used the BizTalk Mapper to produce an enriched output message. In this blog post, I’ll walk through the steps necessary to build such a Workflow. If you’re not familiar with AppFabric Connect, check out the Microsoft product page, or a nice long paper (BizTalk and WF/WCF, Better Together) which actually covers a few things that I show in this post, and also Thiago Almeida’s post on installation considerations.
First off, I’m using Visual Studio 2010 and therefore Workflow Services 4.0. My project is of type WCF Workflow Service Application.
Before actually building a workflow, I want to generate a few bits first. In my scenario, I have a downstream service that accepts a “customer registration” message. I have a SQL Server database with existing customers that I want to match against to see if I can add more information to the “customer registration” message before calling the target service. Therefore, I want a reference both to my database and my target service.
If you have installed the BizTalk Adapter Pack, which exposes SQL Server, Oracle, Siebel and SAP systems as WCF services, then right-clicking the Workflow Service project should show you the option to Add Adapter Service Reference.
After selecting that option, I see the wizard that lets me browse system metadata and generate proxy classes. I chose the sqlBinding and set my security settings, server name and initial database catalog. After connecting to the database, I found my database table (“Customer”) and chose to generate the WF activity to handle the Select operation.
Next, I added a Service Reference to my project and pointed to my target service which has an operation called PublishCustomer.
After this I built my project to make sure that the Workflow Service activities are properly generated. Sure enough, when I open the .xamlx file that represents my Workflow Service, I see the customer activities in the Visual Studio toolbox.
This service is an asynchronous, one-way service, so I removed the “Receive and Send Reply” activities and replaced it with a single Receive activity. But, what about my workflow variables? Let’s create the variables that my Workflow Service needs. The InboundRequest variable points to a WCF data contract that I added to the project. The CustomerServiceRequest variable refers to the Customer object generated by my WCF service reference. Finally, the CustomerDbResponse holds an array of the Customer object generated by the Adapter Service Reference.
With all that in place, let’s flesh out the workflow. The initial Receive activity has an operation called PublishRegistration and uses the InboundRequest variable.
Next up, I have the custom Workflow activity called SelectActivity. This is the one generated by the database reference. It has a series of properties including which columns to bring back (I chose all columns), any query parameters (e.g. a “where” clause) and which variable to put the results in (the CustomerDbResponse).
Now I’m ready to start building the request message for the target service. In used an Assign shape to instantiate the CustomerServiceRequest variable. Then I dragged the Mapper activity that is available if you have AppFabric Connect installed.
When then activity is dropped onto the Workflow surface, we get prompted for what “types” represent the source and destination of the map. The source type is the customer registration that the Workflow initially receives, and the destination is the customer object sent to target service. Now I can view, edit and save the map between these two data types. The Mapper activity comes in handy when you have a significant number of values to map from a source to destination variable and don’t want to have 45 Assign shapes stuffed into the workflow.
Recall that I want to see if this customer is already known to us. If they are not, then there are no results from my database query. To prevent any errors from trying to access a database result that doesn’t exist, I added an If activity that looks to see if there were results from our database query.
Within the Then branch, I extract the values from the first result of the database query. This done through a series of Assign shapes which access the “0” index of the database customer array.
Finally, outside of the previous If block, I added a Persist shape (to protect me against downstream service failures and allow retries from Windows Server AppFabric) and finally, the custom PublishCustomer activity that was created by our WCF service reference.
The result? A pretty clean Workflow that can be invoked as a WCF service. Instead of using BizTalk for scenarios like this, Workflow Services provide a simpler, more lightweight means for doing simple data enrichment solutions. By adding AppFabric Connect and the Mapper activity, in addition to the Persist capability supported by Windows Server AppFabric, you get yourself a pretty viable enterprise solution.
[UPDATE: You can now download the code for this example via this new blog post]
Can you please upload the code that you used for this?
Looking to do so shortly. I’ll update this post with a link to it.
Richard, was it ever determined what the licensing implications were for using the adapter pack without purchasing a production biztalk license? it would be nice to just use the mapper +wf4 (+ optional selected adapters as needed).
Looks like it’s still tied to the BizTalk license (http://www.microsoft.com/biztalk/en/us/adapter-pack.aspx)
Can I ask for favor? I am still trying to learn this, would you tell me the steps to deploy it and test the app?
I’ve updated this post with a link to the source code. Let me know if it makes the solution and its deployment more clear.
Thanks a lot Richard.
Yes it did make a lot more clearer, so basically I deploy Registration Routing and CustomerRegWorkflow in IIS. The only portion i didn’t get yet was where BizTalkBatchProcessing is used in the scenario?
Ah, that was used in another demo that I didn’t mention here. Feel free to ignore 😉