Reputation: 485
I'm using a WCF restful webservice with framework 4.0. I want to serialize a datatable as XML and return the resulting XML. I have this working, but I can't help but feel there is a better way.
I initially started out doing the following:
[WebGet(UriTemplate = "")]
public DataTable helloWorld()
{
using (DataTable dt = new DataTable("Test"))
{
dt.Columns.Add("Message");
dt.Rows.Add(dt.NewRow());
dt.Rows[0]["Message"] = "Hello World";
return dt;
}
}
Which gave me the following undesired results:
<DataTable xmlns="http://schemas.datacontract.org/2004/07/System.Data">
<xs:schema id="NewDataSet" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns="" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xs:element name="NewDataSet" msdata:IsDataSet="true" msdata:MainDataTable="Test" msdata:UseCurrentLocale="true">
<xs:complexType>
<xs:choice minOccurs="0" maxOccurs="unbounded">
<xs:element name="Test">
<xs:complexType>
<xs:sequence>
<xs:element name="Message" type="xs:string" minOccurs="0"/>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:choice>
</xs:complexType>
</xs:element>
</xs:schema>
<diffgr:diffgram xmlns:diffgr="urn:schemas-microsoft-com:xml-diffgram-v1" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<DocumentElement xmlns="">
<Test diffgr:id="Test1" msdata:rowOrder="0" diffgr:hasChanges="inserted">
<Message>Hello World</Message>
</Test>
</DocumentElement>
</diffgr:diffgram>
</DataTable>
After a bit of tinkering I came up with the following code, which is a bit clunky. Is there a better way? Why can't I dispose the memory stream? Do I have a memory leak?
[WebGet(UriTemplate = "")]
public Stream helloWorld()
{
WebOperationContext.Current.OutgoingResponse.ContentType = "text/xml";
using (DataTable dt = new DataTable("Test"))
{
dt.Columns.Add("Message");
dt.Rows.Add(dt.NewRow());
dt.Rows[0]["Message"] = "Hello World";
using (StringWriter sw = new StringWriter())
{
dt.WriteXml(sw, System.Data.XmlWriteMode.IgnoreSchema, false);
MemoryStream ms = new MemoryStream(Encoding.UTF8.GetBytes(sw.ToString()));
return ms;
//this fails for some reason
//using (MemoryStream ms = new MemoryStream(Encoding.UTF8.GetBytes(sw.ToString())))
// return ms;
}
}
}
This code gives me the desired result (I'm not picky about the root tag):
<DocumentElement>
<Test>
<Message>Hello World</Message>
</Test>
</DocumentElement>
Upvotes: 2
Views: 3368
Reputation: 13976
I recommend using WCF Data Services to do this. They implement the OData protocol, meaning they are built to expose data in a consistent and portable way. Serialization can be done to either JSON or XML.
Samples:
Upvotes: 1
Reputation: 598
I would suggest using a DataContract for the serialization:
This is a good tutorial on how to do this: http://www.codeproject.com/Articles/105273/Create-RESTful-WCF-Service-API-Step-By-Step-Guide
You create a contract interface where you define all the necessary methods.
In your case something like this:
namespace MyProject.HelloWorld {
[ServiceContract]
public interface IHelloWorld {
[OperationContract]
[WebGet(UriTemplate="", ResponeFormat=WebMessageFormat.Xml)]
HelloWorldResult helloWorld();
}
[DataContract()]
public class HelloWorldResult {
[DataMember]
public String Message {get; set;}
}
}
Just implement the Interface IHelloWorld in your Service.svc and return a new Instance of a HelloWorldResult class:
public HelloWorldResult helloWorld() {
return new HelloWorldResult() {
Message = "Hello World!"
};
}
But you must tell the endpoint to use the IHelloWorld Service Contract as the contract (see tutorial: http://www.codeproject.com/Articles/105273/Create-RESTful-WCF-Service-API-Step-By-Step-Guide --> Step 6)
Hope this helps
cheers
Upvotes: 0