5
votes

I have a really simple customized collection type that inherits from List<> and uses a CollectionDataContract.

When I use DataContractSerializer.WriteObject to serialize it, it respects the CollectionDataContract attribute the way I'd expect; however, when I use it as a return type for a WCF method, I get the default ArrayOfFoo.

I'm wondering if there is some decoration I'm missing in the service contract.

Details:

[DataContract(Namespace = "")]
public class Foo
{
    [DataMember]
    public string BarString { get; set; }
}

[CollectionDataContract(Namespace = "")]
[Serializable]
public class FooList : List<Foo> {}

If I just instantiate a Foo and then use DataContractSerializer.WriteObject to serialize it, I get what you'd expect:

<FooList>
    <Foo>
        <BarString>myString1</BarString>
    </Foo>
</FooList>

However, if I have a service with a method like this...

[ServiceContract Name = "MyService"]
public interface IMyService
{
    [OperationContract, WebGet(UriTemplate = "foos/")]
    FooList GetAllFoos();
}

and then do a GET for http://www.someEndpoint.com/foos/, I get this:

<ArrayOfFoo>
    <Foo>
        <BarString>myString1</BarString>
    </Foo>
</ArrayOfFoo>

I've also tried specifying Name="MyFooListName" in the CollectionDataContract attribute. Same results: DataContractSerializer gets the memo; WCF doesn't.

3
I think, yes, it convert lists to array. - Saeed Amiri
You're right that a List gets serialized to an Array if you don't customize the collection type; what I'm trying to figure out is whether there's a way to get WCF to respect my CollectionDataContract. - pisomojado

3 Answers

3
votes

Saeed sent me in the right direction: I inadvertently ended up with XmlSerializer, when I had been hoping for DataContractSerializer.

I had ended up with XmlSerializer... well... by asking for it.

In particular, I had decorated methods in my service with the XmlSerializerFormat like this:

[ServiceContract Name = "MyService"] 
public interface IMyService 
{ 
    //  ... other stuff ...

    [OperationContract, WebInvoke(UriTemplate = "foos/", Method = "POST")] 
    [XmlSerializerFormat]
    Foo PostAFoo(Foo yourNewFoo);
} 

I had done this in the hopes of forgiving member order in hand-rolled Foo XML blobs. Of course, when one does this one ends up with XmlSerializer, not DataContractSerializer.

When I take away the XmlSerializerFormat attribute, problem solved: WCF is now serializing my FooList collection the way I want.

2
votes

See MSDN for detail:

The DataContractSerializer does not support the programming model used by the XmlSerializer and ASP.NET Web services. In particular, it does not support attributes like XmlElementAttribute and XmlAttributeAttribute. To enable support for this programming model, WCF must be switched to use the XmlSerializer instead of the DataContractSerializer.

So the serialization going to be done by XMLSerializer, and you can't change it.

0
votes

Have you selected Generic types while configuring your WCF service? if not then,

right click and go to configuration, then select Generic Type, by default it is arraylist type.