While working on a BizTalk POC last week, I needed to track Business Activity Monitoring (BAM) data across
looping iterations and had to set up relationships between activities. I wanted to share the steps below.
This is the same POC mentioned in my post two days ago. It's
a Change Request scenario where we get a Change Request from SharePoint, and start a workflow to get that Request both approved and
acted upon. The approval notice is sent to multiple individuals, who each approve or deny the Request. So, as you can see, it would be
of great importance to be able to track response time for each approver, accept/deny trends, and so forth. But since the BAM Primary Import
table is fairly flat, how do you track these iterative responses, without resorting to having node/BAM values for "Approver1, Approver1Response,
Approver2, Approver2Response" and so forth?
The first thing to do (after the project has been built) is to create a BAM definition file. I created mine in Excel using the BAM
add-in, and exported the settings to XML. As you see in my file below, I've defined two separate Activities: ProcessNewChangeRequest
and ProcessApprovalResponse. The first is for tracking the greater, parent change request process, and the second is for each
approval response we get back from an individual. After the definition is done, deploy it using the BAM Management Tool (bm.exe).
Next step is go into the orchestration(s) and explicitly populate the BAM data at strategic points. Using the BAM API is the alternate
to use the Tracking Profile Editor (TPE). There's pros and cons for both, and in my case, the flexibility of the API won over the ease of use
of the TPE. Add a reference to the Microsoft.BizTalk.Bam.XLANGs assembly. The orchestration starts like this ...
You need to make a decision from the start as to WHICH of the various BAM streams you wish to use. You can see some nice comparisons of
Basically, Buffered Event Stream collects the data up and publishes it to the BAM service, which in turn
populates the database. The Direct Event Stream goes directly to the Primary Import table, which is slower, but you get notification if
something fails vs. the async nature of the Buffered Event Stream. The Messaging Event Stream is for pipelines, and not used here. The last
choice is the one I used: Orchestration Event Stream. This one commits the data as the orchestration does, is fairly easy to use, and doesn't
require a connection string parameter. It's not documented in the least, but inherits from EventStream and has a similar API.
So, my first BAM Expression Shape starts up the process. The code in the Shape starts with a BeginActivity, which takes in the
name of the Activity (in our case, ProcessNewChangeRequest) and, a unique identifier to mark this instance throughout it's lifetime. I
used the unique RequestID field of my message. After starting the activity, I then executed an UpdateActivity which accepts
the Activity Name, which instance to update (using unique ID), and then list of name/value pairs of data/milestones to update.
I then perform UpdateActivity a couple more times with data acquired at various steps. Next big thing is calling another
orchestration which controls the process loop that receives Approver response messages. So, I do a sync Call Orchestration and
pass in a few messages plus the unique ID, and, get a StatusCode and final message out.
This second orchestration sends out messages for email, and, loops through responses that get returned. The key thing here was to
create a *new* Activity instance for each loop, and tie that back to the original caller. In the loop, I first populate a variable
for a unique ID (that gets reset on each loop), and then have an Expression Shape that does a BeginActivity, passing in the
Activity name (in this case, ProcessApprovalResponse), and the unique ID. I then do an UpdateActivity and pass in values
from our message that came back from an Approver.
At the end of the loop we do two things. First, I called AddRelatedActivity, passing in the current Activity name
(ProcessApprovalResponse) and ID, and then, the parent Activity name (ProcessNewChangeRequest) and the unique ID of the parent
instance (passed in as an orchestration parameter). What does this do? Populates the <activityname>_Relationships table which creates
an association between these activities. Finally, I called EndActivity to close the process. Back in the calling orchestration,
I also call EndActivity when all responses are received and the Change Order process is completed.
So what does the result look like? In the BAM Portal, I can search for various Change Requests ...
If I click on a given row, I'm taken to the Details page. Notice at the bottom, I have two Related Activities. Here's where
we see that association we made from the orchestration!
If I click a RelatedActivity, I get the Details page for that Approval activity, and a link back to my parent process under
So, very nice functionality and reporting, without a whole lotta work. If you're loving this topic, don't forget to check
out Darren Jefford's recent post
and tool for putting a more elegant facade over the BAM API. Enjoy.