Frage

  • Please note that i am modifying an existing service to add an extra datamember, i can not change the structure of the service nor the client. I know ASMX is outdated and best practices are not being used.

I am encountering a very weird problem and i just can not figure out how to get this to work properly. I have an ASMX web service ( i know its out of date, i can't change this) That takes a response and compresses it with zip compression. Then it is delivered to the client over SOAP and the client takes the stream and decompresses it and uses the contract created by "add service reference" and an XMLSerializer to deserialize the object.

The problem i am having is that it fails to deserialize the object correctly. My XML before compression and after decompression looks exactly the same but it appears that the web service is ignoring the ordering of my parameters. I've tried [DataMember] , [MessageBodyMember], [XmlElement],[MessageHeader] all with the correct ordering params and MustUnderstand but it seems to always stick elements at the bottom of the XML.

Here is what is confusing, my messagecontract class inherits from another message contract class like so

[MessageContract(IsWrapped = true)]
public class MyClass : MyBaseContract{}

The elements in the base contact deserialize just fine every time, even if i change them around they work just fine. The elements in there do not contain any ordering at all and they just work.

Here is my deserialization code.

using (MemoryStream stream = new MemoryStream(data))
        {
            XDocument document = XDocument.Load(stream);

            System.Xml.Serialization.XmlSerializer serializer = new System.Xml.Serialization.XmlSerializer(type);
            System.Xml.XmlReader read = System.Xml.XmlReader.Create(new System.IO.StringReader(document.ToString()));

            object o = serializer.Deserialize(read);

            return o;
        }

Here is serialization code:

        XmlSerializer xs = new XmlSerializer(value.GetType());
        MemoryStream stream = new MemoryStream();
        xs.Serialize(stream, value);
        stream.Position = 0;
        StreamReader sr = new StreamReader(stream);
        return sr.ReadToEnd();

So here is the steps that my code takes

  1. Call to web service
  2. Web service calls helper and returns a response object
  3. Response object is compressed
  4. Compressed object is sent over the wire in a soap format
  5. Client gets the response
  6. Client deserializes based on contract provided from the "Add Service Reference" feature.
  7. Client manages to deserialize data from the base class of the response but nothing from the response class itself gets deserialized.
War es hilfreich?

Lösung

Ok i solved it but its really screwy.

What happened is the "Add service reference" generated code contains a namespace aka

    [System.Xml.Serialization.XmlTypeAttribute(Namespace="http://myservice.com")]

But the XML serialization that you can perform manually does not include the namespace anywhere in the generated XML. If i specify using this code the XML serializer will break.

   [MessageContract(IsWrapped = true,WrapperNamespace="http://myservice.com")]

The ONLY way to get it to work properly is to add the line specifing the namespace from the generated code back to the contract class, like so.

[XmlType(Namespace="http://myservice.com")]
public class MyContract {}

After this addition all the generated xml will contain the full namespace in each element and the deserializer will behave properly. Why it breaks on the WCF ism for namespace i have no idea. It works fine with the other WCF isms.

The reason it was partially working in the first place is that the previous developer added a method that manually inserted the namespaces on certain XML elements on the client side. Specifically those of the base class that were working correctly! I just didn't see the method being called because it was buried so deep.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top