Frequently I find myself at clients explaining BizTalk best practices and one of the items I always try and push forward is proper schema inheritance practices. Much like object-oriented design, schema inheritance can help create a nice canonical domain model. However, there are always questions as to which type of inheritance to use. While these practices go beyond just BizTalk, I wanted to focus this on implementation within the BizTalk tools.
Microsoft (and others) do put out documentation on this very subject but it doesn’t really go into any good examples of each type so I plan to plug that gap here. The first few sections go into some background and other practices … if you are just looking for examples and practices for the given types feel free to skip ahead.
Types of Schema Inheritance
To summarize, there are three ways to re-use schemas within your BizTalk solution:
- XSD Import – Importing types from another schema/namespace
- XSD Include – Importing types from another schema within the SAME namespace
- XSD Redefine – Importing types from another schema with the intent on extending/overriding the types
These all sound very similar in definition but there are some key usage scenarios for each in practice.
Organization of Schemas
Before going into the re-use of schemas it is important to think of re-use of your schemas beyond just your solution and extend into the greater collection of BizTalk applications at a given organization. This becomes even MORE crucial in the realm of BizTalk when dealing with dependency, deployment and maintenance issues. Without getting into too much detail, here are some quick pointers:
- When creating canonical schemas to be shared with multiple BizTalk applications they MUST be isolated in their own project/assembly.
- Treat yourself like a 3rd party vendor when consuming these schemas: add a reference to a well-known, strongly versioned DLL of these schemas
- Remember that BizTalk only allows a given schema message type to be defined once in the entire BizTalk group so sharing these at the source code level won’t work
- Track these central schemas as a separate project/lifecycle so that there is a clean separation between your consuming application and these soon-to-be highly shared schemas
- Enforce schema versioning (especially in the namespace) from the beginning. When you roll out an update you’ll not only have to version the .NET DLL but also the schema namespace
The first step in re-using other schemas is to define the reusable schema itself (obviously) but then to create actual schema types (ComplexType) out of the bits to re-use. This is the simple part: Simply select the “record” node which you want to re-use/share and set the DataStructureType property to the name you wish to use for the type. The following screen shot shows the data structure type property.
BizTalk - Schema Data Structure Type
It would be a good idea to define a naming standard/practice for these types … I generally use something like the node name plus the word type. For example if I were creating an Order schema I would create a complex type named simply: OrderType.
The following sections define a typical usage scenario for each type of schema inheritance.
XSD Import – Composition
Frequently, you have the same type of information repeated throughout your projects and solutions. A classic example is the Address. When defining a schema like Order, you can have several addresses all containing the same fields but representing different locations. For example, you may want to have a shipping and billing address in your order and ensure the addresses are consistent. This is very simple to accomplish:
- Create a schema which represents your address, and create a ComplexType out of it as in the above example.
- Create a schema called Order and ensure it has a different target namespace than the Address schema
- Click on the <Schema> node, then open the Imports collection in the properties window
- In this windows you’ll now be able to “XSD Import” the address schema into the Order schema
The following screenshots depict the XSD Import of the Address schema:
Next, create a couple of Child Records nodes for holding a Billing and a Shipping address. In the properties window for each record, set the Base Data Type to the complex type created above.
Base Data Type
Now as the address type is changed, it will be reflected in your Order schema as well.
Another, perhaps more useful, example is adding additional context details to a schema. Take, for example, the Order Schema created above. If you wanted to add additional process context items you could wrap the order schema into another schema (call it: MyProcessOrder) where a child record node represents the Order and additional items are added as sibling nodes. Using this method isolates your Order schema as the “Order entity” without poluting it with non-Order related attributes.
XSD Include – Batch Schemas
XSD Includes are slightly different from Imports in that the target namespaces of the schema and the included schema must match. The primary use case I have used here is when creating envelope schemas used for debatching. Continuing the above Order example, convert the Order schema to a ComplexType (using the Data Structure Type node) so it can be included in another schema.
Use the following steps to create an Orders schema containing one or more Order records:
- Create a new schema called Orders
- Ensure the target namespace of the Order and Orders schema are IDENTICAL
- Open the Imports collection (same as above) and now you can “XSD Include” the Order schema
- Now, add a child record and set it’s type to the OrderType created above
The following screen shots show including the Order schema into the Orders envelope schema:
And then creating the Order record …
Since this will be used for debatching, a few more properties need set at:
- Envelope: Yes
- Root Reference: Orders
- On the Orders node, set the Body Xpath property to point to the Order node
- On the Order node, set the maxOccurs to unbounded
XSD Redefine – Embrace and Extend
The XSD Redefine is probalby the least uses type of schema reuse for me as I genreally find myself using it to “hack” around another schema or trying to over-simplify something … and actually making it more cumbersome in the end.
An easy example of this is to take the AddressType above and create a new type from it to include some phone numbers:
- Create a new schema called AddressPhoneType
- Ensure the namespace on AddressPhoneType matches that of AddressType above
- As above, use the Imports property to “XSD Redefine” the Address schema
- Add a new child record and set its Data Structure Type property to AddressType (this is different from earlier where the Base Data Type property was used)
- Now, add a new Sequence Group to the new child record and customize!
The following screen shot depicts the AddressPhoneType schema:
Now you can change the Address schema without affecting other “consumers” of it. Very useful if you want to embrace the re-usability of the Address type but not break aa bunch of other schemas which inherit it as well.
Now, with the above examples BizTalk developers can embrace re-usability in their BizTalk schemas along with other best practices!