OOP with WCF: Decorate DataContract with [KnownType(typeof(aType))]

WCF makes heavy use of reflection.  In order to support object inheritance one needs to help WCF by decorating DataContract with [KnownType(typeof(aType))] so the service reference will include the proper information.  Below is a quick example:

The below data contract for an Animal also includes the known types of Cat and Dog:

[DataContract]
[KnownType(typeof(Cat))]
[KnownType(typeof(Dog))]
public class Animal
{
    [DataMember]
    public string Name
    { get; set; }
}

[DataContract]
public class Dog : Animal
{ }

[DataContract]
public class Cat : Animal
{ }

 

Here, the service contract is working only with Animal:

[ServiceContract]
public interface IServiceInterface
{
    [OperationContract]
    string GetAnimalName(Animal anAnimal);

}

And the implementation is looking for specific descendant classes (Cat & Dog):

public class ServiceInstance : IServiceInterface
{
    public string GetAnimalName(Animal anAnimal)
    {
        if (anAnimal is Dog)
            return "Dog";
        if (anAnimal is Cat)
            return "Cat";
        return "Unknown";
    }

}

 

The calling code could look something like this:

ServiceReferenceTest.ServiceInterfaceClient aClient = new ServiceReferenceTest.ServiceInterfaceClient();

var aCat = new ServiceReferenceTest.Cat();
Console.WriteLine(aClient.GetAnimalName(aCat));

Bottom line: WCF is an amazingly powerful way to build OOP web services.

If one comments out [KnownType(typeof(Cat))] and runs the program, the client will give the below runtime error:

The formatter threw an exception while trying to deserialize the message: There was an error while trying to deserialize parameter http://tempuri.org/:anAnimal. The InnerException message was ‘Error in line 1 position 261. Element ‘http://tempuri.org/:anAnimal’ contains data from a type that maps to the name ‘http://schemas.datacontract.org/2004/07/WcfServiceWEOTest:Cat’. The deserializer has no knowledge of any type that maps to this name. Consider using a DataContractResolver or add the type corresponding to ‘Cat’ to the list of known types – for example, by using the KnownTypeAttribute attribute or by adding it to the list of known types passed to DataContractSerializer.’.  Please see InnerException for more details.

Leave a Reply

Your email address will not be published. Required fields are marked *