Tuesday, July 27, 2010

WCF DataContractSerializer Working Process
How does this class serialize the contract? And why does it have performance issue? These questions make me mad these days, because my project suffers a lot from this class. I have to spend several hours to figure this thing out. Here is what it does.
There is an internal class named DataContract used in this process, and it’s important. When it starts to serialize/deserialize something, it first gets different DataContract according to the data types. In other words, there are many subclasses of DataContract:
ClassDataContract
CollectionDataContract
EnumDataContract
GenericParameterDataContract
PrimitiveDataContract (this class has many subclasses for bool, int, object etc.)
SpecialTypeDataContract
SurrogateDataContract
XmlDataContract
This class is important because I think it’s the class that does the real serialization. In this class, there is an important member method: WriteXmlValue, it should be easy to tell what it does by the name. When the DataContract for the specific type is created, it will be stored in a cache, its key is generated based the type.
After getting the correct DataContract, it creates XmlObjectSerializerWriteContext object. This class is also an internal class, which is used to maintain the object references in contracts. XmlObjectSerializerWriteContext.SerializeWithXsiTypeAtTopLevel will be used to serialize the object. If there is a DataContractResolver, it will be used here to resolve the type information. Since this is not my focus, I just let it go. Then, SerializeAndVerifyType is invoked in which WriteDataContractValue is called. In this WriteDataContractValue method, it calls DataContract.WriteXmlValue, which is mentioned above.
Here, I will take ClassDataContract as an example to explain how this class works. When it’s the first to invoke WriteXmlValue, it will dynamically generate an XmlFormatWriterDelegate by XmlFormatWriterGenerator.GenerateClassWriter. Following is the implementation copied from Reflector.
internal XmlFormatClassWriterDelegate GenerateClassWriter(ClassDataContract classContract)
{
this.ilg = new CodeGenerator();
bool allowPrivateMemberAccess = classContract.RequiresMemberAccessForWrite(null);
try
{
this.ilg.BeginMethod("Write" + classContract.StableName.Name + "ToXml", Globals.TypeOfXmlFormatClassWriterDelegate, allowPrivateMemberAccess);
}
catch (SecurityException exception)
{
if (!allowPrivateMemberAccess !exception.PermissionType.Equals(typeof(ReflectionPermission)))
{
throw;
}
classContract.RequiresMemberAccessForWrite(exception);
}
this.InitArgs(classContract.UnderlyingType);
this.DemandSerializationFormatterPermission(classContract);
this.DemandMemberAccessPermission(allowPrivateMemberAccess);
this.WriteClass(classContract);
return (XmlFormatClassWriterDelegate) this.ilg.EndMethod();
}
After that, this delegate will be used to do the serialization. There is also another XmlFormatReaderDelegate, which works like the same way. This method generation spends some time and may cause performance issue.
As above mentioned, it’s put in a cache, at the second time the same DataContract is used; it won’t do this again, so it saves much time.

Search YouTube