HowTo: Using XLANGMessages in Custom Exceptions in BizTalk

By jpsmit
May 12, 2008
0

On the project I’m working on at the moment we’re using custom exceptions in BizTalk. We have adopted the exception handling part of the ESB guidance and so the custom exception consists of a string indicating what to do next and an XLANGMessage object to store messages in.

There was something not working as expected so I had to debug it. I wasn’t very familiar with custom exceptions in BizTalk so I searched the internet for some information. On this blog by Tomas Restrepo I found some interesting tips and information:

Tip #1: Exceptions are not serializable by default. If you create a custom exception class, it is your responsibility to ensure it is serializable.

Tip #2: Marking an exception class with [Serializable] is not enough. System.Exception implements ISerializable, so it forces you to do so as well.

Here’s what you should keep in mind when writing an exception class:

  • Mark the exception type with the [Serializable] attribute.
  • Add an empty protected serialization constructor that simply delegates to the base class: protected MyException(SerializationInfo info, StreamingContext ctxt) : base(info, ctxt)

For most exception classes, this will be enough, since most don’t actually add new properties and simply rely on the message.

However, if your custom exception class has custom properties, then it MUST override ISerializable.GetObjectData() (and don’t forget to call the base one), and you MUST unpack those properties in your serialization constructor.

While testing the solution I found out that something went wrong after the custom exception was returned to the orchestration. All information was present in the object but the messages could not be retrieved. I was puzzled. It looked like something in the serialization/deserialization process of the XLANGMessage object failed, but if one object should be serializable it should be this object. Right?

Further research showed that the XLANGMessage object was serialized/deserialized ok, but the XLANGPart object wasn’t. This resulted in a correct XLANGMessage structure, with the correct number of parts in it, but with empty content. As a last resort I posted a question on the MSDN forum.

Within a day I had the solution. It turned out that the XLANGMessage property containing the XLANGParts data wasn’t public so with binary serialization it was skipped. That at least explained this behavior, but how to solve it? In fact that was also in the reply (thanks Douglas Marsh) and in the Tomas Restrepo blog. You have to manually get the parts that aren’t serializable and put them in the SerializationInfoStore in the GetObjectData method. Like this:

         public override void GetObjectData(SerializationInfo info, StreamingContext context)
        {
            base.GetObjectData(info, context);
            if (info != null)
            {
                info.AddValue("Fault", this.Fault, typeof(XLANGMessage));
                // Get the message parts, they aren't serializable so we have to do it by hand
                // Get the contents of the parts, convert them to a byte[] and add them to the store
                if (this.Fault != null)
                {
                    info.AddValue("NumberOfFaultParts", this.Fault.Count, typeof(Int32));
                    for (int i = 0; i < this.Fault.Count; i++)
                    {
                        info.AddValue("FaultMsgPart" + i, Helper.XmlDocumentToByteArray((XmlDocument)this.Fault[i].RetrieveAs(typeof(XmlDocument))), typeof(byte[]));
                    }
                }
            }
        }

When deserializing you can get them back in the serialization constructor, like this:

        protected MyCustomException(SerializationInfo info, StreamingContext ctxt)
            : base(info, ctxt)
        {
            if (info != null)
            {
                // get all the public members
                this.Fault = (XLANGMessage) info.GetValue("Fault", typeof(XLANGMessage));
                // Get the message parts, they aren't serializable
                // This has to be in a try block, because the 'NumberOfFaultsParts' isn't always there and there is no way of knowing in advance
                try
                {
                    int faultPartsCnt = info.GetInt32("NumberOfFaultParts");
                    for (int i = 0; i < faultPartsCnt; i++)
                    {
                        XmlDocument doc = Helper.ByteArrayToXmlDocument((byte[])info.GetValue("FaultMsgPart" + i, typeof(byte[])));
                        this.Fault[i].LoadFrom(doc);
                    }
                }
                catch (Exception ex)
                {
                    Trace.WriteLine("XLANGPart serialization error: ", ex.Message);
                }
            }
        }

So after all it wasn’t that difficult at all, but isn’t that always the case?? Thanks to everybody helping me.

Comments: 0

Leave a Reply

Your email address will not be published. Required fields are marked *

  • Recent Posts
  • Recent Comments
  • Archives
  • Categories
  • Meta