Using the BizTalk Server R2 BAM interceptor for WF

For some time now I have been pushing the use of BizTalk BAM outside of BizTalk Server implementations. BizTalk BAM provides a generic interceptor framework to track relevant data on business processes. BizTalk Server is just one of the many products that can leverage that framework in order to add visibility into Business Processes. Finally, with the release of BizTalk R2, Microsoft provides BAM interceptor implementations for WCF and WF. Using those interceptors we can extend the classic BAM features like aggregation, tracking and alerting into generic foundations like WF and WCF.

To utilize BAM with WCF-WF we need to use two main components:

  • bm.exe, an enhanced version of the BAM deployment utility extended to modify interceptor configurations including add, remove, update, and list functionalities.
  • CommonInterceptorConfiguration.xsd, the Common Interceptor Foundation configuration XML schema. At minimum, all interceptor configurations must validate against this schema.

The WF BAM interceptor combines the above mentioned components with a custom tracking service that logs data to the BAMPrimaryImport database. Let’s explore a classic sample. I plan to explain the details of the different components of this example in following posts. Our workflow is a simple State Machine workflow that simulates a PO Process.

 

The observation model for this example was built using the Excel BAM plugin that ships with BizTalk Server. The model contains just one activity and a set of dimensions for further aggregation in the generated OLAP cubes.  The following is the XML generated by the Excel plugin.

<?xml version="1.0" encoding="UTF-16"?>

<BAMDefinition xmlns="http://schemas.microsoft.com/BizTalkServer/2004/10/BAM">

                    <Activity Name="POActivity" ID="IDD38284A4F64745409E88DC7BF608D414">

                                          <Checkpoint Name="Item" ID="IDF57663E311524757851437C1D9B8A183" DataType="NVARCHAR" DataLength="500"/>

                                          <Checkpoint Name="Quantity" ID="IDADEABF22B6C6416789C3ADF2D4CD2E59" DataType="INT"/>

                                          <Checkpoint Name="Received" ID="IDED14A7F26EC7477DA4ED63B8C08CBB86" DataType="DATETIME"/>

                                          <Checkpoint Name="Approved" ID="IDC1BADE06C3B04AC99BDDF544E84033BB" DataType="DATETIME"/>

                                          <Checkpoint Name="Shipped" ID="ID20C1465442184553929AB6B0EE49796C" DataType="DATETIME"/>

                                          <Checkpoint Name="Denied" ID="IDE88C30D7ADE5440B8F19191C288D6D74" DataType="DATETIME"/>

                    </Activity>

                    <View Name="POView" ID="IDDCA141B0E6E94D879B04CF6C4E8ED62A">

                                          <ActivityView Name="ViewPOActivity" ID="IDB0C4AA0BE204425590FB1704829D6E9F" ActivityRef="IDD38284A4F64745409E88DC7BF608D414">

                                                              <Alias Name="Approved" ID="ID6CF7A7B9BB4140218259616AA698587D">

                                                                                  <CheckpointRef>IDC1BADE06C3B04AC99BDDF544E84033BB</CheckpointRef>

                                                              </Alias>

                                                              <Alias Name="Denied" ID="ID4B6715A4FF434D61AD6B55B62DCE80EE">

                                                                                  <CheckpointRef>IDE88C30D7ADE5440B8F19191C288D6D74</CheckpointRef>

                                                              </Alias>

                                                              <Alias Name="Item" ID="IDAB2C1362300142B884A6F567D5AEEFDB">

                                                                                  <CheckpointRef>IDF57663E311524757851437C1D9B8A183</CheckpointRef>

                                                              </Alias>

                                                              <Alias Name="Quantity" ID="IDCE258F95A63B4177B383FC83F7923A1A">

                                                                                  <CheckpointRef>IDADEABF22B6C6416789C3ADF2D4CD2E59</CheckpointRef>

                                                              </Alias>

                                                              <Alias Name="Received" ID="ID6C75FDA099DE462EB145ABF00CA2AE4D">

                                                                                  <CheckpointRef>IDED14A7F26EC7477DA4ED63B8C08CBB86</CheckpointRef>

                                                              </Alias>

                                                              <Alias Name="Shipped" ID="IDE59DA0F05E7A428DA444CD2ACFA75ABE">

                                                                                  <CheckpointRef>ID20C1465442184553929AB6B0EE49796C</CheckpointRef>

                                                              </Alias>

                                          </ActivityView>

                    </View>

                    <Cube Name="POView" ID="ID1C2CF921025A47AC96A2F3382168FB08" CreateOlapCube="false" ActivityViewRef="IDB0C4AA0BE204425590FB1704829D6E9F">

                                          <Measure Name="TotalReceived" ID="ID04E27CBA4B2F4813B45BA59C3EA0BC2D" AliasRef="IDCE258F95A63B4177B383FC83F7923A1A" AggregationFunction="Sum"/>

                                          <Measure Name="TotalApproved" ID="ID915659F57AB9462BAE0E037F76CF2DF6" AliasRef="IDCE258F95A63B4177B383FC83F7923A1A" AggregationFunction="Sum"/>

                                          <TimeDimension Name="ApprovedDim" ID="ID97905E2E89734CBCA0169AC06934BE1B" TimeStampAliasRef="ID6CF7A7B9BB4140218259616AA698587D">

                                                              <TimeLevel>Year</TimeLevel>

                                                              <TimeLevel>Quarter</TimeLevel>

                                                              <TimeLevel>Month</TimeLevel>

                                          </TimeDimension>

                                          <TimeDimension Name="ReceivedDim" ID="ID61B667B6CF9F4409900B4F49EC3B6033" TimeStampAliasRef="ID6C75FDA099DE462EB145ABF00CA2AE4D">

                                                              <TimeLevel>Year</TimeLevel>

                                                              <TimeLevel>Quarter</TimeLevel>

                                                              <TimeLevel>Month</TimeLevel>

                                          </TimeDimension>

                    </Cube>

                    <Extension>

                                          <OWC xmlns:x="urn:schemas-microsoft-com:office:excel">

                                                             

                                          </OWC>

                    </Extension>

</BAMDefinition>

After generating this XML file, the next step is to deploy the observation model using the following syntax:

< installation path >\Program Files\Microsoft BizTalk Server 2006\Tracking\BM.exe deploy-all -definitionfile:< definitionfile.xml >

Once the bm.exe is completed, we need to create the interceptor configuration file which states how to map specific Workflow events and properties to BAM activities. Watch for more details about WF interceptor files in future postings. The interceptor configuration file for our example looks like the following.

<?xml version="1.0" encoding="utf-8" ?>

<ic:InterceptorConfiguration xmlns:ic="http://schemas.microsoft.com/BizTalkServer/2004/10/BAM/InterceptorConfiguration" xmlns:wf="http://schemas.microsoft.com/BizTalkServer/2004/10/BAM/WorkflowInterceptorConfiguration">

<ic:EventSource Name="Workflow1" Technology="WF" Manifest="StPO.Workflow1, StPO, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"/>

                    <ic:BamActivity Name="POActivity">

                                          <!--Workflow Initiated-->

                                          <ic:OnEvent Name="MyWorkflowEvent" Source="Workflow1" IsBegin="true">

                                                              <ic:Filter>

                                                                                    <ic:Expression>

                                                                                                        <wf:Operation Name="GetWorkflowEvent" />

                                                                                                        <ic:Operation Name="Constant">

                                                                                                                              <ic:Argument>Created</ic:Argument>

                                                                                                        </ic:Operation>

                                                                                                        <ic:Operation Name="Equals" />

                                                                                    </ic:Expression>

                                                              </ic:Filter>

                                                              <ic:CorrelationID>

                                                                                    <ic:Expression>

                                                                                                        <wf:Operation Name="GetContextProperty">

                                                                                                                              <wf:Argument>InstanceId</wf:Argument>

                                                                                                        </wf:Operation>

                                                                                  </ic:Expression>

                                                              </ic:CorrelationID>

                                                              <ic:Update DataItemName="Received" Type="DATETIME">

                                                                                    <ic:Expression>

                                                                                                        <wf:Operation Name="GetContextProperty">

                                                                                                                              <wf:Argument>EventTime</wf:Argument>

                                                                                                        </wf:Operation>

                                                                                    </ic:Expression>

                                                              </ic:Update>

                                          </ic:OnEvent>

                                          <!--PO Received...-->

                                          <ic:OnEvent Name="POReceived"  Source="Workflow1">

                                                              <ic:Filter>

                                                                                    <ic:Expression>

                                                                                                        <wf:Operation Name="GetActivityName" />

                                                                                                        <ic:Operation Name="Constant">

                                                                                                                              <ic:Argument>OrderReceived</ic:Argument>

                                                                                                        </ic:Operation>

                                                                                                        <ic:Operation Name="Equals" />

                                                                                    </ic:Expression>

                                                              </ic:Filter>

                                                              <ic:CorrelationID>

                                                                                    <ic:Expression>

                                                                                                        <wf:Operation Name="GetContextProperty">

                                                                                                                              <wf:Argument>InstanceId</wf:Argument>

                                                                                                        </wf:Operation>

                                                                                    </ic:Expression>

                                                              </ic:CorrelationID>

                                                              <ic:Update DataItemName="Quantity" Type="INT">

                                                                                    <ic:Expression>

                                                                                                        <wf:Operation Name="GetWorkflowProperty">

                                                                                                                              <wf:Argument>Quantity</wf:Argument>

                                                                                                        </wf:Operation>

                                                                                    </ic:Expression>

                                                              </ic:Update>

                                                              <ic:Update DataItemName="Item" Type="NVARCHAR">

                                                                                    <ic:Expression>

                                                                                                        <wf:Operation Name="GetWorkflowProperty">

                                                                                                                              <wf:Argument>ItemName</wf:Argument>

                                                                                                        </wf:Operation>

                                                                                    </ic:Expression>

                                                              </ic:Update>

                                          </ic:OnEvent>

                                          <ic:OnEvent Name="POApproved"  Source="Workflow1">

                                                              <ic:Filter>

                                                                                    <ic:Expression>

                                                                                                        <wf:Operation Name="GetActivityName" />

                                                                                                        <ic:Operation Name="Constant">

                                                                                                                              <ic:Argument>POApproved</ic:Argument>

                                                                                                        </ic:Operation>

                                                                                                        <ic:Operation Name="Equals" />

                                                                                    </ic:Expression>

                                                              </ic:Filter>

                                                              <ic:CorrelationID>

                                                                                    <ic:Expression>

                                                                                                        <wf:Operation Name="GetContextProperty">

                                                                                                                              <wf:Argument>InstanceId</wf:Argument>

                                                                                                        </wf:Operation>

                                                                                    </ic:Expression>

                                                              </ic:CorrelationID>

                                                              <ic:Update DataItemName="Approved" Type="DATETIME">

                                                                                    <ic:Expression>

                                                                                                        <wf:Operation Name="GetContextProperty">

                                                                                                                              <wf:Argument>EventTime</wf:Argument>

                                                                                                        </wf:Operation>

                                                                                    </ic:Expression>

                                                              </ic:Update>

                                          </ic:OnEvent>

                                          <ic:OnEvent Name="POShipped"  Source="Workflow1">

                                                              <ic:Filter>

                                                                                    <ic:Expression>

                                                                                                        <wf:Operation Name="GetActivityName" />

                                                                                                        <ic:Operation Name="Constant">

                                                                                                                              <ic:Argument>POShipped</ic:Argument>

                                                                                                        </ic:Operation>

                                                                                                        <ic:Operation Name="Equals" />

                                                                                    </ic:Expression>

                                                              </ic:Filter>

                                                              <ic:CorrelationID>

                                                                                    <ic:Expression>

                                                                                                        <wf:Operation Name="GetContextProperty">

                                                                                                                              <wf:Argument>InstanceId</wf:Argument>

                                                                                                        </wf:Operation>

                                                                                    </ic:Expression>

                                                              </ic:CorrelationID>

                                                              <ic:Update DataItemName="Shipped" Type="DATETIME">

                                                                                  <ic:Expression>

                                                                                                        <wf:Operation Name="GetContextProperty">

                                                                                                                              <wf:Argument>EventTime</wf:Argument>

                                                                                                        </wf:Operation>

                                                                                    </ic:Expression>

                                                              </ic:Update>

                                          </ic:OnEvent>

                                          <ic:OnEvent Name="PODenied"  Source="Workflow1">

                                                              <ic:Filter>

                                                                                    <ic:Expression>

                                                                                                        <wf:Operation Name="GetActivityName" />

                                                                                                        <ic:Operation Name="Constant">

                                                                                                                              <ic:Argument>PODenied</ic:Argument>

                                                                                                        </ic:Operation>

                                                                                                        <ic:Operation Name="Equals" />

                                                                                    </ic:Expression>

                                                              </ic:Filter>

                                                              <ic:CorrelationID>

                                                                                    <ic:Expression>

                                                                                                        <wf:Operation Name="GetContextProperty">

                                                                                                                              <wf:Argument>InstanceId</wf:Argument>

                                                                                                        </wf:Operation>

                                                                                    </ic:Expression>

                                                              </ic:CorrelationID>

                                                              <ic:Update DataItemName="Denied" Type="DATETIME">

                                                                                    <ic:Expression>

                                                                                                        <wf:Operation Name="GetContextProperty">

                                                                                                                              <wf:Argument>EventTime</wf:Argument>

                                                                                                        </wf:Operation>

                                                                                    </ic:Expression>

                                                              </ic:Update>

                                          </ic:OnEvent>

                    </ic:BamActivity>

</ic:InterceptorConfiguration>

After that we need to deploy the interceptor file using one of the enhancements to the bm.exe tool.

< installation path >\Program Files\Microsoft BizTalk Server 2006\Tracking\BM.exe deploy-interceptor -filename:< icfile.xml >

The final and most important step is to add the BAM tracking service to the WF runtime. The following shows the required code which must be added to the WF host.  The additional code is highlighted below.


using System.Threading;

using System.Workflow.Runtime;

using System.Workflow.Runtime.Hosting;

using Microsoft.BizTalk.Bam.Interceptors.Workflow;

#endregion

namespace StPO

{

            class Program

              {

                            static void Main(string[] args)

                            {

                                          using(WorkflowRuntime workflowRuntime = new WorkflowRuntime())

                                          {

                                                        AutoResetEvent waitHandle = new AutoResetEvent(false);

                                                        System.Collections.Specialized.NameValueCollection serviceParams= new System.Collections.Specialized.NameValueCollection();

                                                        serviceParams.Add("InterceptorConfigurationPollingInterval", "5");

                                                        serviceParams.Add("ConnectionString", "Integrated Security=SSPI;Data Source=.;Initial Catalog=BAMPrimaryImport");

                                                        workflowRuntime.AddService(new BamTrackingService(serviceParams));

CODE…

                                          }

                            }

              }

}

While running the workflow, the data gets saved into the BAMPrimaryImport database and aggregated in OLAP representations. At this point we can use some of the existing BAM end-user tool to get a real-time representation of the workflow activity. The following figure shows a view of the BAM Portal rendering the views of the observation model of our target workflow.



The source code for this example will be available on www.AdapterWorx.com in the next few days.

6 Comments

  • Very nice post. I think the method you describe is a good one for instrumenting WF with BAM. I had hopes that the Tracking Profile Editor would be extended to work with non-BizTalk sources like WF. But this is still very workable. Great article!

  • Great post my friend,

  • Gr8 post.
    Can we adopt the same procedure for WCF Interceptor? If not explain for WCF Interceptor also.

    Thanks
    Vidyakumar.naarumanchi
    MCTS-BizTalk 2006

  • I followed your steps and created a sample Interceptor Configuration File(IC). When i try to deploy the same using Command Promt , it is throwing the error.
    Here are the steps i followed while deploying the Interceptor Configuration File.

    1) Created IC file

    2) from Visual Studio Commant prompt went to the path

    C:\Program Files\Microsoft BizTalk Server 2006\Tracking\BM.exe deploy-interceptor -filename: (Ajduster is my IC file name)

    and then i press Enter...it is showing an error stating that "unknown Command for Bm.exe" and giving some help...when i googled it i came to know that this is because "Bm.exe tool does't have the enhancement for handelling interceptor Configuration file".....

    Am i going wrong

    I'm using Visual studio 2005, Sql Server 2005 , BizTalk Server 2006R2 with all latest service packs.

    Please help me and let me know the why one can deploy the interceptor Configuration file. Do i need to do some more configurations in the WCF Adapter also?"

    Any help will be greatly appreciated .

    thanks

    Vidyakumar.naarumanchi

    MCTS-BizTalk 2006

  • Hey Jesus, Very nice article. How would you go about adding the BamInterceptor service to a WF host whose creation you don't have control over such as that running from within Sharepoint Services 2007?

  • Can you please post the source code link, if it is available?

    Thanks

Comments have been disabled for this content.