Using the ESB Toolkit’s Exception Management Functionality in .NET Applications

One nice thing about when you deploy all of the artifacts for the BizTalk ESB Toolkit, you not only get a great tool for supporting ESB architectures with BizTalk, but you get a bunch of web services that can be used by other applications.  In my current project, I’ve been making use of this functionality to allow our WCF services to use ESB’s Exception Management capabilities.  This approach would work just as well with any code that can access a web service.

The first step here is to add a reference to the Web Service in your Visual Studio project (if you’re not working with VS, you should be able to access the services through standard SOAP calls).  There are two services you can use.  If you prefer to work with WCF, find a service called  ESB.ExceptionHandlingServices.WCF/ExceptionHandling.svc on the web server to which you deployed your ESB Toolkit web artifacts. You can also use the .asmx service ESB.ExceptionHandlingServices/ExceptionHandling.asmx.  Both services expose a wsdl, so generating classes or .xsd’s that will work is pretty easy. 

Now that you can access the service, all you have to do is create a fault message and send it to the service when an exception occurs.  Below is some sample code from a SubmitFaultMessage  method I’ve written.  It gets called from within a catch block in C#, passing a reference to the exception that is caught:


private void SubmitFaultMessage(Exception ex, string  failureCategory,  string faultCode, Severity severity, string appName)
{
    //Create a FaultMessage
   FaultMessage fault = new FaultMessage();

   //Create the header
   FaultMessageHeader fmHeader = new FaultMessageHeader();
   fmHeader.Application = appName;
   fmHeader.DateTime = DateTime.Now.ToString();
   fmHeader.Description = ex.Message;
   fmHeader.ErrorType = ex.GetType().ToString();
   fmHeader.FailureCategory = failureCategory;
   fmHeader.FaultCode = faultCode;
   fmHeader.FaultDescription = ex.Message;
   fmHeader.FaultSeverity = (int)severity; 
   fault.Header = fmHeader;

   //Get the exception info and attach it to the message
   FaultMessageExceptionObject fmEx = new FaultMessageExceptionObject();
   fmEx.Message = ex.Message;
   fmEx.Type = ex.GetType().Name;
   fmEx.Source = ex.Source;
   fmEx.StackTrace = ex.StackTrace;
   fmEx.TargetSite = ex.TargetSite.Name;

   if (ex.InnerException != null)
      fmEx.InnerExceptionMessage = ex.InnerException.Message;
   else
      fmEx.InnerExceptionMessage = string.Empty;

   fault.ExceptionObject = fmEx;

   //Submit the fault 
   try
   {
      BizTalkServiceInstance exceptionHandlingSvc = new BizTalkServiceInstance();
      exceptionHandlingSvc.SubmitFault(fault);
   }
   catch (Exception exc)
   {
      System.Diagnostics.Trace.WriteLine(exc.Message);
      throw exc;
   }
}

Note that the service name BizTalkServiceInstance is the object representing the WCF service.  For .asmx, the service type is ExceptionHandling.  You may also create custom messages and add them through the Messages property of the FaultMessage which is simply an array of Message objects that you can create on the fly.  The Severity type is simply a custom enumeration wrapping the values Information (0), Warning (1), Error (2), Severe (3), and Critical (4).

When your code completes execution, you’ll be able to find your exceptions plus any messages that you added in the ESB. Portal.  Happy hunting!

Advertisements

About Ed Jones

Ed is a Connected Systems and .NET Specialist for RBA in the Twin Cities. Contact Ed

7 responses to “Using the ESB Toolkit’s Exception Management Functionality in .NET Applications”

  1. Lyle Bowe says :

    Do you have a working example of attaching messages using .NET? The following snippet appears to function although the message(s) never appear in the database:


    public static void AddMessage(ref FaultMessage faultMessage, string contentType, Guid interchangeID, string messageData, Guid messageID, string messageName, string messageType, string routingURL)
    {
    ArrayOfFaultMessageMessageMessage message = new ArrayOfFaultMessageMessageMessage();
    message.ContentType = string.IsNullOrEmpty(contentType) ? "text/plain" : contentType;
    message.InterchangeID = interchangeID.ToString();
    if (!string.IsNullOrEmpty(messageData))
    {
    XmlDocument xmlDoc = new XmlDocument();
    xmlDoc.LoadXml(messageData);
    XmlNode[] xmlNodes = new XmlNode[1];
    xmlNodes[0] = xmlDoc.DocumentElement;
    message.MessageData = new ArrayOfFaultMessageMessageMessageMessageData();
    message.MessageData.Any = xmlNodes;
    }
    message.MessageID = messageID == Guid.Empty ? faultMessage.Header.MessageID : messageID.ToString();
    message.MessageName = string.IsNullOrEmpty(messageName) ? string.Empty : messageName;
    message.MessageType = string.IsNullOrEmpty(messageType) ? string.Empty : messageType;
    message.RoutingURL = string.IsNullOrEmpty(routingURL) ? string.Empty : routingURL;

    ArrayList alMessages = new ArrayList();
    if (faultMessage.Messages != null)
    {
    alMessages.AddRange(faultMessage.Messages);
    }
    alMessages.Add(message);
    faultMessage.Messages = (ArrayOfFaultMessageMessageMessage[])alMessages.ToArray(typeof(ArrayOfFaultMessageMessageMessage));
    }

  2. Ed Jones says :

    The key component for using functionality is the service call to the same WCF service that BizTalk calls when submitting exception messages through the fault message routing or a Fault message send from inside an orchestration. The code below is key:

    BizTalkServiceInstance exceptionHandlingSvc = new BizTalkServiceInstance();
    exceptionHandlingSvc.SubmitFault(faultMessage);

  3. Lyle Bowe says :

    Sorry, the above was just a snippet. Yes, I already have an instance of the FaultMessage populated, along with using the SubmitFault() method after calling AddMessage(). The Fault appears in the EsbExceptionDb, however the Message and MessageData do not.


    public class ExceptionHandlingServices
    {
    #region Enumerations

    public enum FaultSeverity
    {
    Information = 0,
    Warning = 1,
    Error = 2,
    Severe = 3,
    Critical = 4
    }

    #endregion
    #region Fields

    #endregion
    #region Properties

    #endregion
    #region Methods

    public static void SubmitFault(FaultMessage faultMessage)
    {
    ExceptionHandlingService.ExceptionHandling svc = new ExceptionHandling();
    svc.Url = BusinessComponents.Domain.Configuration.BizTalkConfig.ExceptionHandlingService;
    svc.SubmitFault(faultMessage);
    }

    public static FaultMessage CreateFaultMessage(string application, string description, string errorType, string failureCategory, string faultCode, string faultDescription, FaultSeverity faultSeverity, string scope, Guid serviceInstanceID, string serviceName, string faultGenerator, string machineName, DateTime dateTime, string controlBit, Guid messageID, string activityIdentity, bool nack, string message, string type, string source, string targetSite, string stackTrace, string innerExceptionMessage)
    {
    // Create the Fault Message
    FaultMessage faultMessage = new FaultMessage();

    // Create the Fault Message Header
    FaultMessageHeader fmHeader = new FaultMessageHeader();
    fmHeader.Application = string.IsNullOrEmpty(application) ? string.Empty : application;
    fmHeader.Description = string.IsNullOrEmpty(description) ? string.Empty : description;
    fmHeader.ErrorType = string.IsNullOrEmpty(errorType) ? string.Empty : errorType;
    fmHeader.FailureCategory = string.IsNullOrEmpty(failureCategory) ? string.Empty : failureCategory;
    fmHeader.FaultCode = string.IsNullOrEmpty(faultCode) ? string.Empty : faultCode;
    fmHeader.FaultDescription = string.IsNullOrEmpty(faultDescription) ? string.Empty : faultDescription;
    fmHeader.FaultSeverity = !Enum.IsDefined(typeof(FaultSeverity), faultSeverity) ? (int)FaultSeverity.Information : (int)faultSeverity;
    fmHeader.Scope = string.IsNullOrEmpty(scope) ? string.Empty : scope;
    fmHeader.ServiceInstanceID = serviceInstanceID.ToString();
    fmHeader.ServiceName = string.IsNullOrEmpty(serviceName) ? string.Empty : serviceName;
    fmHeader.FaultGenerator = string.IsNullOrEmpty(faultGenerator) ? string.Empty : faultGenerator;
    fmHeader.MachineName = string.IsNullOrEmpty(machineName) ? string.Empty : machineName;
    fmHeader.DateTime = dateTime.ToString();
    fmHeader.ControlBit = string.IsNullOrEmpty(controlBit) ? string.Empty : controlBit;
    fmHeader.MessageID = messageID.ToString();
    fmHeader.ActivityIdentity = string.IsNullOrEmpty(activityIdentity) ? string.Empty : activityIdentity;
    fmHeader.NACK = nack;
    faultMessage.Header = fmHeader;

    // Create the Fault Message Exception Object
    FaultMessageExceptionObject fmExceptionObj = new FaultMessageExceptionObject();
    fmExceptionObj.Message = string.IsNullOrEmpty(message) ? string.Empty : message;
    fmExceptionObj.Type = string.IsNullOrEmpty(type) ? string.Empty : type;
    fmExceptionObj.Source = string.IsNullOrEmpty(source) ? string.Empty : source;
    fmExceptionObj.TargetSite = string.IsNullOrEmpty(targetSite) ? string.Empty : targetSite;
    fmExceptionObj.StackTrace = string.IsNullOrEmpty(stackTrace) ? string.Empty : stackTrace;
    fmExceptionObj.InnerExceptionMessage = string.IsNullOrEmpty(innerExceptionMessage) ? string.Empty : innerExceptionMessage;
    faultMessage.ExceptionObject = fmExceptionObj;

    return faultMessage;
    }

    public static FaultMessage CreateFaultMessage(Exception ex, string application, string failureCategory, string faultCode, FaultSeverity faultSeverity, string scope, Guid serviceInstanceID, string serviceName, string faultGenerator, string machineName, DateTime dateTime, string controlBit, Guid messageID, string activityIdentity, bool nack)
    {
    return CreateFaultMessage(application, ex.Message, ex.GetType().ToString(), failureCategory, faultCode, ex.Message, faultSeverity, scope, serviceInstanceID, serviceName, faultGenerator, machineName, dateTime, controlBit, messageID, activityIdentity, nack, ex.Message, ex.GetType().ToString(), ex.Source, ex.TargetSite.Name, ex.StackTrace, ex.InnerException.Message);
    }

    public static void AddMessage(ref FaultMessage faultMessage, string contentType, Guid interchangeID, string messageData, Guid messageID, string messageName, string messageType, string routingURL)
    {
    ArrayOfFaultMessageMessageMessage message = new ArrayOfFaultMessageMessageMessage();
    message.ContentType = string.IsNullOrEmpty(contentType) ? "text/plain" : contentType;
    message.InterchangeID = interchangeID.ToString();
    if (!string.IsNullOrEmpty(messageData))
    {
    XmlDocument xmlDoc = new XmlDocument();
    xmlDoc.LoadXml(messageData);
    XmlNode[] xmlNodes = new XmlNode[1];
    xmlNodes[0] = xmlDoc.DocumentElement;
    message.MessageData = new ArrayOfFaultMessageMessageMessageMessageData();
    message.MessageData.Any = xmlNodes;
    }
    message.MessageID = messageID == Guid.Empty ? faultMessage.Header.MessageID : messageID.ToString();
    message.MessageName = string.IsNullOrEmpty(messageName) ? string.Empty : messageName;
    message.MessageType = string.IsNullOrEmpty(messageType) ? string.Empty : messageType;
    message.RoutingURL = string.IsNullOrEmpty(routingURL) ? string.Empty : routingURL;

    ArrayList alMessages = new ArrayList();
    if (faultMessage.Messages != null)
    {
    alMessages.AddRange(faultMessage.Messages);
    }
    alMessages.Add(message);
    faultMessage.Messages = (ArrayOfFaultMessageMessageMessage[])alMessages.ToArray(typeof(ArrayOfFaultMessageMessageMessage));
    }

    #endregion
    }

    I suspect maybe I should be supplying a messageID and/or interchangeID value but haven’t a clue where they are supplied, or do I use Guid.NewGuid()?

    • Ed Jones says :

      My apologies for not correctly understanding your problem. Unfortunately, this may be a shortcoming of this approach. As the message does not exist in BizTalk at this point, an interchange id wouldn’t be available. Perhaps trying the Guid.NewGuid() approach may work–I’ll need to research further.

      Sorry I don’t have an answer straight away 😦

  4. pinoyinusa says :

    Hi,
    Hopefully you still check this blog.
    I followed what you have and unfortunately, I’m getting “Operation timed out” error. May I know if you have a solution on this?
    Thanks a lot!

    • Ed Jones says :

      Make sure the services are correctly installed and are running in IIS. The most common cause of a time out error is something missing in the path between calling code and the service. If that isn’t the problem, make sure that the account that the services’ application pool is running under has access to the Exception Management database and that the DB itself is running OK. Good luck!

Trackbacks / Pingbacks

  1. 2010 in review | Extremely Talented Monkeys - January 8, 2011

What do you think?

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: