WCF — Using the NetDataContractSerializer to share your type

Dat­a­Con­tract­Se­ri­al­izer

For those of your who are famil­iar with WCF you would no doubt know about the Dat­a­Con­tract­Se­ri­al­izer class, the Dat­a­Con­tract­Se­ri­al­izer does not include the CLR type infor­ma­tion in the seri­al­ized XML, which allows for loose cou­pling between the client and server because they don’t have to share the same CLR types.

How­ever, this also means you often have to re-create the same types on the client, though Visual Stu­dio han­dles most of this for you when you add a new ser­vice ref­er­ence to your project. How­ever, rather than dese­ri­al­iz­ing the orig­i­nal type, mes­sages are dese­ri­al­ized into a new, but iden­ti­cal CLR type on the client.

Net­Dat­a­Con­tract­Se­ri­al­izer

Whilst Dat­a­Con­tract­Se­ri­al­izer is used by WCF by default, there is another seri­al­izer which you can use if you wish to share the same CLR types between the client and server – the Net­Dat­a­Con­tract­Se­ri­al­izer. The Net­Dat­a­Con­tract­Se­ri­al­izer dif­fers from the Dat­a­Con­tract­Se­ri­al­izer in that it includes the CLR type infor­ma­tion in the seri­al­ized XML and can only be used if the same CLR types are seri­al­ized and dese­ri­al­ized at both ends.

You can use the Net­Dat­a­Con­tract­Se­ri­al­izer on any type which are marked with the Dat­a­Con­trac­tAt­tribute or Seri­al­iz­ableAt­tribute, or types that imple­ment the ISe­ri­al­iz­able interface.

UseNet­Dat­a­Con­tract­Se­ri­al­iz­er­At­tribute

Here’s the attribute you need to replace the default Dat­a­Con­tract­Se­ri­al­izer with the Net­Dat­a­Con­tract­Se­ri­al­izer, taken from Tim Scott’s blog post here:

public class NetDataContractOperationBehavior : DataContractSerializerOperationBehavior
{
    public NetDataContractOperationBehavior(OperationDescription operation) : base(operation)
    {
    }

    public NetDataContractOperationBehavior(
                OperationDescription operation,
                DataContractFormatAttribute dataContractFormatAttribute)
            : base(operation, dataContractFormatAttribute)
    {
    }

    public override XmlObjectSerializer CreateSerializer(
                Type type, string name, string ns, IList knownTypes)
    {
        return new NetDataContractSerializer(name, ns);
    }

    public override XmlObjectSerializer CreateSerializer(
                Type type, XmlDictionaryString name, XmlDictionaryString ns,
                IList knownTypes)
    {
        return new NetDataContractSerializer(name, ns);
    }
}

public class UseNetDataContractSerializerAttribute : Attribute, IOperationBehavior
{
    public void AddBindingParameters(OperationDescription description,
                                     BindingParameterCollection parameters)</pre>
{
}

public void ApplyClientBehavior(OperationDescription description,
System.ServiceModel.Dispatcher.ClientOperation proxy)
{
ReplaceDataContractSerializerOperationBehavior(description);
}

public void ApplyDispatchBehavior(OperationDescription description,
System.ServiceModel.Dispatcher.DispatchOperation dispatch)
{
ReplaceDataContractSerializerOperationBehavior(description);
}

public void Validate(OperationDescription description)
{
}

private static void ReplaceDataContractSerializerOperationBehavior(
OperationDescription description)
{
DataContractSerializerOperationBehavior dcsOperationBehavior =
description.Behaviors.Find();

if (dcsOperationBehavior != null)
{
description.Behaviors.Remove(dcsOperationBehavior);
description.Behaviors.Add(new NetDataContractOperationBehavior(description));
}
}
}

To use it, you can add it to a ser­vice method defined in the contract:

[OperationContract]
[UseNetDataContractSerializer]
Company SaveCompany(CompanyUpdater companyUpdater);