Tallan's Technology Blog

Tallan's Top Technologists Share Their Thoughts on Today's Technology Challenges

How to resolve the “Reason: Unexpected event (“eos”) in state “processing_header”.” error from the XML Disassembler

Dan Field

This error is typically harmless, but can result when the XML Disassembler encounters an empty Envelope message instance that’s formatted like this:

<ns0:EnvelopeRoot xmlns:ns0="http://Tallan.BizTalk.Schemas.CommonEnvelope"/>

instead of this:

<ns0:EnvelopeRoot xmlns:ns0="http://Tallan.BizTalk.Schemas.CommonEnvelope"></ns0:EnvelopeRoot>

BizTalk chooses to make a semantic difference between these two instances, and process the second one fine (publishing no messages), but raising an exception like this for the first:

There was a failure executing the response(receive) pipeline: "..." Source: "XML disassembler" Send Port: "..." URI: "..." Reason: Unexpected event ("eos") in state "processing_header". 

This can happen particularly when using an XmlProcedure or XmlPolling from SQL – if the resultset is empty, the adapter will publish this message. While this behavior may be desirable (and can frequently be avoided by ensuring you have good Data Available statements on your polling ports, and only call XmlProcedures with valid parameters/at valid times), it can also generate a lot of alarming errors. If you can tolerate empty envelopes and don’t want these errors (or would just like a better error), a custom Decode pipeline component can be used. The following code aims to be as non-obtrusive as possible (it will swallow exceptions and pass the message on if it can’t fix it, it will tolerate invalid XML characters like the BizTalk runtime, it will reset the body part’s position if it fails at some point but has read the position, and it will only attempt this correction if the document corresponds to an envelope schema), but corrects the message if it’s bad. If you wanted to raise a more meaningful exception, you could do that instead of rewriting the message. This code would go in the Execute method of a Decode component.

Stream origStream = pInMsg.BodyPart.GetOriginalDataStream();
try
{
    XmlReaderSettings readerSettings = new XmlReaderSettings();
    readerSettings.CheckCharacters = false;
    readerSettings.CloseInput = false;

    XmlReader reader = XmlReader.Create(origStream, readerSettings);
    pContext.ResourceTracker.AddResource(reader);

    reader.MoveToContent();

    IDocumentSpec docSpec = pContext.GetDocumentSpecByType(reader.NamespaceURI + "#" + reader.LocalName);
    if (!string.IsNullOrWhiteSpace(docSpec.GetBodyPath()) && reader.IsEmptyElement) // this is an envelope schema with an empty root node
    {
        // ALTERNATIVELY: throw new Exception("Empty Envelope message received from " ... etc.
        XmlWriterSettings writerSettings = new XmlWriterSettings();
        writerSettings.CheckCharacters = false;
        writerSettings.OmitXmlDeclaration = true;

        MemoryStream ms = new MemoryStream(); // for such a small stream, MemoryStream is perfectly fine - normally use VirtualStream.
        pContext.ResourceTracker.AddResource(ms);

        XmlWriter writer = XmlWriter.Create(ms, writerSettings);
        pContext.ResourceTracker.AddResource(writer);

        writer.WriteStartElement(reader.Prefix, reader.LocalName, reader.NamespaceURI);
        writer.WriteFullEndElement();
        writer.Flush();

        ms.Position = 0;
        pInMsg.BodyPart.Data = ms;
    }
}
catch (Exception e)
{
    // swallow exception
    System.Diagnostics.Debug.WriteLine(e.ToString());
}
finally // make sure we're somewhat well behaved
{
    if (pInMsg.BodyPart.Data.CanSeek == true)
        pInMsg.BodyPart.Data.Position = 0;
}

Enjoy!

No comments

Leave a Reply

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

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>