Fellow BizTalk developer Bram Veldhoen was kind enough to send me some suggestions for a future version of my PipelineTesting library, as well as with a question that could point to a potential bug in the library.

The problem basically revolves around consuming a stream returned by the XML Assembler component in a send pipeline when testing under a library. What Bram noticed was that executing the pipeline would seem to work, but trying to read the body part stream of the output message would fail with a ComException with error code 0x8004005 (E_FAIL).

I was fairly confident this should've been working, based on my own use of the library, but I sat down to test it just to make sure. What I discovered was that indeed this can happen if the pipeline context for the test is not aware of the schema for the message being processed by the pipeline.

I added a new test to the library to make sure this was working correctly:

[Test]
public void CanReadXmlAssemblerStream() {
   SendPipelineWrapper pipeline = Pipelines.Xml.Send()
      .WithSpec<Schema3_FF>();
   IBaseMessage input = MessageHelper.CreateFromStream(
      DocLoader.LoadStream("CSV_XML_SendInput.xml")
      );
   IBaseMessage output = pipeline.Execute(input);
   Assert.IsNotNull(output);
   // doc should load fine
   XmlDocument doc = new XmlDocument();
   doc.Load(output.BodyPart.Data);
   XmlNodeList fields = doc.SelectNodes("//*[local-name()='Field3']");
   Assert.Greater(fields.Count, 0);
}

There are a few things to keep in mind about this issue:

  1. If you're using the XML Assembler, make sure your pipeline context has all the necessary schemas. There are three ways you can do this, depending on how you are creating the pipeline:
    1. If you're using the original raw API, you can use the AddDocSpec() method of the SendPipelineWrapper class.
    2. If you're using the new, simple API, you can add the schema through the WithSpec() method, which is what the test above does.
    3. If you're using the simple API, but you're dynamically creating the pipeline, you can just add the schemas directly in the XmlAssembler configuration using the WithDocumentSpec() and WithEnvelopeSpec() methods (see the XmlAssembler.cs file for details).
  2. Make sure you're testing the right thing. Sometimes, it's enough to make sure that the pipeline can be executed successfully. Remember, however, that pipelines are streaming beasts, so a lot of the work will oftentimes happen just when you read the resulting stream, thus causing the processing to happen.
    This is exactly the scenario we're seeing here today.

The second point is really important, but, for some reason, I never put much emphasis in it when creating the library and when talking about it. I think this is important enough to warrant doing something about it.

For starters, I've committed a few changes to the PipelineTesting repository. Besides adding the test above, I've also added a few ConsumeStream() and ReadString() helper methods to the MessageHelper class to make it easier to validate your components work by simply reading the entire stream from a message. I'll add a few other helper methods for this later on, but the idea is to make it so that you can write less code for your tests.

Technorati tags: ,


Tomas Restrepo

Software developer located in Colombia.