Using WMI to Monitor Send Ports and Receive Locations in BizTalk Server

The question has come up more than a couple of times: How do I monitor my Send Ports or Receive Locations if I don't have MOM (or monitoring solution of your choice) configured for my BizTalk servers?  I've always been positive the answer was in WMI, so I finally decided to see if I could write a very basic port monitor for BizTalk.

First, I needed to build the WMI queries, using the WqlEventQuery class.  Most of the WMI-specific classes mentioned here are in the System.Management namespace.  Full source code is available at the end of the article.

 WqlEventQuery wqlSendPortEventQuery = new WqlEventQuery(
    "__InstanceModificationEvent", 
    new TimeSpan(0, 0, 10), // poll every 10 sec
    "TargetInstance isa \"MSBTS_SendPort\"");
WqlEventQuery wqlReceiveLocationEventQUery = new WqlEventQuery(
    "__InstanceModificationEvent",
    new TimeSpan(0, 0, 10),
    "TargetInstance isa \"MSBTS_ReceiveLocation\"");

Next I had to configure a ManagementEventWatcher for Send Ports and Receive Locations:

 ManagementEventWatcher wmiSendPortEvents = new ManagementEventWatcher(
    new ManagementScope(@"\\.\root\MicrosoftBizTalkServer"),
    wqlSendPortEventQuery);
ManagementEventWatcher wmiReceiveLocationEvents = new ManagementEventWatcher(
    new ManagementScope(@"\\.\root\MicrosoftBizTalkServer"),
    wqlReceiveLocationEventQuery);

Then an event handler for each watcher:

 wmiReceiveLocationEvents.EventArrived += 
    new EventArrivedEventHandler(WmiEventReceived);
wmiSendPortEvents.EventArrived += 
    new EventArrivedEventHandler(WmiEventReceived);

Finally, I fire them up:

 Console.WriteLine("Starting event watchers...");
wmiReceiveLocationEvents.Start();
wmiSendPortEvents.Start();
Console.WriteLine("Event watchers started.  Press ENTER to exit...\r\n");

The event handler itself is where things got somewhat complicated, because the event itself doesn't contain the BizTalk-specific properties I'm interested in.  So I had to dig a little.  In this case, we're only interested in the TargetInstance:

 static void WmiEventReceived(object sender, EventArrivedEventArgs e)
{
    ManagementBaseObject evt = e.NewEvent;
    PropertyDataCollection col = evt.Properties;
    PropertyDataCollection.PropertyDataEnumerator en = col.GetEnumerator();

    while (en.MoveNext())
    {
        PropertyData data = en.Current;

        // Grab TargetInstance only (could use PreviousInstance to get prior state data) :
        if(data.Value != null && data.Name == "TargetInstance")
        {
            ManagementBaseObject mbo = (ManagementBaseObject)data.Value;
            if (mbo.ClassPath.ClassName == "MSBTS_SendPort") // Send port event
            {
                ROOT.MICROSOFTBIZTALKSERVER.SendPort.ManagementSystemProperties prop = new SendPort.ManagementSystemProperties(mbo);
                int iSendPortStatus = Convert.ToInt32(mbo.Properties["Status"].Value.ToString());
                Console.WriteLine("Server: {0}", prop.SERVER);
                Console.WriteLine("Send Port Name: {0}", mbo.Properties["Name"].Value.ToString());
                Console.WriteLine("Send Port Status: {0}", GetSendPortStatusString(iSendPortStatus));
            }
            else if (mbo.ClassPath.ClassName == "MSBTS_ReceiveLocation") // Receive location event
            {
                ROOT.MICROSOFTBIZTALKSERVER.ReceiveLocation.ManagementSystemProperties prop = new ReceiveLocation.ManagementSystemProperties(mbo);
                bool isDisabled = true;
                bool.TryParse(mbo.Properties["IsDisabled"].Value.ToString(), out isDisabled);
                Console.WriteLine("Server: {0}", prop.SERVER);
                Console.WriteLine("Receive Location Name: {0}", mbo.Properties["Name"].Value.ToString());
                Console.WriteLine("Receive Port Name: {0}", mbo.Properties["ReceivePortName"].Value.ToString());
                Console.WriteLine("Receive Location Status: {0}", GetReceiveLocationStatusString(isDisabled));
            }
        }
    }
    Console.WriteLine("");
}

In case you're wondering, the ROOT.MICROSOFTBIZTALKSERVER classes are generated from the Management Classes in the Visual Studio Server Explorer.  See this article for more details.

So, how does it look?

PortMonitor

So from here you can do anything with these events that you'd like.  I supposed you could even have the event handler generate a message that you send to BizTalk... as long as the port doesn't go down. =)

Source code:

 

Technorati Tags: BizTalk,WMI