Moving DataSets through BizTalk
- by EltonStoneman
[Source: http://geekswithblogs.net/EltonStoneman]
Yuck. But sometimes you have to, so here are a couple of things to bear in mind:
Schemas
Point a codegen tool at a WCF endpoint which exposes a DataSet and it will generate an XSD which describes the DataSet like this:
<xs:elementminOccurs="0"name="GetDataSetResult"nillable="true">
<xs:complexType>
<xs:annotation>
<xs:appinfo>
<ActualTypeName="DataSet"
Namespace="http://schemas.datacontract.org/2004/07/System.Data"
xmlns="http://schemas.microsoft.com/2003/10/Serialization/" />
</xs:appinfo>
</xs:annotation>
<xs:sequence>
<xs:elementref="xs:schema" />
<xs:any />
</xs:sequence>
</xs:complexType>
</xs:element>
In a serialized instance, the element of type xs:schema contains a full schema which describes the structure of the DataSet – tables, columns etc. The second element, of type xs:any, contains the actual content of the DataSet, expressed as DiffGrams:
<GetDataSetResult>
<xs:schemaid="NewDataSet"xmlns:xs="http://www.w3.org/2001/XMLSchema"xmlns=""xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xs:elementname="NewDataSet"msdata:IsDataSet="true"msdata:UseCurrentLocale="true">
<xs:complexType>
<xs:choiceminOccurs="0"maxOccurs="unbounded">
<xs:elementname="Table1">
<xs:complexType>
<xs:sequence>
<xs:elementname="Id"type="xs:string"minOccurs="0" />
<xs:elementname="Name"type="xs:string"minOccurs="0" />
<xs:elementname="Date"type="xs:string"minOccurs="0" />
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:choice>
</xs:complexType>
</xs:element>
</xs:schema>
<diffgr:diffgramxmlns:diffgr="urn:schemas-microsoft-com:xml-diffgram-v1"xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<NewDataSetxmlns="">
<Table1diffgr:id="Table11"msdata:rowOrder="0"diffgr:hasChanges="inserted">
<Id>377fdf8d-cfd1-4975-a167-2ddb41265def</Id>
<Name>157bc287-f09b-435f-a81f-2a3b23aff8c4</Name>
<Date>a5d78d83-6c9a-46ca-8277-f2be8d4658bf</Date>
</Table1>
</NewDataSet>
</diffgr:diffgram>
</GetDataSetResult>
Put the XSD into a BizTalk schema and it will fail to compile, giving you error: The 'http://www.w3.org/2001/XMLSchema:schema' element is not declared. You should be able to work around that, but I've had no luck in BizTalk Server 2006 R2 – instead you can safely change that xs:schema element to be another xs:any type:
<xs:elementminOccurs="0"name="GetDataSetResult"nillable="true">
<xs:complexType>
<xs:sequence>
<xs:any />
<xs:any />
</xs:sequence>
</xs:complexType>
</xs:element>
(This snippet omits the annotation, but you can leave it in the schema).
For an XML instance to pass validation through the schema, you'll also need to flag the any attributes so they can contain any namespace and skip validation:
<xs:elementminOccurs="0"name="GetDataSetResult"nillable="true">
<xs:complexType>
<xs:sequence>
<xs:anynamespace="##any"processContents="skip" />
<xs:anynamespace="##any"processContents="skip" />
</xs:sequence>
</xs:complexType>
</xs:element>
You should now have a compiling schema which can be successfully tested against a serialised DataSet.
Transforms
If you're mapping a DataSet element between schemas, you'll need to use the Mass Copy Functoid to populate the target node from the contents of both the xs:any type elements on the source node:
This should give you a compiled map which you can test against a serialized instance. And if you have a .NET consumer on the other side of the mapped BizTalk output, it will correctly deserialize the response into a DataSet.