Include XML Declaration in WCF RESTful Service Response

|

When using WCF to write RESTful web services, the default XML response stream doesn’t contain the XML Declaration or XML DOCTYPE. the default XML serialization mechanism used by WCF’s data contract serializer does support emitting XML declaration, but it isn’t turned out by default. You could try using XmlSerializer instead which does support emitting XML declaration,  but if you need stick to data contract serializer, you could try hooking into the WCF serialization process by writing a custom message formatter, the following code contains the full implementation of this approach:

public class XmlDeclarationMessage : Message
{
    private Message message;
    public XmlDeclarationMessage(Message message)
    {
        this.message = message;
    }

    public override MessageHeaders Headers
    {
        get { return message.Headers; }
    }

    protected override void OnWriteBodyContents(System.Xml.XmlDictionaryWriter writer)
    {
        // WCF XML serialization doesn't support emitting XML DOCTYPE, you need to roll up your own here.
        writer.WriteStartDocument();
        message.WriteBodyContents(writer);
    }


    public override MessageProperties Properties
    {
        get { return message.Properties; }
    }

    public override MessageVersion Version
    {
        get { return message.Version; }
    }
}

public class XmlDeclarationMessageFormatter : IDispatchMessageFormatter
{
    private IDispatchMessageFormatter formatter;
    public XmlDeclarationMessageFormatter(IDispatchMessageFormatter formatter)
    {
        this.formatter = formatter;
    }

    public void DeserializeRequest(Message message, object[] parameters)
    {
        formatter.DeserializeRequest(message, parameters);
    }

    public Message SerializeReply(MessageVersion messageVersion, Object[] parameters, Object result)
    {
        var message = formatter.SerializeReply(messageVersion, parameters, result);
        return new XmlDeclarationMessage(message);
    }
}

public class IncludeXmlDeclarationAttribute : Attribute, IOperationBehavior
{
    public void AddBindingParameters(OperationDescription operationDescription, BindingParameterCollection bindingParameters)
    {
    }

    public void ApplyClientBehavior(OperationDescription operationDescription, ClientOperation clientOperation)
    {
    }

    public void ApplyDispatchBehavior(OperationDescription operationDescription, DispatchOperation dispatchOperation)
    {
        dispatchOperation.Formatter = new XmlDeclarationMessageFormatter(dispatchOperation.Formatter);
    }

    public void Validate(OperationDescription operationDescription)
    {
    }
}

Then you could specify the IncludeXmlDeclarationAttribute at service operation level, if you need to enable this at service wide level, you could try implementing the IServiceBehavior interface instead.

[ServiceContract]
public interface IDemoService
{
    [OperationContract]
    [IncludeXmlDeclaration]
    [WebGet(UriTemplate = "customers/{name}/")]
    Customer GetCustomer(String name);
}

8 comments:

Anonymous said...

XmlDictionaryWriter doesn't allow writing doctype so how would you do that in te place you specified ?

The Master said...

It worked perfectly for me without changing anything. Thanks !

Anonymous said...

Worked beautifully. Simple and elegant usage with the attribute. Thanks!

Camilo said...

Hi,
When the formatter is passed to the constructor, it comes as null. Any idea ?

dispatchOperation.Formatter = new XmlDeclarationMessageFormatter(dispatchOperation.Formatter);

Anonymous said...

Worked perfectly without change, thank you!

Anonymous said...

You rock dude! Exactly what I was looking for.

Anonymous said...

This was exactly what I needed! Works like a charm!

Anton said...

Set up breakpoint at:
dispatchOperation.Formatter = new XmlDeclarationMessageFormatter(dispatchOperation.Formatter);

It never have been hit :(