2
votes

I'm using C# and WCF to do web services. I have a member variable of a class that implements IEnumerable. I tried to have it be serialized as part of my data contract by doing:

[DataContract]
class Item
{
    [DataMember]
    private IEnumerable<KeyValuePair<string, object>> Member1
    {
        get { return this._Properties; }
        set { this._Properties = Value; }
    }
}

Where _Properties is of type:

class PropertiesCollection:IEnumerable<KeyValuePair<string, object>>
{
    ...
}

I thought that WCF would serialize Member1 as an IEnumerable, because that's the type I gave to that member, but I'm getting an InvalidDataContractExceptiom, with this message:

Type PropertyCollectioncannot be serialized. Consider marking it with the DataContractAttribute attribute, and marking all of its members you want serialized with the DataMemberAttribute attribute. If the type is a collection, consider marking it with the CollectionDataContractAttribute. See the Microsoft .NET Framework documentation for other supported types.

It seems WCF is looking at the runtime type of the object being passed via Member1 (PropertyCollection) rather than the type of the property (IEnumenable). Is this understanding correct? Is the only fix adding [CollectionDataContract] to PropertiesCollection? I would prefer to keek the service contract non-specific (i.e. it just knows that iot is an IEnumerable), if possible.

4

4 Answers

1
votes

Off the top of my head: I think you need to decorate the Member1 property with the KnownType attribute.

see: http://msdn.microsoft.com/en-us/library/ms730167.aspx

[DataContract]
[KnownType(typeof(PropertiesCollection))] //<--- this guy here
class Item
{
    [DataMember]
    private IEnumerable<KeyValuePair<string, object>> Member1
    {
        get { return this._Properties; }
        set { this._Properties = Value; }
    }
}

Adding the code from Example2 in the link above to show how even though the attribute is a Class decorator, it applies to the DataMember:

public interface ICustomerInfo {}

[DataContract(Name = "Customer")]
public class CustomerTypeA : ICustomerInfo {}

[DataContract(Name = "Customer")]
public class CustomerTypeB : ICustomerInfo {}

[DataContract]
[KnownType(typeof(CustomerTypeB))] //<-- check it! This applies to 'buyer'
public class PurchaseOrder
{
    [DataMember]
    ICustomerInfo buyer;

    [DataMember]
    int amount;
}
1
votes

Ehe real aswer to this question is that there are some requirements that a type must fulfill to be a valid collection DataContract:

  1. It must have a parameterless constructor
  2. It must have an Add Method.

When I implemented those my problem went away.

0
votes

You have to have DataContract in front of PropertiesCollection class definition:

 [DataContract]
 class PropertiesCollection:IEnumerable<KeyValuePair<string, object>>
 {
    ...
 }

Each of the types that enter serialization should be [DataContract] or [Serializable]

0
votes

Simplest solution:

  1. create new serializable Class containing key and value
  2. Pass this class in any collection