woensdag 23 maart 2011

BizTalk monitoring, PART 2: BTS suspended messages

We've written some code to receive an E-mail when a message is suspended in Biztalk. For this code we've created a scheduled task that is triggered when an error is raised by Biztalk.

First of all I'll show how to setup such a triggered event. Just make a new scheduled task in your windows task scheduler. To start the task you add a new trigger, here's a screenshot from how to set up this trigger:


Then click on the 'Edit event filter' button.
Following screenshot shows you how to configure the trigger to the Biztalk 2009 Errors:


Now that the trigger is set, just configure the scheduled task to run the programming code. Just like the BizTalk monitoring tool of my previous post, the configuration is done in an external XML File.

So here is the used code the send us an E-mail with an overview of suspended messages, including the error details and the receiving port. The method will return a boolean to specify if there are no suspended messages.


   1:  public Boolean CheckBTSQueue()
   2:          {
   3:              String tab = "    ";
   4:              //Constant Values
   5:              String ErrorMessage = tab + "<b><i>Suspended message with error at {0}:</i></b><BR>" +
   6:                  tab + tab + "Receive Port: {1}<BR>" +
   7:                  tab + tab + "Error Code: {2}<BR>" + 
   8:                  tab + tab + "Error Description: {3}<BR><BR>";
   9:                  //tab + tab + "Inner Exception: {3}";
  10:              String ErrorSuspendedMsgHeader = "<strong>WARNING: Suspended Message(s) in Biztalk</strong><BR><BR>";
  11:              String MailSubject = "Messages stuck on " + Dns.GetHostName();
  12:   
  13:              StringBuilder suspendedMessages = new StringBuilder();
  14:   
  15:              Boolean allRunning = true;
  16:   
  17:              BizTalkOperations operation = new BizTalkOperations(dBServer, dB);
  18:   
  19:              int count = 10;
  20:              foreach (BizTalkMessage message in operation.GetMessages())
  21:              {
  22:                  if (message.MessageStatus == MessageStatus.Suspended)
  23:                  {
  24:                      suspendedMessages.AppendLine(String.Format(ErrorMessage, message.CreationTime.ToString(),
  25:                          message.Context.Read("PortName", "http://schemas.microsoft.com/BizTalk/2003/messagetracking-properties"), message.ErrorCode, message.ErrorDescription));
  26:                      //message.Context.Read("Name", "NameSpace");
  27:   
  28:                      count--;
  29:   
  30:                      allRunning = false;
  31:                  }
  32:                  if (count <= 0)
  33:                  {
  34:                      count--;
  35:                      break;
  36:                  }
  37:              }
  38:   
  39:              if (!allRunning)
  40:              {
  41:                  if (!String.IsNullOrEmpty(suspendedMessages.ToString()))
  42:                      suspendedMessages.Insert(0, ErrorSuspendedMsgHeader);
  43:   
  44:                  String body = "";
  45:   
  46:                  if (count < 0)
  47:                      body = "Only last 10 messages are given<BR><BR>";
  48:   
  49:                  body += suspendedMessages.ToString();
  50:   
  51:                  Helper.SendMail(body, MailSubject, sendMailAddress, receiveMailAddress, SMTP);
  52:              }
  53:   
  54:              return false;
  55:          }

the method to send an email, the method to read the configuration from XML and the XML itself are the same as in my previous Blog. Here they are again:

the method to send an email is the following:


   1:  public static void SendMail(String body, String subject, String fromAddress, String toAddress, String SMTPAddress)
   2:          {
   3:              MailMessage msg = new MailMessage(fromAddress, toAddress);
   4:              msg.IsBodyHtml = true;
   5:              msg.Body = body;
   6:              //msg.From = new MailAddress(fromAddress);
   7:              msg.Subject = subject;
   8:   
   9:              System.Net.Mail.SmtpClient smtp = new SmtpClient(SMTPAddress);
  10:              smtp.Send(msg);
  11:              //SmtpMail.SmtpServer = SMTPAddress;
  12:              //SmtpMail.Send(msg);
  13:          }

to read the configuration out of the XML file, we've programmed following in the constructor (all is read to private class variables:


   1:  private string dBServer;
   2:          private string dB;
   3:          private string userName;
   4:          private string password;
   5:   
   6:          private List<string> BTSService;
   7:   
   8:          private string sendMailAddress;
   9:          private string receiveMailAddress;
  10:          private string SMTP;
  11:   
  12:          public Monitor()
  13:          {
  14:              XmlDocument config = new XmlDocument();
  15:              config.Load(System.IO.Directory.GetCurrentDirectory() + "/BTSMonitorConfiguration.xml");
  16:   
  17:              try
  18:              {
  19:                  dBServer = config.SelectSingleNode("CONFIGURATION/DBSETTINGS/Server").InnerText;
  20:                  dB = config.SelectSingleNode("CONFIGURATION/DBSETTINGS/DB").InnerText;
  21:                  userName = config.SelectSingleNode("CONFIGURATION/DBSETTINGS/UserName") == null ?
  22:                      "" : config.SelectSingleNode("CONFIGURATION/DBSETTINGS/UserName").InnerText;
  23:                  password = config.SelectSingleNode("CONFIGURATION/DBSETTINGS/Password") == null ?
  24:                      "" : config.SelectSingleNode("CONFIGURATION/DBSETTINGS/Password").InnerText;
  25:   
  26:                  BTSService = new List<string>();
  27:   
  28:                  foreach(XmlNode service in config.SelectNodes("CONFIGURATION/BTSSETTINGS/BTSSERVICES/BTSServiceName"))
  29:                  {
  30:                      BTSService.Add(service.InnerText);
  31:                  }
  32:   
  33:                  sendMailAddress = config.SelectSingleNode("CONFIGURATION/MAILSETTINGS/From").InnerText;
  34:                  receiveMailAddress = config.SelectSingleNode("CONFIGURATION/MAILSETTINGS/To").InnerText;
  35:                  SMTP = config.SelectSingleNode("CONFIGURATION/MAILSETTINGS/SMTP").InnerText;
  36:              }
  37:              catch (Exception e)
  38:              {
  39:                  StringBuilder error = new StringBuilder();
  40:                  error.AppendLine("not all necessary data to perform the action is provided.");
  41:                  error.AppendLine("Make sure these fields are correctly filled in in the XML File:");
  42:                  error.AppendLine("\tDBServer (server name)");
  43:                  error.AppendLine("\tDB (Database)");
  44:                  error.AppendLine("\tBTSServiceName (BTS Service Name)");
  45:                  error.AppendLine("\tFrom (sending mail address)");
  46:                  error.AppendLine("\tTo (receiveing mail address)");
  47:                  error.AppendLine("\tSMTP (SMTP host address)");
  48:                  throw (new Exception(error.ToString()));
  49:              }
  50:          }


and finally the created XML file:


<?xml version="1.0" encoding="utf-8" ?>
<CONFIGURATION>
  <DBSETTINGS>
    <Server>.</Server>    <!-- Server Name -->
    <DB>BizTalkMgmtDb</DB>    <!-- DataBase Name -->
    <!--<UserName>user</UserName>-->    <!-- optional -->
    <!--<Password>password</Password>-->    <!-- optional -->
  </DBSETTINGS>
  <BTSSETTINGS>
    <BTSSERVICES>
      <BTSServiceName>BizTalk Service BizTalk Group : BizTalkServerApplication</BTSServiceName>      <!-- BTS Service Name -->
      <BTSServiceName>BizTalk Service BizTalk Group : BizTalkServerApplication2</BTSServiceName>
      <!-- BTS Service Name -->
    </BTSSERVICES>
  </BTSSETTINGS>
  <MAILSETTINGS>
    <From>from@company.com</From>
    <To>to@company.com</To>
    <SMTP>smtp.company.com</SMTP>
  </MAILSETTINGS>
</CONFIGURATION>



In this example, only the last 10 suspended messages are mailed to us.

These monitoring mails have proven to be very valuable to us.
Hope you enjoyed my post.

2 opmerkingen:

  1. Hey, how can I pass the user and password for the DB to the BizTalkOperations Class? Thank you, Philipp

    BeantwoordenVerwijderen
    Reacties
    1. Hi, I don't think it is possible to pass user name and password to the BizTalkOperations class.

      The user name and password in my xml configuration example are intended for the BtsCatalogExplorer from my previous monitoring post (part 1).

      Verwijderen