Embedding Arbitrary XML in Faults
How can I directly craft the XML content that goes into a fault detail?
Getting control over the detail element doesn't have to mean crafting the fault message yourself. While WCF requires that the fault detail be serializable using a data contract, remember that DataContractSerializer treats XmlElement as a special primitive type. This allows you to construct arbitrary content using XmlElement when your content can be represented as a rooted document. Due to the automatic conversion process of FaultException to a fault message, you don't need to construct a data contract to act as a wrapper.
Here's a sample that builds some content in an XmlElement and uses it to construct a fault. I made the method return a Message so that I could look at the response more easily but you can use any contract you want.
[ServiceContract]
public interface IMyService
{
[OperationContract]
Message Fail();
}
public class MyService : IMyService
{
public Message Fail()
{
XmlDocument document = new XmlDocument();
XmlElement root = document.CreateElement("tag");
root.SetAttribute("attributeName", "value");
XmlElement subtag = document.CreateElement("moretags");
subtag.InnerText = "blah";
root.AppendChild(subtag);
throw new FaultException<XmlElement>(root);
}
}
public class Program
{
static void Main(string[] args)
{
string address = "localhost:8000/";
BasicHttpBinding binding = new BasicHttpBinding();
ServiceHost host = new ServiceHost(typeof(MyService), new Uri(address));
host.AddServiceEndpoint(typeof(IMyService), binding, "");
host.Open();
ChannelFactory<IMyService> factory = new ChannelFactory<IMyService>(binding);
IMyService proxy = factory.CreateChannel(new EndpointAddress(address));
Message response = proxy.Fail();
Console.WriteLine(response.ToString());
Console.ReadLine();
host.Close();
}
}
That code produces a fault message that looks like the following.
<s:Envelope xmlns:s="schemas.xmlsoap.org/soap/envelope/">
<s:Header />
<s:Body>
<s:Fault>
<faultcode>s:Client</faultcode>
<faultstring xml:lang="en-US">The creator of this fault did not specify a Reason.</faultstring>
<detail>
<tag attributeName="value">
<moretags>blah</moretags>
</tag>
</detail>
</s:Fault>
</s:Body>
</s:Envelope>
Depending on how much hand-crafting you want, XmlDocument lets you simplify the process even further. For example, you could generate the same message from simple XML completely put together by hand.
XmlDocument document = new XmlDocument();
document.LoadXml("<tag attributeName=\"value\"><moretags>blah</moretags></tag>");
throw new FaultException<XmlElement>(document.FirstChild as XmlElement);
Next time: DataMember Best Practices
Comments
Anonymous
February 20, 2008
This article is primarily an introduction on protecting message data since the topic overall seems toAnonymous
February 29, 2008
Let's build on a few earlier samples to actually demonstrate a working call context initializer. I'll