I\'ve got a web app that sends a request to a WCF service. The WCF service gets a LINQ resultset (anon. ilist) and sends that in reply, back to the web app. In order to get
The only problem with sending datasets over WCF is that it isn't interoperable - i.e. you wouldn't be able to use the dataset from a non-.NET client.
I've worked in several large applications that send Datasets across the wire via WCF just fine. As long as both the sender and receiver run on .NET you should be fine.
If you still don't want to use datasets, then consider creating a DataContract class to hold your data to send across the wire. This is the classic way to transmit data across WCF. Unless your XML is pretty complex (which it may well be) this might be a good alternative.
If you don't already have it, I strongly suggest picking up a copy of Juval Lowy's excellent "Programming WCF Services 2nd Edition." He has a whole chapter on transmitting information across WCF. It's the WCF Bible.
The class returned by the method needs to implement IXmlSerializable.
public XmlContent XmlContent()
{
return new XmlContent();
}
[XmlRoot(ElementName = "div")]
public class XmlContent : IXmlSerializable
{
#region IXmlSerializable Members
public System.Xml.Schema.XmlSchema GetSchema()
{
return null;
}
public void ReadXml(XmlReader reader)
{
throw new NotImplementedException();
}
public void WriteXml(XmlWriter writer)
{
writer.WriteRaw("<p>some text</p>");
}
#endregion
}
I still haven't found how to avoid serializing the root element (e.g., "div").
I tried sending XML as a string too, but it is not output as expected, that is, the "string" is HTML encoded and wrapped in tags. This make parsing very difficult.
You can simply return an XmlElement - possibly the DocumentElement property of an XmlDocument instance.
You do not have to use the XmlSerializer to do this. The DataContractSerializer is the default, and will send back an XmlElement just fine. You do not need to implement IXmlSerializable.
some sample code follows
service interface :
using System;
using System.Xml;
using System.ServiceModel;
using System.Runtime.Serialization;
namespace Cheeso.Samples.Webservices
{
[ServiceContract(Namespace="urn:Cheeso.Samples" )]
public interface IService
{
[OperationContract]
XmlElement Register(String request);
}
}
Notice I have no DataContract (and thus no DataMembers), because I am sending back an instance of a predefined class (XmlElement).
This is the service implementation:
using System;
using System.Xml;
using System.ServiceModel;
namespace Cheeso.Samples.Webservices._2009Jun01
{
public class Results
{
public int Id;
public Int64 WorkingSet;
public String Name;
public String Title;
}
[ServiceBehavior(Name="WcfXmlElementService",
Namespace="urn:Cheeso.Samples",
IncludeExceptionDetailInFaults=true)]
public class WcfXmlElementService : IService
{
int index = 0;
public XmlElement Register(string request)
{
XmlDocument doc = new XmlDocument();
// can get the doc from anywhere. We use a LINQ-to-Objects result.
// do the LINQ thing
var processInfo =
from p in System.Diagnostics.Process.GetProcesses()
select new Results {
Id = p.Id,
WorkingSet = p.WorkingSet64,
Name = p.ProcessName,
Title = p.MainWindowTitle
};
// Note: cannot use an anonymous ilist if we will use XmlSerializer
// serialize that list into the XmlDocument
using (XmlWriter writer = doc.CreateNavigator().AppendChild())
{
var L = processInfo.ToList();
XmlSerializer s1 = new XmlSerializer(L.GetType());
s1.Serialize(writer, L);
}
index++;
// Append some additional elements to the in-memory document.
XmlElement elem = doc.CreateElement("id");
elem.InnerText = System.Guid.NewGuid().ToString();
doc.DocumentElement.AppendChild(elem);
elem = doc.CreateElement("stamp");
elem.InnerText = DateTime.Now.ToString("G");
doc.DocumentElement.AppendChild(elem);
elem = doc.CreateElement("in-reply-to");
elem.InnerText = request;
doc.DocumentElement.AppendChild(elem);
return doc.DocumentElement;
}
}
}
The client, if you are using .NET, gets an XmlElement. If you are using some other stack, it will just be an XmlElement or XmlNode in that stack.
The XSD for the reply message is generic, like this:
<xs:element name="RegisterResponse">
<xs:complexType>
<xs:sequence>
<xs:element minOccurs="0" name="RegisterResult" nillable="true">
<xs:complexType>
<xs:sequence>
<xs:any minOccurs="0" processContents="lax" />
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
Why don't you try to send xml as a string ?