Update (25/08/2008): .net Framework 3.5 SP1 has added the support for serializing faults using XML Serializer.

[

XmlSerializerFormat(SupportFaults=true)]: by setting SupportFaults=true will result in the use of Xml Serializer for fault serialization as well. The default value is false to maintain backward compatibility. The approach mentioned in this article is still valid for scenarios where you want to use DataContractSerializer for input & output messages but XML Serializer for faults (a rare requirement though).

------------------------------------------------------------------------------------------------------------------------------------------

 

Today someone asked me how to serialize the TDetail part of FaultException<TDetail> using XmlSerializer. The scenario was to interoperate with an existing schema using some of the XSD features (attributes etc.), which are currently not supported by DataContractSerializer. The solution is to Subclass the MessageFault class and use XmlSerializer to serialize the TDetail.

public class XmlSerializerMessageFault : MessageFault

{

    FaultCode code;

    FaultReason reason;

    object details;

    public XmlSerializerMessageFault(FaultCode code, FaultReason reason, object details)

    {

        this.details = details;

        this.code = code;

        this.reason = reason;

    }

    public override FaultCode Code

    {

        get { return code; }

    }

    public override bool HasDetail

    {

        get { return (details != null); }

    } 

    protected override void OnWriteDetailContents(System.Xml.XmlDictionaryWriter writer)

    {

        var ser = new XmlSerializer(details.GetType());

        ser.Serialize(writer, details);

        writer.Flush();

    } 

    public override FaultReason Reason

    {

        get { return reason; }

    }

}

Fault was created from a global error handler (IErrorHandler).

public class ErrorHandlerEx : IErrorHandler

{

    public bool HandleError(Exception error)

    {

        return true;

    } 

    public void ProvideFault(

        Exception error, MessageVersion version, ref Message fault)

    {

        if (error is FaultException)

        {

            // extract our FaultContract object from the exception object.

            var detail = error.GetType().GetProperty("Detail").GetGetMethod().Invoke(error, null);

            // create a fault message containing our FaultContract object

            var msgFault = new XmlSerializerMessageFault(FaultCode.CreateSenderFaultCode("systemDown", "http://zamd.net"), new FaultReason("System is down"), detail);

            fault = Message.CreateMessage(version, msgFault, "http://zamd.net/action");

        }

    }

}

Xml output

<Fault xmlns="http://schemas.microsoft.com/ws/2005/05/envelope/none">

  <Code>

    <Value>Sender</Value>

    <Subcode>

      <Value xmlns:a="http://zamd.net">a:systemDown</Value>

    </Subcode>

  </Code>

  <Reason>

    <Text xml:lang="en-GB">System is down</Text>

  </Reason>

  <Detail>

    <GreaterThan3Fault ErrorCode="90192" Location="ISB" xmlns="" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">

      <FaultMessage>Count cannot be greate than 3. Please try again later.</FaultMessage>

    </GreaterThan3Fault>

  </Detail>

</Fault>