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>