It's always a good practice to validate your incoming messages against schema to make sure you discard useless messages up front and avoiding unnecessary processing.
BizTalk allows you to verify the validity of the incoming Xml message against deployed schema in few different ways. Some of the easy options are
- Using XmlReceive pipeline and setting the ValidateDocument property to true.
- Create a custom Receive Pipeline and use the XmlValidate pipeline component in the validate stage.
In both the scenarios, the incoming message is validated inside a receive pipeline and an exception is raised if the message fails validation, eventually suspending the pipeline service instance. You'll see description of the error messages both in event log and suspended instance with associated messages in the admin console.
Here are the few challenges in a real world situation:
- The default Xml validation component supplied with BizTalk (both the above cases) only notifies you about the very first error message it encounters.
- It simply suspends the service instance, and its all your responsibility to take necessary action (configure routing failure, or administrator taking appropriate action etc). If you don't take any action, the consumer won't get any clue about the validation failure.
Our (improved) requirements are:
- We need to get all the schema validation exceptions at one go. Say for example, if there are 4 validation errors in the incoming message, then we need to see the reasons for all the 4 errors.
- Also, there should be an accessible error message with all the error descriptions, which we can map it to a response to send it back to the consumer (explained later.) in addition to suspending the service instances.
NOTE: Attached sample code got all the relevant materials discussed in this article.
Sample Schema, Extended Pipeline component code, Sample receive pipeline, Sample Orchestration and required binding file.
Test Schema definition:
employeeId: Is a string that contain only numbers of 5 chars long.
jobSpecification: Manager, Programmer, Analyst.
firstName/lastName: Can only be of alphabets.
Validation using XmlReceive default pipeline:
You can enable validation inside the default XmlReceive pipeline by setting ValidateDocument property to true. But there is a trick, if you enable this property you need to set the DocumentSpecName property as well specifying the schemas. Unfortunately it doesn't resolve the schemas automatically, and you'll see clear exception message saying
There was a failure executing the receive pipeline: "Microsoft.BizTalk.DefaultPipelines.XMLReceive, Microsoft.BizTalk.DefaultPipelines, Version=126.96.36.199, Culture=neutral, PublicKeyToken=31bf3856ad364e35" Source: "XML disassembler" Receive Port: "Receive.XmlReceive" URI: "C:@BlogXmlValidationFileDropXmlReceiveIn*.xml" Reason: Validation can only be performed when document schemas are provided.
DocumentSpecName property must be specified in this format (it's not documented clearly and took me a while to figure out)
DDL.Demo.Schemas.EmployeeRequest, DDL.Demo.Schemas, Version=188.8.131.52, Culture=neutral, PublicKeyToken=c2b0cafd9314ef3e
DDL.Demo.Schemas: Schema .net namespace
EmployeeRequest: Type name defined for the Schema
DDL.Demo.Schemas: Fully qualified assembly name.
(You can easy get these values from BizTalk Admin Console by opening the schema)
If you receive more than one message type inside the same pipeline, you can add multiple DocumentSpecNames by splitting it with a pipe (|) symbol.
Validation using XmlValidator pipeline component:
Configuring and performing validation using the out of the box XmlValidator component is simple. Follow these easy steps:
- Create a blank BizTalk project and add New item of type Receive Pipeline
- From the BizTalk tool box, drag and drop the XmlValidator component into the Validate Stage
- Assign strong key and deploy the pipeline.
- In the BizTalk administration console, create a receive port/ location utilizing the pipeline deployed in #3.
- Get a message into the configured receive port via your choice of adapter File, HTTP, etc
The XmlValidator component should resolve the schema dynamically and validate the message against the schema. If there are any exceptions it will raise an exception and suspends the instance.
I created a sample message as shown below
There are 3 invalid elements in the schema. employeeId is not in the right format and both first name and last name got some invalid characters (according to our schema definition only alphabets are allowed).
Firing the above message with validation enabled (either one of the above methods) will raise the exception and suspends the service instance. The exception message will be:
The document failed to validate because of the following error:"The 'employeeId' element has an invalid value according to its data type." .
Correcting the above error in the message and firing it second time will show the second validation failure as below
The document failed to validate because of the following error:"The 'firstName' element has an invalid value according to its data type." .
Extended XmlValidation pipeline component:
In most of the cases it not useful to get one error message at a time, consumers would like to receive all the validation failure messages at one go, so that they correct all of them and send the message back.
This problem forces us to write the extended XmlValidation pipeline component, which basically extend the functionality of the default BizTalk XmlValidation component to raise all the errors at one go and also give a serialized exception message, which you can easily to map it to a customer specific response message.
The complete source code is available for download here.
Firing the message via the extended validation component will raise the following error description.
There was a failure executing the receive pipeline: "DDL.Pipeline.ExtendedXmlValidation, DDL.Pipeline, Version=184.108.40.206, Culture=neutral, PublicKeyToken=c2b0cafd9314ef3e" Source: "Pipeline " Receive Port: "Receive.ExtendedXmlValidation" URI: "C:@BlogXmlValidationFileDrop ExtendedXmlValidation.In.ReceivePortIn*.xml" Reason: Exception of type 'DDL.PipelineComponents.XmlValidationException' was thrown.NodeName: employeeIdNodeValue: 12 NodeNameSpace: . Severity: Error. Description: The 'employeeId' element has an invalid value according to its data type.. NodeName: firstNameNodeValue: firstName007 NodeNameSpace: . Severity: Error. Description: The 'firstName' element has an invalid value according to its data type.. NodeName: lastNameNodeValue: lastName008 NodeNameSpace: . Severity: Error. Description: The 'lastName' element has an invalid value according to its data type..
So, you can see clearly you got all the validation failures at one go and also you got extra information like the node value, severity of the error (whether its error or warning) etc.
Sending the validation failure message back to caller:
One of the other big challenges is sending this exception message to the caller or to some other system to process. Just plainly terminating the service is instance is not useful most of the time.
We utilised BizTalk 2006 ability to call Receive pipeline within orchestration to achieve this.
First a response schema is defined as shown below, which contains an errors collection node with description and nodeName elements inside.
The sample orchestration looks like:
Inside the Schema Validation expression shape we called our custom pipeline as shown below:
An exception handler is created to catch exceptions of type Microsoft.XLANGs.Pipeline.XLANGPipelineManagerException
Exception message is created inside the 2nd construct shape using the following statement
schemaException = (DDL.PipelineComponents.XmlValidationException)exSchemaValidation.InnerException;
MSG_XML_VALIDATION_ERROR = schemaException.ErrorCollection;
Note we are accessing the innerException property of the XLANGPipelineManager exception.
If there are no schema validation exceptions a response message will be constructed normally (first construct shape). Else if the control goes to the exception handler block a map is applied to transform the errors from XmlValidation to the response message as shown below
The response message will look like:
Setting up the sample file:
Unzip the content to C:@blogXmlValidation folder. Open DDL.Demo.PipelineComponent solution and compile it, open XmlValidation.sln build and deploy it. Binding file is present.