Even though XML will be the foundation of BizTalk Dev for, well, forever and there’s nothing wrong with that, we can adopt the huge benefit of the JSON scheme while giving up absolutely no functionality. The best part, XML itself provides a completely legitimate way to avoid all of the complication that namespaces bring by just using the Empty Namespace (or no namespace, depending on where you look).
**Yes, I am aware that a namespace is implicitly part of JSON since it follows Java rules, but we can do the same thing in Xml. “Contoso.PlantName” : “Bellvue” and <Fabrikan.PlantName>Tacoma</Fabrikan.PlantName> are conceptually the same.
The sample Solution for this Article can be found in the MSDN Code Gallery at: https://code.msdn.microsoft.com/BizTalk-Simplify-BizTalk-90f4e1cf
Before we get started, I want to lay out some key benefits and important points.
Creating a Schema with the Empty Namespace is very easy. There are just two extra steps:
Step 2 is very important. I often find developers are still confused by this definition, believing that Qualified vs Unqualified refers to the use of a namespace prefix, such as ns0. This is not the case. It means that all Elements in the Schema, at any level, are qualified with the Target Namespace, whatever it is. What trips people up is that the the Target Namespace will always apply to elements defined at the Root, but not elements defined lower in the hierarchy unless Element FormDefault is Qualified.
A-ha, if you’re the inquisitive type, you will notice that when using an empty Target Namespace, the value of Element FormDefault has no effect, and you would be correct. I still recommend setting it to Qualified so that all elements are unambiguously defined in the Empty Namespace, as opposed to the ‘default’ Empty Namespace. Splitting hairs, yes, but you should be using Qualified even when using a namespace so this is also an issue of consistency.
Modifying External Schemas
If full Canonical Schemas don’t make sense for a particular app, we can still benefit from using the Empty Namespace by modifying the external schema for use within our app.
The EDI Schemas are a great candidate for this. You will still need versions of the EDI Schemas for the edge, meaning for use by the EDI Disassembler and Assembler, but within your app, Maps, Orchestrations, Rules, etc., all use Schemas with the Empty Namespace.
Modifying the EDI schemas for this purpose is very easy.
Now, you have a much simplified Schema to use within the app.
In these Properties, note the Schema Editor Extensions field is blank.
To sSchemas for the edge, meaning for use by the EDI Disassembler and Assembler, but within your app, Maps, Orchestrations, Rules, etc., all use Schemas with the Empty Namespace.
Modifying the EDI schemas for this purpose is very easy.
The EDI Schemas are easy to make namespace free since they are all self contained with no external references. This is not always the case and there are many interface schemas that use a complicated import/include scheme when defining types and structures (I’m looking at you CRM! ).
Using the CRM Schema as an example, we can’t simple remove the namespaces since that will break all the references. But, this is not a showstopper, we just have to take a quick round trip through a Generated Instance and the Schema Generator Wizard.
1. Set Root Reference to the operation you want a Schema for.
2. Right-click and choose Generate Instance.
3. Open the generated instance in the Visual Studio XML Editor.
4. Replace “ns0:”, “ns1:” and “ns2:” all with nothing. You don’t need to do anything about the xmlns declarations since the Schema Generator will ignore them.
5. Use the Well-formed XML Schema Wizard to generate a Schema from the modified instance.
The wizard will generate a single .xsd representing the Create operation for CRM. Verify the Element FormDefault is set to Qualified and the TargetNamespace option is empty.
You now have a very much simplified Schema to use within your app.
**Note, having done this several times, it’s worth pointing out that while the Schema Wizard usually does a really great job, it’s not always perfect. So, during development, I recommend you run the either the XmlAssembler with Validation on or use the XmlValidator component to catch any differences between the inferred Schema and the actual messages.
Now that we have simple, easy to use Schemas using the Empty Namespace, we have to get our incoming message to conform. There are two ways to accomplish this, a Pipeline Component that strips namespaces and references or a Map. The choice depends on weather or not you are using an dedicated Canonical Schema or a Schema copy with the Empty Namespace.
A Map is the best option if you meet these two criteria:
In these two cases, using a Map allows you to remove the namespaces and modify the structure at the same time. Also, since a Map would be used to create the outgoing message, which likely would require namespaces, this keeps the two operations consistent. Creating the Map from the incoming to Canonical is the exact same Mapping process we would do in any app, including converting data, changing structure and anything else that needs to be done. The fact that the the destination Schema is namespace free is irrelevant.
However, if one of these apply:
Then a Pipeline Component is the best option. The reason this applies for case 2 is that using the Empty Namespace significantly reduces mapping complexity, especially if custom Xslt is required. For this scenario, the pattern would be:
The compiled Assembly is included with the sample Solution linked above.
Because the Empty Namespace is part of XML, all of BizTalk Server and .Net fully support the use of XML documents with an Empty Namespace. This applies to the Schema Designer, Map Designer, XML Disassembler and Assembler, the Flat File Disassembler and Assembler, Orchestration Designer and Engine (including the xpath() function), Xslt. Simply, there is no technical requirement for anything other then the Empty Namespace.
Here are some examples of why using the Empty Namespace is better:
CRM Value With Namespaces: /*[local-name()='Create' and namespace-uri()='http://schemas.microsoft.com/xrm/2011/Contracts/Services']/*[local-name()='entity' and namespace-uri()='http://schemas.microsoft.com/xrm/2011/Contracts/Services']/*[local-name()='Attributes' and namespace-uri()='http://schemas.microsoft.com/xrm/2011/Contracts']/*[local-name()='KeyValuePairOfstringanyType' and namespace-uri()='http://schemas.microsoft.com/xrm/2011/Contracts']/*[local-name()='value' and namespace-uri()='http://schemas.datacontract.org/2004/07/System.Collections.Generic']
CRM Value with the Empty Namespace: /Create/entity/Attributes/KeyValuePairOfstringanyType/value
CRM XPath with conditions: /Create/entity/Attributes/KeyValuePairOfstringanyType[key = ‘customerName’]/value
Of interesting note, on the MSDN page titled XPath Examples, every sample uses the Empty Namespace. See here: XPath Examples
EmptyNamespaceFlatFileSent = EmptyNamespaceFlatFileReceived;
xpath(EmptyNamespaceFlatFileSent,
"/EmptyNamespaceFlatFile/EmptyNamespaceFlatFile_Child1[2]/EmptyNamespaceFlatFile_Child1_Child2"
) =
"SET IN ORCHESTRATION"
;
Xslt gety Namespace. See here: XPath Examples
With Namespaces:
<
xsl:element
name
=
"MyOutputElementName"
namespace
=
"
http://MyNamespace"
>
<
xsl:text
>MyOutputValue</
xsl:text
><
br
>
</
xsl:element
>
With the Empty Namespace:
<
MyOutputElementName
>
<
xsl:text
>MyOutputValue</
xsl:text
>
</
MyOutputElementName
>
Because the Empty Namespace is completely valid XML, the XmlDisassembler and XmlAssembler work without issue.
Similar to the XML components, the Flat File Assembler and Disassembler work with Empty Namespace Schemas without issue. There is one exception in the Flat File Experience. The Flat File Schema Wizard requires a Target Namespace be entered with running the Wizard. But, this Target Namespace can be immediately deleted from the generated Schema
Oddly, there is a bug in the JSON Decoder component in that it requires a value for the RootNodeNamespace property, otherwise, a runtime error is thrown. This problem is compounded by the lack of a way to set the scope of the namespace. Fortunately, this is very easy to work around this by using the above referenced Empty Namespace Pipeline Component.
The JSON Encoder works with Empty Namespace message without issue.
For the long foreseeable future, we will have to XML with namespace to apps that still require them. This is actually requires the least effort and should happen normally in most apps.
Adding any required namespaces to outbound documents should happen naturally and without any additional effort in the final map to the outbound format, meaning, it’s just another mapping operation. Because the source document uses the Empty Namespace, we still get most of the benefits and most of the problems are well hidden by the Mapper.
For cases, such as EDI, where we are using a copy of a schema with an Empty Namespace, the Mapping operation is just the opposite of the Map to remove the namespace.
In many cases, there is no extra effort to use the Empty Namespace in out app, especially if we can do this in an existing Mapping operation. Also, the Empty Namespace Pipeline Component uses a Stream implementation for minimal impact. So, in most cases, any ‘performance’ impact would be barely detectable.
Also worth considering is that XML Documents using only the Empty Namespace are much smaller, often by more than half. Moving around fewer bits is always better so the ‘cost’ of removing namespaces can be made up by saving the cost of handling them. This applies to memory, network and storage.
Finally, while a lot of unnecessary effort is put on runtime performance, I see too often where dev-time performance issues are ignored. Eliminating the burden of namespaces in our app development is well worth the expense of CPU time probably measured in minutes over a year. I compare that to the hours spent in XPath/Xslt/Schema dev cycles just to deal with namespace issues. That is hours plus hours we can use to make better apps in every other way.
Happy BizTalking!