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: ,
Comments (6)
  1. eliassal says:

    Hi Chris, when I run the application, I get in the console watcher waiting.

    I drop messages in several receive locations but nothing happens.

    Thanks for your help

  2. Chris Romp says:

    The program will monitor the status of the port (enabled/disabled), not the traffic through the port.

    To test the application, start the console app and then disable or unenlist a port.

    Feel free to email me (email button at top of page) if you need clarification.

  3. Sergio says:

    Nice Article!

    What is the minimun permissions set required to make it works? What services (EntSSo,…)does it depends on?

  4. Chris Romp says:

    You need permission to query WMI on the box, but that’s all as far as I’m aware.

    Depending on the OS version, the permissions can get pretty granular, IIRC, but I’m not a Windows Server security expert.  I think they’re somewhere in the Component Services admin tool?

  5. Alden Xu says:

    I have got a problem anout using WMI. We have a Biztalk server and SQL server. I have made an application, which uses WMI, to watch the suspended queue from Biztalkserver. It works fine. But when I want to enumerate "MSBTS_ReceiveLocation" to find out the service name, the error message is:

    BizTalk Server cannot access SQL server.  This could be due to one of the following reasons:

    1. Access permissions have been denied to the current user.  Either log on as a user that has been granted permissions to SQL and try again, or grant the current user permission to access SQL Server.
    2. The SQL Server does not exist or an invalid database name has been specified.  Check the name entered for the SQL Server and database to make sure they are correct as provided during SQL Server installation.

    3. The SQL Server exists, but is not currently running.  Use the Windows Service Control Manager or SQL Enterprise Manager to start SQL Server, and try again.

    4. A SQL database file with the same name as the specified database already exists in the Microsoft SQL Server data folder.

    Internal error from OLEDB provider: "Login failed for user ‘NT AUTHORITYANONYMOUS LOGON’."

    The account I am using is in "local administrators group".

    Any help will be nuch appreciated.

    Thanks

  6. arjaygg says:

    Great Article!

    This is big! Thanks a lot for having this article.

    In my organization we are going to use WCF-SQL adapter and since we have a BizTalk that has two BizTalk Server(for now) then we have to handle the concurrency. I think one solution is to cluster the receive location host instance but unfortunately windows clustering is not an option for us right now so we’ve decided we’re just going to disable the other host instance. supposed to be it will be a manual disaster recovery but i have this idea to create a windows service that will monitor host instance to automatically enable the other host instance once problem was encountered. I think it’s a nice solution but since i found this wmi event then it will be even more better.

    have you thought of this idea of enabling another hostinstance of the same BizTalk Group once the other hostinstance once disable? do you foresee any issue for this? I would appreciate if you could let me know.

    Thanks a lot!

Comments are closed.

Skip to main content