Introduction
This article details a simple but powerful method of transferring data persisted in a relational typed dataset from a WCF Service to BizTalk Server, thus allowing the developer the opportunity to use the BizTalk Mapper to transform a WCF response message to an end destination message easily.
Background
I am currently working on an integration project which mainly focuses on parsing and processing HL7 messages.. yeah, you read it right, "HL7" meaning, we need to deal with lots of elements for a single message.
Now, for one of the HL7 message types (VXQ), I had to implement the Request-Response model of the solution using BizTalk Server, with the HL7 Accelerator as my parsing and transformation engine, and WCF as my SOA comprising of the business logic and data tier that would interact with SQL Server to retrieve the data requested in the VXQ message.
In simple, VXQ requests for a patient and his hierarchical data that we have in our fully relational tables in a SQL Server database.
Bird's eye view of the steps to be followed
- Create the typed dataset replicating the data relations as in the datastore (in this article, it is SQL Server).
- Create a single Stored Procedure that will return multiple resultsets for all the tables that you need to construct the outbound message for.
- Populate the dataset using your preferred approach, or the conventional ADO.NET approach, i.e.,
DataAdapter.Fill
will fill all the tables returned by the Stored Procedure. - Using XSDObjectGenerator.exe, create the serializable class of the typed dataset, so it can be used as the
DataContract
for the WCF part. - Create the WCF part and specify the operation contract and data contract (with the serializable class created in step 4).
- Convert the dataset to the serializable XML object that can be sent to BizTalk.
- Publish the WCF service and consume it in BizTalk Server Orchestration using the request_response port.
Using the code
- Create the typed dataset (HL7dataset.xsd) and define the data relation: We can do this by simply dragging and dropping the tables of interest from the Server Explorer or creating them in Visual Studio. Please see the screenshot below:
Make sure you enable the "Nested Relation" checkbox. Otherwise, the code generation (XSDobjectGen) will not be able to create the hierarchical class for you.
- Create the Stored Procedure to return the multiple dataset: This is fairly simple and you can find a lot of articles for the same in CodeProject.
- Populate the dataset using DataAdapter.Fill: Here, we have to use table index based data population to the dataset from the SQL Server source. Refer to the code below.
scmd.Connection = new SqlConnection(@"Data Source="[ServerName]";Initial " +
@"Catalog=[DatabaseName];Persist Security " +
@"Info=True;User ID=User;Password=welcome");
SqlDataAdapter sadapter = new SqlDataAdapter(scmd);
sadapter.TableMappings.Add("Table", "HL7Patients");
sadapter.TableMappings.Add("Table1", "HL7Contacts");
sadapter.Fill(objHL7dataset);
Note that, we have to use table mappings to fill the typed dataset. It would not automatically load based on the table names; hence, we need to use table indexes and correlate the order in the Stored Procedure as well.
- Using the XSDObject generator, create the serializable class of the typed dataset: You can download the XSDObjectGenerator from here.
Create the serializable class by using the VS command prompt with the following command:
[Directory]\XSDObjectGenerator>XSDObjectGen.exe HL7dataset.xsd
/l:cs /n:"MyProject.HL7Services" /f:HL7dataset.cs
- Create the WCF part and specify the operation contract and data contract (with the serializable class created in step 4): Create the XML serializable WCF service using the attribute
[XmlSerializerFormat]
for the operation.
[ServiceContract]
public interface IVXQService {
[OperationContract]
[XmlSerializerFormat]
MyProject.HL7Services.HL7DataSet ProcessVXQ(InboundMsg objVXQ);
}
Note: The "HL7DataSet
" that you see in the above code is not the typed dataset, but instead, it is the XMLSerializable class that was created in step 4. To avoid conflict with class names and its members, make sure you use different namespaces, but retain the class name as-is. Otherwise, we won't be able to convert the typed dataset to the XMLSerializable class and send it to BizTalk.
- Convert the DataSet to the serializable XML object: This is the trickiest part. Here we convert the dataset to a
MemoryStream
and then deserialize it to a message that will be sent to BizTalk.
MemoryStream stream = new MemoryStream();
XmlTextWriter writer = new XmlTextWriter(stream, System.Text.Encoding.UTF8);
writer.WriteStartDocument();
ds.WriteXml(writer); stream.Seek(0, SeekOrigin.Begin);
using (StreamReader str = new StreamReader(stream))
{
XmlSerializer xs1 =
new XmlSerializer(typeof(MyProject.HL7Services.HL7DataSet));
MyProject.HL7Services.HL7DataSet Result =
(MyProject.HL7Services.HL7DataSet)xs1.Deserialize(str);
}
- Publish the WCF service and consume it in a BizTalk Server Orchestration using the request_response port: Now that the WCF service is ready, publish it and add a reference to the WCF service from the BizTalk project: "Right click the BizTalk project-->Add-->Add Generated Items-->Consume WCF Service".
Once the wizard creates and adds all the artifacts for the WCF reference, we would have a multipart message, one for the request and another for the response in the orchestration named after your WCF service (VXQService). We will be able to implement our logic in the response message either by using transform shapes or message assignment shapes.
Note: We need to import the custom binding file created by the above step using the BizTalk Administration Console, which will automatically create the Request-Response send port in the BizTalk application.
Points of interest
- Converting the typed dataset to an XML serializable object that can be transmitted to BizTalk.
- Increasing the property "
maxReceivedMessageSize="365536"
" for the WCF client (BizTalk Server Send Port) to accept an XML message of size greater than the default value. - It should work for all types of WCF bindings.
- Steps are clearly explained in the article. If anyone needs the sample code, please let me know, I would be uploading it on a demand basis.
History
Draft version.