Search code examples
wcfsoapksoap2

ksoap2 and WCF complex types


I'm sending this request to my WCF webservice with a Android client using ksoap2:

<v:Envelope xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns:d="http://www.w3.org/2001/XMLSchema" xmlns:c="http://schemas.xmlsoap.org/soap/encoding/" xmlns:v="http://schemas.xmlsoap.org/soap/envelope/"><v:Header />
    <v:Body>
        <HelloComplex xmlns="http://tempuri.org/" id="o0" c:root="1">
            <complex i:type="n0:SampleComplexType" xmlns:n0="http://tempuri.org/">
                <Value i:type="d:string">Hello!</Value>
            </complex>
        </HelloComplex>
    </v:Body>
</v:Envelope>

and receive back this:

<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
    <s:Body>
        <s:Fault>
            <faultcode xmlns:a="http://schemas.microsoft.com/net/2005/12/windowscommunicationfoundation/dispatcher">a:DeserializationFailed</faultcode>
            <faultstring xml:lang="pt-BR">
                The formatter threw an exception while trying to deserialize the message: There was an error while trying to deserialize parameter http://tempuri.org/:complex. The InnerException message was 'Error in line 1 position 363. Element 'http://tempuri.org/:complex' contains data from a type that maps to the name 'http://tempuri.org/:SampleComplexType'. The deserializer has no knowledge of any type that maps to this name. Consider using a DataContractResolver or add the type corresponding to 'SampleComplexType' to the list of known types - for example, by using the KnownTypeAttribute attribute or by adding it to the list of known types passed to DataContractSerializer.'.  Please see InnerException for more details.
            </faultstring>
        </s:Fault>
    </s:Body>
</s:Envelope>

But when my other application (AspNew MVC) call this :

<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
    <s:Body>
        <HelloComplex xmlns="http://tempuri.org/">
            <complex xmlns:a="http://schemas.datacontract.org/2004/07/IssueCenter.Core" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
                <a:Value>C#VALUE!</a:Value>
            </complex>
        </HelloComplex>
    </s:Body>
</s:Envelope>

ant it works.

What can I do to fix my Android client requests?

Notes: I know about the namespace diference and I already try to make the same.


Solution

  • The service doesn't know how to deal with the "ComplexType" type attribute in the XML, so you basically need to tell the service-side serializer what it means. You can do it in a few ways: either you add a DataContractResolver that tells the serializer what this unknown type ID means, or you can add the type (if it exists on the service side) to the list of "known types", so that the service knows exactly what to do with it. I think you should use a DataContractResolver.

    In the version 4.0 of the framework, WCF introduced the data contract resolver. Instead of defining the set of known types “statically” (e.g. by specifying the types directly in a KnownTypeAttribute like you did until .NET 4), the data contract resolver provides some hooks which allow you to specify, at the moment when the object is being serialized or deserialized, a mapping between the CLR type and the name / namespace in the XML which will be used to represent this “unknown” type. To do this, you just inherit from the DataContractResolver class and provide your mapping logic.

    I think this is the better solution for you, because you likely don't want to create a dummy type on the server side just to deal with this problem, which is what you'd have to do if you were to use KnownTypeAttribute. Only thing to remember is that a resolver makes the serialization slower than using the “standard” known types feature (since known types are static, they can be cached and the calls don’t need to be made all the time), so be aware that when using the resolver, the additional functionality comes at a price in terms of execution time.