2009-02-14

WCF – serialize the unserializable

Introduction

WCF serialization rely on the Data Contract and Data Member decoration

This post discuss one simple trick that available in cases that you having your own data contract that holding data members that does not been decorated for the WCF serialization

This trick will work as long as you reuse the same assembly of the data contract both on the client and service sides

There some other techniques for advance serialization which will beyond the scope of this post

you can find the post code in here

Our Test Case

In our test case we will have data contract that has data member of type DataTable

Note: you do not need this trick for typed data table, it does serialized well

Having the following service:

[ServiceContract]
public interface IMyService
{
[OperationContract]
CustomEntity GetData ();
}

[DataContract]
public class CustomEntity
{
[DataMember]
public DataTable Table { get; set; }
}

Notice that we try to have data contract that having data member which does not design to be serialized using WCF serialization (because DataTable does not decorate with data contract attribute)

The trick is very simple and it can be assign for any similar cases
it simply using the data contract serialization processing with little twist

We will serialize the DataTable indirectly using private data member which won’t expose by our Custom Entity API so the consumer of our Custom Entity won’t e aware of it, still the WCF will use it during the serialization process

Steps needed to achieve our goal

  1. Remove the data member decoration from the Table property
  2. Add custom private data member that will handle the serialization process
    1. We need one member to serialize the DataTable schema
    2. And other member to serialize the DataTable data (the data deserialization must occur after the schema deserialization completed)

Our data contract should look like the following one

[DataContract]
public class CustomEntity
{
[DataMember (Order=0)]
private byte[] TableSchemaSerialization
{
get
{
// the folowing operation will occur during the WCF serializing
var srm = new MemoryStream ();
this.Table.WriteXmlSchema (srm);
return srm.ToArray ();
}
set
{
// the folowing operation will occur during the WCF deserializing
this.Table = new DataTable ();
var srm = new MemoryStream (value);
this.Table.ReadXmlSchema (srm);
}
}

[DataMember (Order=1)]
private byte[] TableDataSerialization
{
get
{
// the folowing operation will occur during the WCF serializing
var srm = new MemoryStream ();
this.Table.WriteXml (srm);
return srm.ToArray ();
}
set
{
// the folowing operation will occur during the WCF deserializing
var srm = new MemoryStream (value);
this.Table.ReadXml (srm);
}
}

//[DataMember]
public DataTable Table { get; set; }
}

Conclusion

As long as we reusing the data contract at both service and client sides

We can build our data contract to intercept the serialization process without changing the data contract API

2009-02-02

WCF Serialization

Some words before we start
I intend to start blog series of .NET technical blogs
I encourage you to add comments whether the post content meeting your expectation
I will try to keep the post short and technical.

So with that said lets dive into this post topic.
As you may know while passing complex type as parameter for WCF will be serialized using DataContractSerializer.

One thing you should notice about this serialization process is that unlike XmlSerializer it will not call the constructor or field initialization.

So if you declare the following contract
[DataContract]
public class MyCompositeType
{
private Guid m_id1 = Guid.NewGuid (); // will not happens during serialization
public MyCompositeType () // will not happens during serialization
{
Id2 = Guid.NewGuid ();
}
public Guid Id1
{
get { return m_id1; }
}
public Guid Id2 { get; private set; }

[DataMember]
public string StringValue { get; set; }
}

So do not expect that the ids (which is not data member) be initialized on the other side of the serialization process

The code sample for this post is available here

If we having the following service implementation:
public MyCompositeType GetDataUsingDataContract ( MyCompositeType composite )
{
composite.StringValue += " : " + composite.Id1.ToString () +
" : " + composite.Id2.ToString ();
return composite;
}

And we call it from the client like this:
static void Main ( string[] args )
{
MyProxy.SampleServiceClient svc = new MyProxy.SampleServiceClient ();
var composite = new MyCompositeType { StringValue = "Test" };

Console.WriteLine ("Id1 = {0} \nId2 = {1}",
composite.Id1.ToString (), composite.Id2.ToString ());

var response = svc.GetDataUsingDataContract (composite);

Console.WriteLine (response.StringValue);
Console.WriteLine ("Id1 = {0} \nId2 = {1}",
response.Id1.ToString (), response.Id2.ToString ());

Console.ReadLine ();
}

The ids will be initialized to none empty Guid only on the client side
Both at the server and the response ids will be empry