Serializing WCF Contract with Object Property

Introduction

This sample project is posted in reply to the forum post: http://social.msdn.microsoft.com/Forums/en-US/554a7c1c-cea7-4743-ad4f-7845da2e9683/sending-xml-string-to-generated-webservice-proxy-stub.

**WCF Service **The issue stems with how to handle contracts with object type properties:

[System.Runtime.Serialization.DataMemberAttribute(IsRequired=true)]        
       public object  richPresenceField {
           get {
               return this.richPresenceFieldField;
           }
           set {
               if ((object.ReferenceEquals(this.richPresenceFieldField, value) != true)) {
                   this.richPresenceFieldField = value;
                   this.RaisePropertyChanged("richPresenceField");
               }
           }
       }

To illustrate, I created a WCF Service using the Visual Studio template and then modified the default service to return the contract provided in the forum post.  The class setPresence contains a property that has the richPresenceField shown above.

[ServiceContract]
public interface  IService1
{

    [OperationContract]
    string GetData(int value);

    [OperationContract]
    setPresence GetPresence(setPresence composite);        
}

I wanted my implementation to be a little interesting so I added a couple of changes.  In general, the service just echos what it receives but I wanted to add a class that was included in the original contract and introduce a new contract that I manually added to the service.

public setPresence GetPresence(setPresence presence)
{
    if (presence == null)
    {
        throw new  ArgumentNullException("setPresence");
    }
    
    if (presence.presenceInfo.richPresence is string)
    {
        // if a string is sent then try to parse and return as
        // an int to illustrate that the type can change
        int value;
        if (int.TryParse(((string) presence.presenceInfo.richPresence), out  value))
            presence.presenceInfo.richPresence = value;

        // return out a new setPresence
        if(value==4)
            presence.presenceInfo.richPresence = new  setPresence { expiration = 4, presenceType = "test presence" };

        // return out a new MyClass
        if (value == 5)
            presence.presenceInfo.richPresence = new  MyOtherClass
                {
                    AnIntWithAnotherName = 3,
                    MyStringCollection = new  string[] {"avalue", "and another"}
                };
    }
    
    return presence;
}

WCF Client

The proxy was initially generated in a normal console app using Add Service Reference.  This created the proxy as expected and added the following known types to the proxy (note the service was added as funnyservice so the namespace was created as FunnyClient.funnyservice):

[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.Runtime.Serialization", "4.0.0.0")]
[System.Runtime.Serialization.DataContractAttribute(Name="PresenceInfoType", Namespace="http://schemas.datacontract.org/2004/07/FunnySerialisation")]
[System.SerializableAttribute()]
[System.Runtime.Serialization.KnownTypeAttribute(typeof(FunnyClient.funnyservice.setPresence))]
[System.Runtime.Serialization.KnownTypeAttribute(typeof(System.MulticastDelegate))]
[System.Runtime.Serialization.KnownTypeAttribute(typeof(System.Delegate))]
[System.Runtime.Serialization.KnownTypeAttribute(typeof(System.ComponentModel.PropertyChangedEventHandler))]    
public partial  class PresenceInfoType : object, System.Runtime.Serialization.IExtensibleDataObject, System.ComponentModel.INotifyPropertyChanged {

In my client I created a little helper method that returns an setPresence object that contains the object I am trying to verify:

private static  setPresence BuildSimplePresence(object content)
{
    return new  setPresence
        {
            expirationField = 100,
            presenceInfoField = new  PresenceInfoType
                {
                    basicPresenceField = "basic",
                    richPresenceField = content
                },
            presenceTypeField = "a type of presence"
        };
}

** Initial observations**

Without making any changes to the proxy or service contracts, the datacontract serializer will allow us to send the richPresenceField as a base type (e.g., int, string, etc) or to a setPresence object.  This is shown and validated in the statements below (Note, I validated the result in the debugger):

var presence = client.GetPresence(BuildSimplePresence("some simple content that will be encoded <here> and <there>."));

presence = client.GetPresence(BuildSimplePresence("12202"));

presence = client.GetPresence(BuildSimplePresence(new setPresence { expirationField = 1 } ));

presence = client.GetPresence(BuildSimplePresence("4"));

presence = client.GetPresence(BuildSimplePresence("5"));

​ Adding a new class

I wanted to do something a little more interesting that hopefully illustrates the disconnect between client and server and provide some insight into serialization.  In my service I added a new class (Note how the class name and first member name do not match the contract name):

[System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.18046")]
[System.SerializableAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
[System.Runtime.Serialization.DataContractAttribute(Name = "PresenceInfoType", Namespace = "http://schemas.datacontract.org/2004/07/FunnySerialisation")]
[System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "urn:somecompany:presence:soap", TypeName = "MyClass")]    
public class  MyOtherClass
{
    /// <remarks/>
    [System.Xml.Serialization.XmlElementAttribute(Order = 0, ElementName = "MyIntValue")]
    [System.Runtime.Serialization.DataMember()]
    public int  AnIntWithAnotherName { get; set; }

    [System.Xml.Serialization.XmlElementAttribute(Order = 0)]
    [System.Runtime.Serialization.DataMember()]
    public string[] MyStringCollection { get; set; }

}

I also had to inform datacontractserializer to expect these type of objects by inserting the knowntypeattribute:

[System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.18046")]
[System.SerializableAttribute()]    
[System.ComponentModel.DesignerCategoryAttribute("code")]
[System.Xml.Serialization.XmlTypeAttribute(Namespace = "urn:somecompany:presence:soap")]
[System.Runtime.Serialization.KnownTypeAttribute(typeof(MyOtherClass))]
public partial  class PresenceInfoType : object, System.ComponentModel.INotifyPropertyChanged

Without updating the proxy, I then manually added a class that has the same contract definition but different class structure:

[System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.18046")]
[System.SerializableAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
[System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "urn:somecompany:presence:soap")]
[System.Runtime.Serialization.DataContractAttribute(Name = "PresenceInfoType", Namespace = "http://schemas.datacontract.org/2004/07/FunnySerialisation")]
public class  MyClass
{
    /// <remarks/>
    [System.Xml.Serialization.XmlElementAttribute(Order = 0, Namespace = "urn:somecompany:presence:soap")]
    [System.Runtime.Serialization.DataMember()]
    public int  MyIntValue { get; set; }

    [System.Xml.Serialization.XmlElementAttribute(Order = 0, Namespace = "urn:somecompany:presence:soap")]
    [System.Runtime.Serialization.DataMember()]        
    public string[] MyStringCollection { get; set; }

}

And, I need to let the proxy (Reference.cs) know about this  new type:

[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.Runtime.Serialization", "4.0.0.0")]
[System.Runtime.Serialization.DataContractAttribute(Name="PresenceInfoType", Namespace="http://schemas.datacontract.org/2004/07/FunnySerialisation")]
[System.SerializableAttribute()]
[System.Runtime.Serialization.KnownTypeAttribute(typeof(FunnyClient.funnyservice.setPresence))]
[System.Runtime.Serialization.KnownTypeAttribute(typeof(System.MulticastDelegate))]
[System.Runtime.Serialization.KnownTypeAttribute(typeof(System.Delegate))]
[System.Runtime.Serialization.KnownTypeAttribute(typeof(System.ComponentModel.PropertyChangedEventHandler))]
[System.Runtime.Serialization.KnownTypeAttribute(typeof(MyClass))]    
public partial  class PresenceInfoType : object, System.Runtime.Serialization.IExtensibleDataObject, System.ComponentModel.INotifyPropertyChanged {

This then allows for the following message to be sent (and echoed):

presence = client.GetPresence(BuildSimplePresence(new MyClass { MyIntValue = 4, MyStringCollection =  new  string[] { "test1", "test2" }}));

Hope this is helpful.