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