mizzle
mizzle

Reputation: 578

BizTalk envelope schema self-closing node

I have created a BizTalk receive location which has a subscribing send port which accepts an enveloped message and splits into separate messages just using the XML Receive Pipeline.

<?xml version="1.0" encoding="utf-8"?>
<MyEnvelope xmlns="MyNameSpace">
    <MyData>ABC</MyData>
    <MyData>DEF</MyData>
    <MyData>GHI</MyData>
</MyEnvelope>

Gets saved as

<?xml version="1.0" encoding="utf-8"?>
<MyData xmlns="MyNameSpace">ABC</MyData>

,

 <?xml version="1.0" encoding="utf-8"?>
 <MyData xmlns="MyNameSpace">DEF</MyData>

and

 <?xml version="1.0" encoding="utf-8"?>
 <MyData xmlns="MyNameSpace">GHI</MyData>

which is great.

However, when there are no elements in the message the service sends the message with self-closing and empty envelope:

<?xml version="1.0" encoding="utf-8"?>
<MyEnvelope xmlns="MyNameSpace"/>

And I get the error message

Source: "XML disassembler" Receive Port: "InLocation" URI: "c:\MyLocation*.xml" Reason: Unexpected event ("eos") in state "processing_header".

If I manually create a message which is not self-closing:

<?xml version="1.0" encoding="utf-8"?>
<MyEnvelope xmlns="MyNameSpace"></MyEnvelope>

I get no error. My processing is unaffected by the errors but it must have some performance impact and litters the Group Hub suspended instances view.

It seems that BizTalk interprets self-closing nodes as whitespace instead of null. This seems linked to my issues with attempting to call a service with no parameters where I need to send a self-closing node but BizTalk just sends nothing.

It must be a common issue to handle an envelope with no content. How can I configure my application to pick up and ignore these messages with self-closing envelope nodes?

Upvotes: 5

Views: 1748

Answers (4)

Ruud
Ruud

Reputation: 1372

Another (very) late answer. It doesn't really answer the OP's question, but since I got here googling the error message and it eventually led me to this solution, I thought I'd answer anyway in case it helps anyone else.

If you have control over the envelope's structure like I did, you can just add another level to the envelope, and it won't result in an error if that's self-closing.

So, this will result in an error:

<MyEnvelope xmlns="MyNameSpace" />

But this won't:

<MyEnvelope xmlns="MyNameSpace">
  <Body />
</MyEnvelope>

Set the Body XPath of the schema to this nested level and it should process just fine.

<MyEnvelope xmlns="MyNameSpace">
    <Body>
        <MyData>ABC</MyData>
        <MyData>DEF</MyData>
        <MyData>GHI</MyData>
    </Body>
</MyEnvelope>

Upvotes: 1

Dan Field
Dan Field

Reputation: 21641

I know this is an old question, but I've encountered the same thing (particularly in SQL XML polling/procedures where an empty resultset is returned). Usually I get around it by making sure SQL isn't called if it would return an empty result set (refine the Data Available statement), but sometimes it's just not entirely possible or foolproof. In the end, I've written a custom pipeline component in the decode stage. It's meant to do the following:

  1. Check if this is an envelope schema (the only time where this error should happen
  2. Try to be as tollerant as BizTalk is of malformed XML (at least with regard to invalid characters in XML)
  3. Check if the first content element (i.e. the root element) is empty
  4. If so, rewrite it with a "FullEndElement".
  5. Reset the streams and add them to the resource tracker for eventual disposal
  6. On an exception, quietly write to the debug tracer but just let BizTalk take it from there - the worst it will do is produce the noisy but harmless error message.
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
    {
        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;
}

Upvotes: 2

Dijkgraaf
Dijkgraaf

Reputation: 11527

Every so often they seem to change the behaviour of how white space is treated. See Change in Default Whitespace Behavior in BizTalk. I'm not sure if your issue is related or not but worth a look. It doesn't mention BizTalk 2013 however but the setting is there in the Host. If you do this configuration setting it would pay to set up a host specially for it so that it has no impact on other existing applications if any.

Installing one of the following updates results in BizTalk changing default behavior to preserve whitespace within the XML during mapping:

  1. BizTalk 2010 CU1 or above
  2. BizTalk 2009 CU3 or above
  3. BizTalk 2006 R2 SP1 CU4 or above
  4. Hotfix 2492255

In some environments, it may be preferred that the transform remove whitespace. In order to revert to this behavior, the following steps can be taken:

In BizTalk 2010, this is set at the host level:

  1. Open BizTalk Server Administration Console
  2. Expand the BizTalk Group out to Platform Settings > Hosts
  3. Right-click on the host and choose Settings
  4. Check the checkbox next to Legacy whitespace behavior
  5. Click OK
  6. Restart the BizTalk Host Instances for this host

In BizTalk 2009 and 2006 R2 this value is set at a per-machine level:

  1. Open Registry Editor
  2. Locate and then click the following registry subkey on an x86-based computer: • HKEY_LOCAL_MACHINE\Software\Microsoft\BizTalk Server\3.0\Administration For an x64-based computer, click the following registry subkeys: • HKEY_LOCAL_MACHINE\Software\Microsoft\BizTalk Server\3.0\Administration
    • HKEY_LOCAL_MACHINE\Software\Wow6432Node\Microsoft\BizTalk Server\3.0\Administration
  3. Right-click and choose DWORD value.
  4. Type LegacyWhitespace for the value name and then double-click on it and set the Value data to 1.
  5. Exit Registry Editor.
  6. Restart the BizTalk Host Instances on this machine

Upvotes: 3

DTRT
DTRT

Reputation: 11040

I have not seen or verified this behavior but I'll trust you ;).

Don't worry about the performance hit of the Exceptions unless you're getting 10K files per hours or something like that.

To prevent the errors, you'll have to quash or reformat the message in a Pipeline Component.

Upvotes: 2

Related Questions