BAM Activity in Custom Pipeline

Sometimes requirement cannot be fulfil by using tracking profile editor for BAM logging. Here in this code I am explaining about how to use BAM in custom pipeline. And also I am using EnableContinuation method so that we can get all the details in single row in BAM table while using different stage of BAM tracking in BizTalk application. When a solution needs BAM, and you what to link the receivedTime and sendTime together you have to use continuation.

Code for BAM Activity in Custom Pipeline:

Begin BAM Activity

This custom pipeline component can be put after xml or flat dissembler pipeline component in Receive Pipeline, because we are consuming MessageType context property to log into BAM.

For creating BAM Definition Activity please click here

https://vkbiztalk.com/2017/06/14/implementation-of-bam-activity-definition-file/

 

using System;

using System.IO;

using System.Text;

using System.Drawing;

using System.Resources;

using System.Reflection;

using System.Diagnostics;

using System.Collections;

using System.ComponentModel;

using Microsoft.BizTalk.Message.Interop;

using Microsoft.BizTalk.Component.Interop;

using Microsoft.BizTalk.Component;

using Microsoft.BizTalk.Messaging;

using System.IO;

using System.Xml;

using Microsoft.BizTalk.Bam.EventObservation;

namespace BeginBAMPipeline

{

[ComponentCategory(CategoryTypes.CATID_PipelineComponent)]

[ComponentCategory(CategoryTypes.CATID_Any)]

[System.Runtime.InteropServices.Guid(“3BB6433B-CF8D-456B-AA78-70D6788C8574”)]

public class BeginBAMPipelineComponent : IBaseComponent, IComponentUI, Microsoft.BizTalk.Component.Interop.IComponent, IPersistPropertyBag

{

#region Configuration Properties

private string _BAMActivityName;

private bool _IsTrackingRequire;

public string BAMActivityName

{

get

{

return _BAMActivityName;

}

set

{

_BAMActivityName = value;

}

}

 

public bool IsTrackingRequire

{

get

{

return _IsTrackingRequire;

}

set

{

_IsTrackingRequire = value;

}

}

 

#endregion

public string Description

{

get

{

return “Pipeline component For Begin BAM Activity”;

}

}

 

public string Name

{

get

{

return “BeginBAMPipelineComponent”;

}

}

public string Version

{

get

{

return “1.0.0.0”;

}

}

public IntPtr Icon

{

get

{

return new System.IntPtr();

}

}

public System.Collections.IEnumerator Validate(object projectSystem)

{

return null;

}

public void GetClassID(out Guid classID)

{

classID = new Guid(“3BB6433B-CF8D-456B-AA78-70D6788C8574”);

}

public void InitNew()

{

}

public virtual void Load(Microsoft.BizTalk.Component.Interop.IPropertyBag pb, int errlog)

{

object val = null;

val = this.ReadPropertyBag(pb, “BAMActivityName”);

if ((val != null))

{

this._BAMActivityName = ((string)(val));

}

val = this.ReadPropertyBag(pb, “IsTrackingRequire”);

if ((val != null))

{

this._IsTrackingRequire = ((bool)(val));

}

}

public virtual void Save(Microsoft.BizTalk.Component.Interop.IPropertyBag pb, bool fClearDirty, bool fSaveAllProperties)

{

this.WritePropertyBag(pb, “BAMActivityName”, this.BAMActivityName);

this.WritePropertyBag(pb, “IsTrackingRequire”, this.IsTrackingRequire);

}

#region utility functionality

/// <summary>

/// Reads property value from property bag

/// </summary>

/// <param name=”pb”>Property bag</param>

/// <param name=”propName”>Name of property</param>

/// <returns>Value of the property</returns>

private object ReadPropertyBag(Microsoft.BizTalk.Component.Interop.IPropertyBag pb, string propName)

{

object val = null;

try

{

pb.Read(propName, out val, 0);

}

catch (System.ArgumentException)

{

return val;

}

catch (System.Exception e)

{

throw new System.ApplicationException(e.Message);

}

return val;

}

 

/// <summary>

/// Writes property values into a property bag.

/// </summary>

/// <param name=”pb”>Property bag.</param>

/// <param name=”propName”>Name of property.</param>

/// <param name=”val”>Value of property.</param>

private void WritePropertyBag(Microsoft.BizTalk.Component.Interop.IPropertyBag pb, string propName, object val)

{

try

{

pb.Write(propName, ref val);

}

catch (System.Exception e)

{

throw new System.ApplicationException(e.Message);

}

}

#endregion

public IBaseMessage Execute(IPipelineContext pContext, IBaseMessage pInMsg)

{

IBaseMessagePart bodyPart = pInMsg.BodyPart;

StringBuilder outputMessageText = null;

XmlDocument xDoc = new XmlDocument();

 

string systemPropertiesNamespace = @”http://schemas.microsoft.com/BizTalk/2003/system-properties&#8221;;

//string messageType = “”;

if (bodyPart != null)

{

if (IsTrackingRequire)

{

Stream originalStream = bodyPart.GetOriginalDataStream();

 

if (originalStream != null)

{

string ActivityName = BAMActivityName;

string messageType = Convert.ToString(pInMsg.Context.Read(“MessageType”, systemPropertiesNamespace));

 

EventStream BAMes;

 

BAMes = pContext.GetEventStream();

 

string ActivityID = Guid.NewGuid().ToString();

string corelationToken = (string)pInMsg.Context.Read(“InterchangeID”, “http://schemas.microsoft.com/BizTalk/2003/system-properties&#8221;);

 

System.Diagnostics.EventLog.WriteEntry(“InterchangeIDStart”, corelationToken);

BAMes.BeginActivity(ActivityName, ActivityID);

BAMes.UpdateActivity(ActivityName, ActivityID, “MessageType”, messageType);

BAMes.UpdateActivity(ActivityName, ActivityID, “StartTime”, DateTime.Now);

 

BAMes.UpdateActivity(ActivityName, ActivityID, “Status”, “START”);

 

BAMes.EnableContinuation(ActivityName, ActivityID, corelationToken);

 

BAMes.EndActivity(ActivityName, ActivityID);

 

BAMes.Flush();

}

}

}

return pInMsg;

}

}

}

END Bam Activity:

This custom pipeline component can be used in any stage at in send pipeline.

using System;

using System.IO;

using System.Text;

using System.Drawing;

using System.Resources;

using System.Reflection;

using System.Diagnostics;

using System.Collections;

using System.ComponentModel;

using Microsoft.BizTalk.Message.Interop;

using Microsoft.BizTalk.Component.Interop;

using Microsoft.BizTalk.Component;

using Microsoft.BizTalk.Messaging;

using System.IO;

using System.Xml;

using Microsoft.BizTalk.Bam.EventObservation;

 

 

namespace EndBAMPipeline

{

[ComponentCategory(CategoryTypes.CATID_PipelineComponent)]

 

[ComponentCategory(CategoryTypes.CATID_Any)]

 

[System.Runtime.InteropServices.Guid(“3AC1B310-C4DF-4732-8AA9-2808349CEFFA”)]

public class EndBAMComponent : IBaseComponent, IComponentUI, Microsoft.BizTalk.Component.Interop.IComponent, IPersistPropertyBag

{

#region Configuration Properties

private string _BAMActivityName;

private bool _IsTrackingRequire;

 

public string BAMActivityName

{

get

{

return _BAMActivityName;

}

set

{

_BAMActivityName = value;

}

}

 

public bool IsTrackingRequire

{

get

{

return _IsTrackingRequire;

}

set

{

_IsTrackingRequire = value;

}

}

#endregion

 

#region IBaseComponent members

public string Description

{

get

{

return “Pipeline component For End BAM Activity”;

}

}

 

public string Name

{

get

{

return “EndBAMPipelineComponent”;

}

}

public string Version

{

get

{

return “1.0.0.0”;

 

}

 

}

#endregion

 

public IntPtr Icon

{

get

{

return new System.IntPtr();

 

}

}

public System.Collections.IEnumerator Validate(object projectSystem)

{

return null;

}

 

#region IPersistPropertyBag members

public void GetClassID(out Guid classID)

{

classID = new Guid(“3AC1B310-C4DF-4732-8AA9-2808349CEFFA”);

}

public void InitNew()

{

}

public virtual void Load(Microsoft.BizTalk.Component.Interop.IPropertyBag pb, int errlog)

{

object val = null;

val = this.ReadPropertyBag(pb, “BAMActivityName”);

if ((val != null))

{

this._BAMActivityName = ((string)(val));

}

val = this.ReadPropertyBag(pb, “IsTrackingRequire”);

if ((val != null))

{

this._IsTrackingRequire = ((bool)(val));

}

}

public virtual void Save(Microsoft.BizTalk.Component.Interop.IPropertyBag pb, bool fClearDirty, bool fSaveAllProperties)

{

this.WritePropertyBag(pb, “BAMActivityName”, this.BAMActivityName);

this.WritePropertyBag(pb, “IsTrackingRequire”, this.IsTrackingRequire);

 

}

#endregion

 

#region utility functionality

/// <summary>

/// Reads property value from property bag

/// </summary>

/// <param name=”pb”>Property bag</param>

/// <param name=”propName”>Name of property</param>

/// <returns>Value of the property</returns>

private object ReadPropertyBag(Microsoft.BizTalk.Component.Interop.IPropertyBag pb, string propName)

{

object val = null;

try

{

pb.Read(propName, out val, 0);

}

catch (System.ArgumentException)

{

return val;

}

catch (System.Exception e)

{

throw new System.ApplicationException(e.Message);

}

return val;

}

 

/// <summary>

/// Writes property values into a property bag.

/// </summary>

/// <param name=”pb”>Property bag.</param>

/// <param name=”propName”>Name of property.</param>

/// <param name=”val”>Value of property.</param>

private void WritePropertyBag(Microsoft.BizTalk.Component.Interop.IPropertyBag pb, string propName, object val)

{

try

{

pb.Write(propName, ref val);

}

catch (System.Exception e)

{

throw new System.ApplicationException(e.Message);

}

}

#endregion

public IBaseMessage Execute(IPipelineContext pContext, IBaseMessage pInMsg)

{

IBaseMessagePart bodyPart = pInMsg.BodyPart;

StringBuilder outputMessageText = null;

string systemPropertiesNamespace = @”http://schemas.microsoft.com/BizTalk/2003/system-properties&#8221;;

if (bodyPart != null)

{

if (IsTrackingRequire)

{

Stream originalStream = bodyPart.GetOriginalDataStream();

if (originalStream != null)

{

string ActivityName = BAMActivityName;

string messageType = Convert.ToString(pInMsg.Context.Read(“MessageType”, systemPropertiesNamespace));

EventStream BAMes;

BAMes = pContext.GetEventStream();

string ActivityID = “seq_” + Guid.NewGuid().ToString();

string corelationToken = (string)pInMsg.Context.Read(“InterchangeID”, “http://schemas.microsoft.com/BizTalk/2003/system-properties&#8221;);

System.Diagnostics.EventLog.WriteEntry(“InterchangeIDEND”, corelationToken);

BAMes.UpdateActivity(ActivityName, corelationToken, “EndTime”, DateTime.Now);

BAMes.UpdateActivity(ActivityName, corelationToken, “Status”, “SUCCESS”);

BAMes.EndActivity(ActivityName, corelationToken);

BAMes.Flush();

}

}

}

return pInMsg;

}

}

}

 

You can see the BAM table or BAM Portal in one row start time and end time of message in BizTalk along with status and messagetype.

Advertisements

BAM in Custom Pipeline

In BizTalk, BAM can be applied on pipeline level and in orchestration. Here we are going to implement BAM in BizTalk through BAM API programming.

For more details of BAM APIs, you can refer to

https://vkbiztalk.wordpress.com/2017/07/17/bam-api/

Normally for BAM Programming below three functions are required under EventStream class.

  • BeginActivity
  • UpdateActivity
  • EndActivity

But if you want some more advance feature in BAM tracking then you can refer below reference:

https://msdn.microsoft.com/en-us/library/microsoft.biztalk.bam.eventobservation.eventstream.aspx

Click on below link for example of BAM activity in custom pipeline

https://vkbiztalk.com/2018/02/25/bam-activity-in-custom-pipeline/

Normally, we write the code to produce BAM events in the Execute method of the pipeline component.

The pipeline context has a GetEventStream method that returns a MessagingEventStream.

Requirements:

Dlls:

  • BizTalk.Bam.EventObservation.dll
  • BizTalk.ExplorerOM
  • BizTalk.Pipeline
  • BizTalk.Streaming

Namespaces:

  • usingBizTalk.Bam.EventObservation;
  • usingBizTalk.Message.Interop;
  • usingBizTalk.Component.Interop;
  • usingBizTalk.Streaming;
  • usingBizTalk.ExplorerOM;

Example:

public Microsoft.BizTalk.Message.Interop.IBaseMessage Execute(Microsoft.BizTalk.Component.Interop.IPipelineContext context, Microsoft.BizTalk.Message.Interop.IBaseMessage inMsg)

{

      EventStream BAMes;

BAMes = context.GetEventStream();

string ActivityID; // it can be a GUID

String operation; // message context properties or any custom value to track in BAM

BAMes.BeginActivity(ActivityName, ActivityID);

BAMes.UpdateActivity(ActivityName, ActivityID, “Data”, operation);

BAMes.EndActivity(ActivityName, ActivityID);

BAMes.Flush();

}

Here ActivityName: BAM Definition File Name

ActivityID: It can be a GUID or any unique id

UpdateActivity function:

public virtual void UpdateActivity( string activityName, string activityInstance,                   params object[] data )

In Update activity, after first two parameters, data items are next parameters which are defined in key value pairs.

These data items can be defined in single UpdateActivity function as well as in separate activity function. E.g. if a BAM table has following data items.

Data1, data2, starttime, endtime, errordetails, status, lastmodified.

Here we can write update function as per requirements, it’s not mandatory to define all data items in one time.

BAMes.UpdateActivity(“BAMSample”, ActivityID, “starttime”, DateTime.Now);

BAMes.UpdateActivity(“BAMSample”, ActivityID, “Status”, “OperationStart”);

You can track info on BAM Portal or BAM definition table in BAM Primary Import Database. You can check data in Bam_<BAM Definition File>_Completed table.

e.g. bam_BAMSample_Completed

BAMTable.jpg

When you defining BAM Definition file then BAM creates five table in BAMPrimaryImport table. you can refer to following reference to create BAM Definition file.

https://vkbiztalk.wordpress.com/2017/06/14/implementation-of-bam-activity-definition-file/

How does EventStream work in pipeline?

MessagingEventStream (MES) is used inside a BizTalk pipeline component to write Bam as part of the messaging transactions ensuring that your BAM event persistence remains in sync with the BizTalk pipeline transactions.

Messaging Event Streams are asynchronous and store tracking data first in the BizTalk MessageBox database. Periodically the data is processed and persisted to the BAM Primary Import database by the Tracking Data Decode Service (TDDS).