Search code examples
c#wcfsoapconstructordatacontractserializer

How to initialize abstract base constructor when client calls new on DataContract?


I'm trying to come up with a workaround that would accommodate an abstract base class's constructor being initialized when a client consuming my WCF service performs a new() over a DataContract object. I'm aware that the DataContract objects are created as raw, uninitialized objects thus no constructors are called. I ran across the user of the [OnSerializing], [OnSerialized], [OnDeserializing], and [OnDeserialized] attributes, and I've discovered that they are not honored by the serialization engine of WCF unless you explicitly force it to use XML, which is not desired in this specific case. Here's a very simplified coding example of what I'm trying to use.

[DataContract(Namespace = "http://somenamespace/Data/ContractBase/v1")]
public abstract ContractBase
{
    [DataMember(IsRequired = true)]
    public SomeDataContract BaseClassObject { get; set; }

    public string Name { get; set; }        

    public ContractBase()
    {
        BaseClassObject = new SomeDataContract("randomConstructorArgument");
        Name = "Ezra";
    }
}

[DataContract(Namespace = "http://somenamespace/Data/TheClass/v1")]
[KnownType(typeof(ContractBase))]
public sealed class TheClass : ContractBase
{
    [DataMember]
    public PetDataContract MyPet { get; set; }

    [DataMember]
    public int SomeIntProperty { get; set; }

    public TheClass()
        : base()
    {
        MyPet = new PetDataContract ("Fido");
        SomeIntProperty = -1;
    }
}

I'm aware that the client performing TheClass myClass = new TheClass(); will not initialize the base constructor since the constructor of TheClass is never called. I attempted to add in methods such as the following to trigger when serialization occurs without any success.

private void Initialize()
{
    MyPet = new PetDataContract ("Fido");
    SomeIntProperty = -1;

    base.Initialize();
}

[OnSerializing]
private void OnSerializing(StreamingContext c)
{
    Initialize();
}

The base class would have the Initialize method as well so that the "constructors" would be chained. The constructors themselves would be updated to include the Initialize(); call to use the same common source of code.

Is there a way to handle this without forcing the serialization to be done through the XmlSerializer? My current workaround is to provide a method in the WCF service to create the object on the server and return the post-constructor version.

public TheClass CreateTheClass(TheClass contract)
{
    // Calls the constructor of TheClass and its base constructor.
    return new TheClass();
}

This does work as expected, but it's an extra service call that I'd rather avoid because of the network I/O cost. Any help would be extremely appreciated.

Thanks!


Solution

  • According to this article the attributes you mentioned should work nicely with DataContractSerializer. Your last example is a little bit strange - you are trying to use OnSerializing attribute while saying that constructors are not called during deserialization by WCF.

    I would suggest to use your approach with Initialize methods marked by OnDeserializing (or OnDeserialized if you wish to call your code after deserialization was completed) attribute.