1

I have two classes, one implements IXmlSerializable and one has DataContract attribute:

public class Foo : IXmlSerializable
{
    public XmlSchema GetSchema()
    {
        return null;
    }

    public void ReadXml(XmlReader reader)
    {
        reader.MoveToContent();
        XElement element = (XElement)XNode.ReadFrom(reader);

        if (element.Element("Foo") != null)
            element = element.Element("Foo");

        Property = Convert.ToInt32(element.Element("Property").Value);
    }

    public void WriteXml(XmlWriter writer)
    {
        var element = new XElement("Foo");
        element.Add(new XElement("Property", Property));

        element.WriteTo(writer);
    }

    public int Property { get; set; }
}

[DataContract]
public class Bar
{
    [DataMember]
    public int Property { get; set; }
}

Then I have the service interface

[ServiceContract]
public interface IFooBarService
{
    [OperationContract]
    void TestFoo(Foo toTest);

    [OperationContract]
    void TestListFoo(Foo[] toTest);

    [OperationContract]
    void TestBar(Bar toTest);

    [OperationContract]
    void TestListBar(Bar[] toTest);
}

And its implementation as:

public class FooBarService : IFooBarService
{

    public void TestFoo(Foo toTest)
    {
        var a = toTest.Property;
    }

    public void TestListFoo(Foo[] toTest)
    {
        foreach (var item in toTest)
        {
            var x = item.Property;
        }
    }

    public void TestBar(Bar toTest)
    {
        var a = toTest.Property;
    }

    public void TestListBar(Bar[] toTest)
    {
        foreach (var item in toTest)
        {
            var x = item.Property;
        }
    }
}

SOAP UI generated the xml needed to call the service. All works correctly except the call to TestListFoo where I receive an empty array

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:tem="http://tempuri.org/" xmlns:com="http://schemas.datacontract.org/2004/07/Com.Panotec.Remote.Core.WebService" xmlns:xs="http://www.w3.org/2001/XMLSchema">
   <soapenv:Header/>
   <soapenv:Body>
     <tem:TestListFoo>
       <tem:toTest>      
         <Foo>
           <Property>1</Property>
         </Foo>    
         <Foo>
           <Property>1</Property>
         </Foo>    
         <Foo>
           <Property>1</Property>
         </Foo>    
         <Foo>
           <Property>1</Property>
         </Foo>
       </tem:toTest>
     </tem:TestListFoo>
   </soapenv:Body>
</soapenv:Envelope>

What am I missing? Is it possible to achieve what I need? If not, how can I add the DataContract attribute to the class that implements IXmlSerializable?

Thanks

Michele mpp Marostica
  • 2,445
  • 4
  • 29
  • 45
  • 1
    DataContracts must not have methods and logic. They must be used only to transfer data. The code relevant to reading and writing xml must reside in a different service or helper class. – Houssam Hamdan Jul 31 '17 at 09:00
  • 1
    @HoussamHamdan - `DataContractSerializer` does in fact support `IXmlSerializable`. See [Types Supported by the Data Contract Serializer](https://learn.microsoft.com/en-us/dotnet/framework/wcf/feature-details/types-supported-by-the-data-contract-serializer): *Additionally, types that implement the IXmlSerializable interface are supported*. – dbc Jul 31 '17 at 09:05
  • @dbc i am stressing here that we should not write logic inside DTO classes. – Houssam Hamdan Jul 31 '17 at 09:10
  • @dbc but if I add the [DataContract] attribute to the Foo class I get a compilation error – Michele mpp Marostica Jul 31 '17 at 09:13
  • @HoussamHamdan so I should write a class only with data and when it is received from the WCF service I have to use that data to initialize the other class with the logic? – Michele mpp Marostica Jul 31 '17 at 09:14
  • @Michele - yes that's correct. Microsoft allows one or the other but not both, since they would conflict. When a type is marked with `IXmlSerializable` the data contract serializer handles it like `XmlSerializer` did. – dbc Jul 31 '17 at 09:16
  • @dbc ok in fact when I call TestFoo it works correctly. But why I do not receive the data when calling the TestListFoo function? Is the XML not correct? – Michele mpp Marostica Jul 31 '17 at 09:18
  • @Michele - looking into it. – dbc Jul 31 '17 at 09:19
  • @Michele - what XML is generated for the call to `TestFoo()`? – dbc Jul 31 '17 at 09:23
  • 1
    @dbc adding the namespace `com:` (I copied it from the `Bar` related xml) at the `Foo` tag made it work as expected, I'm doing more tests to verify it – Michele mpp Marostica Jul 31 '17 at 09:33
  • 1
    @Michele - that's consistent with [this answer](https://stackoverflow.com/a/12041239) to [WCF Service via JavaScript with XML - Array parameters](https://stackoverflow.com/q/12041130) which array items corresponding to complex objects should be in the namespace of the object, which in your case must be the `com:` namespace. – dbc Jul 31 '17 at 09:49
  • 1
    @Michele yes, dont mix concerns. Each layer must have a clear responsibility. – Houssam Hamdan Jul 31 '17 at 10:20

0 Answers0