Thursday, July 28, 2011

BizTalk ESB Toolkit 2.1 Exception Handling bits


A few bits & pieces gleaned from using the Microsoft BizTalk ESB Toolkit 2.1 to provide a standard exception handling framework for BizTalk 2010.

ESB Fault Message Infinite Loop (CPU 100%)

There are certain conditions under which creating an instance of the ESB Fault message using a call similar to the following will cause your orchestration to enter an infinite loop, and your server's CPU to hit 100%:

faultMsg = Microsoft.Practices.ESB.ExceptionHandling.ExceptionMgmt.CreateFaultMessage();

While the call is perfectly valid, there is a bug in the ESB framework that under certain conditions will cause the CreateFaultMessage method to enter an infinite loop. The conditions are either:
  1. You call CreateFaultMessage outside an exception handling block inside a Scope shape.
  2. You call CreateFaultMessage after catching an exception that derives from Microsoft.XLANGs.BaseTypes.XLANGsException.
(1) means that you can't use CreateFaultMessage to create an instance of the ESB fault message schema outside an exception handling block. You can work around this by defining and throwing your own custom exception at the point where you would otherwise have called CreateFaultMessage, and then leave it to an exception handling block that catches your custom exception to call CreateFaultMessage and perform your exception handling pattern... I think this is probably a pretty good pattern anyway.

(2) means that you have to be careful with what you catch and handle in your exception handling block, and if it derives from Microsoft.XLANGs.BaseTypes.XLANGsException, don't call CreateFaultMessage.

The following post has some suggestions for how to rectify this bug in the source: http://www.bizbert.com/bizbert/2011/05/06/Improving+The+ESB+Toolkit+Fixing+The+Endless+Loop+Bug+When+Creating+Fault+Messages.aspx

Creating Custom Exceptions for use with ESB Toolkit

If you decide to head down the path of defining and throwing your own custom exceptions for use with the ESB exception management framework, you need to follow certain rules in the custom exceptions:
  1. Decorate your class with SerializableAttribute.
  2. Inherit from System.Exception.
  3. Define a protected deserialization constructor.
For example:

[Serializable]
public class MyException : System.Exception{
    internal MyException() : base() { }
    internal MyException(string message) : base(message) { }
    protected MyException(SerializationInfo info, StreamingContext context) : base(info, context) { }
}

Also note if you define any custom properties in your custom exception, these will need to be catered for in the deserialization constructor and by overriding the GetObjectData method, for example:

[SecurityPermissionAttribute(SecurityAction.Demand, SerializationFormatter = true)]
protected MyException(SerializationInfo info, StreamingContext context) : base(info, context)
{
  this.mScope = info.GetString("Scope");
}


[SecurityPermissionAttribute(SecurityAction.Demand, SerializationFormatter = true)]
public override void GetObjectData(SerializationInfo info, StreamingContext context)
{
  if (info == null)
  {
    throw new ArgumentNullException("info");
  }
  info.AddValue("Scope", this.Scope);
  base.GetObjectData(info, context);
}


Beware Null Values in Fault Message Properties

After you've created your instance of the ESB fault message using CreateFaultMessage, you would normally set properties of the message using its distinguished fields. Just beware settings any of these values to a null value - this causes the serialization of the message to fail. I usually use some sort of helper function that checks if the value that will be populated into the property is null and uses a default value if it is, for example:

faultMessage.Body.FailureCategory = MyExceptionManager.EsbPropertyProvider.GetFailureCategory(caughtException, MyExceptionManager.FailureCategories.Default);

Writing Exception Details to the Windows Event Log

Lastly, a rather obscure one, but the ESB framework provides a helper function for writing exception details to the Windows Application event log. You need to add a reference to Microsoft.Practices.ESB.Exception.Management.dll, then in an expression shape you can use:

Microsoft.Practices.ESB.Exception.Management.EventLogger.LogMessage(
  exceptionToHandle.Message,
  System.Diagnostics.EventLogEntryType.Error,
  (System.Int32)Microsoft.Practices.ESB.Exception.Management.EventLogger.EventId.Default);


HTH!

2 comments:

  1. Thanks for a good article, it helped me out while troubleshooting the 100% CPU BizTalk hostinstance issue

    ReplyDelete
  2. This comment has been removed by the author.

    ReplyDelete