locked
Constructing XmlTextReader causes "Root element is missing" in BizTalk WCF Send Pipeline RRS feed

  • Question

  • I have a send pipeline, and trying to parse the data using XmlTextReader in order to pick out an element value for use in my context.

    public IBaseMessage Execute(BizTalkComp.IPipelineContext pContext, IBaseMessage pInMsg) { IBaseMessagePart bodyPart = pInMsg.BodyPart; IBaseMessageContext context = pInMsg.Context; //context.Write("OutboundTransportLocation", "http://schemas.microsoft.com/BizTalk/2003/system-properties", // context.Read("OutboundTransportLocation", "http://schemas.microsoft.com/BizTalk/2003/system-properties")); int bufferSize = 0x280; int thresholdSize = 0x100000; System.Diagnostics.EventLog.WriteEntry("LOGGER","Pipeline1"); Stream inboundStream = bodyPart.GetOriginalDataStream(); VirtualStream virtualStream = new VirtualStream(bufferSize, thresholdSize); ReadOnlySeekableStream readOnlySeekableStream = new ReadOnlySeekableStream(inboundStream, virtualStream, bufferSize); System.Diagnostics.EventLog.WriteEntry("LOGGER","Pipeline2"); XmlTextReader xmlTextReader = new XmlTextReader(readOnlySeekableStream); //comment-this-line-out and it works // string dbName = ParseXMLForDatabaseName(xmlTextReader); xmlTextReader.Close(); virtualStream.Close(); virtualStream.Dispose(); string dbName = "US......"; // temporary value to be be able to comment out the XmlTextReader System.Diagnostics.EventLog.WriteEntry("LOGGER", "Pipeline3b dbName=" + dbName); string regionSpecificURL = ""; string firstTwoCharsOfDBame = dbName.Substring(0, 2); switch (firstTwoCharsOfDBame) { case ("US"): regionSpecificURL = "http://MyUSSite.com/MyApp/MyService.svc"; break; case ("EM"): regionSpecificURL = "http://MyEMSite.com/MyApp/MyService.svc"; break; case ("AP"): regionSpecificURL = "http://MyAPSite.com/MyApp/MyService.svc"; break; default: regionSpecificURL = "http://MyINVALIDREGIONAPSite.com/MyApp/MyService.svc"; break; } System.Diagnostics.EventLog.WriteEntry("LOGGER", "Pipeline4 regionSpecificURL=" + regionSpecificURL); // Three parms: 1) context proeprty, 2) context string namespace 3) value context.Promote( "OutboundTransportLocation", "http://schemas.microsoft.com/BizTalk/2003/system-properties", regionSpecificURL); context.Promote( "IsDynamicSend", "http://schemas.microsoft.com/BizTalk/2003/system-properties", true);

    System.Diagnostics.EventLog.WriteEntry("LOGGER","Pipeline5"); return pInMsg; }

    In this issue: https://social.msdn.microsoft.com/Forums/en-US/f86c5ab1-cd2e-4364-bf9f-4caac4f5f9ff/how-to-override-just-the-url-of-a-wcf-sendport-from-an-orchestration?forum=biztalkr2adapters&prof=required,

    James Corbould gave me code that works to set the URL dynamically in a static send port.

    When I hardcode the URL, it works.  But now, when I need to parse the data, i get the following error when I use the XmlTextReader:

    System.Xml.XmlException: Root element is missing.
       at System.Xml.XmlTextReaderImpl.Throw(Exception e)
       at System.Xml.XmlTextReaderImpl.ParseDocumentContent()
       at System.Xml.XmlTextReaderImpl.Read()
       at System.Xml.XmlReader.MoveToContent()
       at Microsoft.BizTalk.Adapter.Wcf.Runtime.BizTalkBodyWriter.ValidateStreamContainsXml(Stream stream)
       at Microsoft.BizTalk.Adapter.Wcf.Runtime.WcfMarshaller.CreateWcfMessage(CreateWcfMessageSettings settings)
       at Microsoft.BizTalk.Adapter.Wcf.Runtime.WcfClient`2.SendRequestMessage(IBaseMessage bizTalkMessage, IRequestChannel channel)
       at Microsoft.BizTalk.Adapter.Wcf.Runtime.WcfClient`2.SendMessage(IBaseMessage bizTalkMessage)

    In the Application EventLog, I see all my "System.Diagnostics.EventLog.WriteEntry" - through "Pipeline5". So I know that my pipline code runs up to the return statement.

    So why is it failing?  What does the XmlReader do that messes things up?

    Thanks,
    Neal Walters
    http://MyLifeIsMyMessage.net


    Tuesday, December 8, 2015 4:41 PM

Answers

All replies

  • It just occured I probably need to seek back to beginning of stream, about to try this:

    readOnlySeekableStream.Seek(0, SeekOrigin.Begin);

    Neal


    Tuesday, December 8, 2015 5:50 PM
  • Sadly, still not working.

    Read this page: https://msdn.microsoft.com/en-us/library/aa577699.aspx?f=255&MSPPError=-2147217396

    Changed my code to remove all .close() and .dispose() related to stream, and added this code at the bottom:

                System.Diagnostics.EventLog.WriteEntry("LOGGER","Pipeline5");
                readOnlySeekableStream.Seek(0, SeekOrigin.Begin);
                System.Diagnostics.EventLog.WriteEntry("LOGGER", "Pipeline6-ReSeek to 0");
                return pInMsg;


    The write to EventLog proves to me that I'm running and properly deploy the new version of my pipeline component, restarted hosts, etc... So I see "Pipeline6-Reseek" in the EventLog on my last run, and I'm still getting the error.  It makes sense that the above would fix the issue.  What else should I try?

    Thanks,
    Neal


    Tuesday, December 8, 2015 6:00 PM
  • Grasping at straws, I tried this and it worked:

                inboundStream.Seek(0, SeekOrigin.Begin);

    So I basically changed back to the original stream, instead of the derived stream.

    I just did a more organized blog on this subject here:

    http://mylifeismymessage.net/xmltextreader-causes-root-element-is-missing-in-biztalk-send-pipeline/

    Neal



    Tuesday, December 8, 2015 6:05 PM
  • Hi Neal - have a read of this blog article of mine - might provide some further information for you:

    https://jamescorbould.wordpress.com/2015/04/08/notes-on-creating-a-streaming-pipeline-component-based-on-the-biztalk-virtualstream-class/

    (Apologies - it's quite a long one!).

    I haven't had a chance to read your blog yet but will do so...

    In the implementation described in my post, I create my own streaming class and override the read method...  The read method is called repeatedly by the BizTalk endpoint manager (EPM - intermediary between the ports and the MessageBox) until there are no more bytes to be read.

    I think your issue is that you need to rewind your stream back to the beginning again in your execute method, so it's ready to be read by the EPM (which you have effectively done):

    pInMsg.BodyPart.Data.Position = 0;

    Cheers,

    James.

    Wednesday, December 9, 2015 12:29 AM