Search code examples
c#wcfsoapuidatacontract

Abstract objects collection definition in wcf service


I have in my DataContract a collection of objects defined as

Collection<BaseAbstractObject>

which I want to fill up with some inherited objects of type ClassA.

I'm using Soap UI to create such a request to my service method, but I'll get error "Cannot create an abstract class"

I have also decorated base class with [KnownType(ClassA)] attribute. My xml request looks like this:

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:tem="http://tempuri.org/" xmlns:wcf="http://schemas.datacontract.org/2004/07/WcfService1" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
   <soapenv:Header/>
   <soapenv:Body>
      <tem:GetDataUsingDataContract>
         <tem:composite>
            <wcf:ClassesCollection>
               <wcf:BaseClass i:type="ClassA" >
                  <wcf:Id>1</wcf:Id>                      
                  <wcf:Name>ClassA</wcf:Name>
               </wcf:BaseClass>
            </wcf:ClassesCollection>
         </tem:composite>
      </tem:GetDataUsingDataContract>
   </soapenv:Body>
</soapenv:Envelope>

And this is how my DataContracts looks like:

[DataContract]
public class MyDataContract
{
    public MyDataContract()
    {
        ClassesCollection = new Collection<BaseClass>();
    }

    [DataMember]
    public Collection<BaseClass> ClassesCollection { get; private set; }
}

[DataContract]
[KnownType(typeof(ClassA))]
public abstract class BaseClass
{
    [DataMember]
    public int Id { get; set; }
}

[DataContract]
public class ClassA : BaseClass
{
    [DataMember]
    public int Name { get; set; }
}

So what should my request looks like? Or need I add some other attribute to DataContract?


Solution

  • First make sure that your collection has a public setter, otherwise WCF won't be able to deserialize it:

    [DataMember]
    public Collection<BaseClass> ClassesCollection { get; set; }
    

    and then here's how a sample request might look like:

    <s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
      <s:Body>
        <GetDataUsingDataContract xmlns="http://tempuri.org/">
          <composite xmlns:a="http://schemas.datacontract.org/2004/07/WcfService1" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
            <a:ClassesCollection>
              <a:BaseClass i:type="a:ClassA">
                <a:Id>1</a:Id>
                <a:Name>5</a:Name>
              </a:BaseClass>
            </a:ClassesCollection>
          </composite>
        </GetDataUsingDataContract>
      </s:Body>
    </s:Envelope>