Using Datasets in WCF and Webservices with Legacy Applications
Recently I came across the issue of XML DataTable to Clean XML, specifically the problem of “Web Service has to deliver neutral/agnostic XML and NOT .NET related information.” The solution code used XmlDocument which is not the best performing, as well as not being to “monkey-see, monkey-do” quality that is often needed.
The solution is simple if you add an extension to the dataset as shown below:
/// <summary> /// Returns a dataset as a Xml String /// </summary> /// <param name="ds">A DataSet</param> /// <param name="isDotNet">If true, optimize for .Net client, if false for Legacy(Java)</param> /// <param name="includeSchema">If true,include the Schema in the Xml</param> /// <returns>The dataset serialized as Xml</returns> public static string GetXml(this DataSet ds, bool isDotNet, bool includeSchema) { var swriter = new StringWriter(); using (var xwriter = new XmlTextWriter(swriter)) { xwriter.Formatting = Formatting.Indented; if (includeSchema) { ds.WriteXml(xwriter, XmlWriteMode.WriteSchema); } else { ds.WriteXml(xwriter, XmlWriteMode.IgnoreSchema); } } if (isDotNet) { return swriter.ToString(); } // remove the Microsoft tags XDocument doc = XDocument.Parse( swriter.ToString(), LoadOptions.PreserveWhitespace); XNamespace namespaceToRemove = XNamespace.Get("urn:schemas-microsoft-com:xml-msdata"); doc.Descendants().Attributes().Where( a => a.Name.Namespace == namespaceToRemove).Remove(); doc.WriteTo(new XmlTextWriter(swriter = new StringWriter())); return swriter.ToString(); }
What is the result? With isDotNet=true, we get the code below (with the offending items being struck thru):
<NewDataSet>
<xs:schema id="NewDataSet" xmlns="" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xs:element name="NewDataSet" msdata:IsDataSet="true" msdata:UseCurrentLocale="true">
<xs:complexType>
<xs:choice minOccurs="0" maxOccurs="unbounded">
<xs:element name="Table1">
<xs:complexType>
<xs:sequence>
<xs:element name="LastName" type="xs:string" minOccurs="0" />
<xs:element name="WT" msdata:DataType="System.DateTimeOffset" type="xs:anyType" minOccurs="0" />
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:choice>
</xs:complexType>
</xs:element>
</xs:schema>
<Table1>
<LastName>Lassesen</LastName>
</Table1>
</NewDataSet>
With isDotNet=false, we get:
<?xml version="1.0" encoding="utf-16"?><NewDataSet>
<xs:schema id="NewDataSet" xmlns="" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xs:element name="NewDataSet">
<xs:complexType>
<xs:choice minOccurs="0" maxOccurs="unbounded">
<xs:element name="Table1">
<xs:complexType>
<xs:sequence>
<xs:element name="LastName" type="xs:string" minOccurs="0" />
<xs:element name="WT" type="xs:anyType" minOccurs="0" />
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:choice>
</xs:complexType>
</xs:element>
</xs:schema>
<Table1>
<LastName>Lassesen</LastName>
</Table1>
</NewDataSet>
Summary
This means that instead of having one contract that is .Net specific:
[OperationContract]
DataSet GetAccountSummary(string user);
We could use the following which performs as well for .Net and simplifies use from Java or other Legacy issues.
[OperationContract] String GetAccountSummary(string user, bool isDotNet, bool includeSchema);
Comments
Post a Comment