Search...

Wednesday, August 21, 2013

KnownType attribute in WCF

The KnownTypeAttribute class allows you to specify, in advance, the types that should be included for consideration during deserialization. Normally, when passing parameters and return values between a client and a service, both endpoints share all of the data contracts of the data to be transmitted. However, this is not the case in the following circumstances:


  • The sent data contract is derived from the expected data contract. In that case, the transmitted data does not have the same data contract as expected by the receiving endpoint. 
  • The declared type for the information to be transmitted is an interface, as opposed to a class, structure, or enumeration. Therefore, it cannot be known in advance which type that implements the interface is actually sent and therefore, the receiving endpoint cannot determine in advance the data contract for the transmitted data. 
  • The declared type for the information to be transmitted is Object. Because every type inherits from Object, and it cannot be known in advance which type is actually sent, the receiving endpoint cannot determine in advance the data contract for the transmitted data. This is a special case of the first item: Every data contract derives from the default, a blank data contract that is generated for Object. 
  • Some types, which include .NET Framework types, have members that are in one of the preceding three categories. For example, Hashtable uses Object to store the actual objects in the hash table. When serializing these types, the receiving side cannot determine in advance the data contract for these members.

Let’s say you have the following classes:

1. Account

2. Users (derives from Account)

3. Guest (derives from Account)

If you mark each class with the DataContract attribute and create a service operation that returns a User type, you will be able to return a User, but not a Guest. If you try to return it, you’ll receive either a serialization error (On the server side) or a strange client-side error.

To fix this problem you decorate your base class Account with the KnownType attribute to tell the outside world what a Account can look like.


     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
        [DataContract]
        [KnownType(typeof(User))]
        [KnownType(typeof(Guest))]
        public class Account
        {
            [DataMember]
            public String UserId { get; set; }
        }
    
        [DataContract]
        public class User : Account
        {
            [DataMember]
            public String Name { get; set; }
    
            [DataMember]
            public String Password { get; set; }
        }
    
        [DataContract]
        public class Guest : Account
        {
            [DataMember]
            public String Name { get; set; }
        }
    

    Once you decorate your Account class with every known derived type, you can return these types from your service.(Download)

    No comments: