Zulfiqar's weblog

Architecture, security & random .Net

Serializing Faults using XmlSerializer

Posted by zamd on August 15, 2008


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&#8221;), new FaultReason(“System is down”), detail);

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

        }

    }

}

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>

Advertisements

3 Responses to “Serializing Faults using XmlSerializer”

  1. Unknown said

    Here is another approach to solving this problem, which may be more suitable some users. My motivation for doing so was to construct a custom fault message for a webHttpBinding-enabled endpoint. If I invoke Message.CreateMessage(version, action, messageObject), then the runtime will default to using the DataContractSerializer much like in the related fault-detail problem.

    At first, it appears that creating an XmlSerializerMessage class and overriding Message.OnWriteBodyContents() will solve the problem. It will, however there is a bit of code duplication amongst the two XmlSerializerMessage and XmlSerializerFault classes, namely, the serialization code.

    Fortunately, both Message.CreateMessage() and MessageFault.CreateFault() accept an XmlObjectSerializer as a parameter to serialize the contents of the Message[Fault]. There is no such class that represents an XmlSerializer, so we create one as follows.

    public sealed class XmlObjectSerializerAdaptor<TObject> : XmlObjectSerializer
    {
    public override bool IsStartObject(XmlDictionaryReader reader)
    {
    throw new NotSupportedException();
    }

    public override object ReadObject(XmlDictionaryReader reader, bool verifyObjectName)
    {
    return TObjectSerializer.Deserialize(reader);
    }

    public override void WriteEndObject(XmlDictionaryWriter writer) { }

    public override void WriteObjectContent(XmlDictionaryWriter writer, object graph)
    {
    TObjectSerializer.Serialize(writer, graph);
    }

    public override void WriteStartObject(XmlDictionaryWriter writer, object graph) { }

    private static readonly XmlSerializer TObjectSerializer = new XmlSerializer(typeof(TObject));
    }

  2. Unknown said

    Cool, Thanks for sharing.

  3. […] http://twenty6-jc.blogspot.com/2011/05/ierrorhandlerprovidefault-serialization.html http://zamd.net/2008/08/15/serializing-faults-using-xmlserializer/ […]

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

 
%d bloggers like this: