Validating an untyped XML message in a BizTalk Orchestration
Receiving an untyped message (a System.Xml.XmlDocument) in a BizTalk orchestration offers a lot of flexibility in design. The same code can be used for many different message types, and schema changes don’t require reworking your ports and receive shapes. However, you lose some of the advantages of working with strongly typed messages – your orchestration could very well get a malformed message that is invalid by structure or content, and you won’t know until further down the line when another component that does validate the message (such as a send port) throws an exception. Many times this isn’t a concern, but I was recently working on a solution where the orchestration received untyped messages and needed to know whether the message would validate against its schema or not. Other components in the integration that processed the message later were not open for modification, and since the message was being constructed by the orchestration I couldn’t just add the XML Validator component to the receive pipeline for the orchestration.
There are a few different ways to handle this scenario. XmlDocument provides a Validate() method that takes a callback function it sends warnings and errors to. This method requires that you add the correct schema for the message type. This could be accomplished with a C# helper class:
This class could be invoked from an orchestration as follows (where tSchema is a System.Type varaible, strFQN is the fully qualified name of the library, and varXmlDoc is the System.Xml.XmlDocument):
varSchema = System.Type.GetType(strFQN); blnIsValid = Utilities.XmlValidator.Validate(varXmlDoc, varSchema);
However, this method becomes fairly cumbersome. You will have to keep track of the fully qualified names of the schemas for your particular message type, and you start facing painful design decisions about where and how to store that information.
A better approach involves calling a custom pipeline that has the default XML Validator component built in. Adding in the XML assembler provides an additional benefit of properly promoting the standard context properties for a constructed message. I designed the following pipeline:
The default properties were fine here. By leaving the Document schemas property empty, it will perform the default schema resolution (using the BTS.MessageType property) to automatically find the deployed schema for the message. This pipeline is in an assembly named Tallan.BizTalk.Pipelines, with the class name XmlValidatorPipeline. Then, the following code can be used in a Construct Message or Expression shape in an Atomic scope:
// the default XMLRecieve pipeline will promote the properties, but won't do XSD validation on the document // varXMLReceivePipelineType = System.Type.GetType("Microsoft.BizTalk.DefaultPipelines.XMLReceive, Microsoft.BizTalk.DefaultPipelines, Version=188.8.131.52, Culture=neutral, PublicKeyToken=31bf3856ad364e35"); // varXMLReceivePipelineType is a System.Type; varRecievePipelineOutputMessages is a Microsoft.XLANGs.Pipeline.ReceivePipelineOutputMessages varXMLReceivePipelineType = System.Type.GetType("Tallan.BizTalk.Pipelines.XmlValidatorPipeline, Tallan.BizTalk.Pipelines, Version=184.108.40.206, Culture=neutral, PublicKeyToken=<PKT>"); varReceivePipelineOutputMessages = Microsoft.XLANGs.Pipeline.XLANGPipelineManager.ExecuteReceivePipeline(varXMLReceivePipelineType, msgXml); varReceivePipelineOutputMessages.MoveNext(); varReceivePipelineOutputMessages.GetCurrent(msgXml);
Now, the pipeline will take care of throwing an exception if the document is invalid, and the schema will be automatically resolved based on the message type! If you’re not familiar with calling pipelines from orchestrations, check out the MSDN article here: https://msdn.microsoft.com/en-us/library/aa562035.aspx