none
sending xml string to generated webservice proxy stub RRS feed

  • Question

  • 

    Hi

    I'm working with a third party webservice that I have no control over. I generated the proxy stub as usual, and I can call every method just fine. The thing is, one particular call takes an object that has multiple string properties, one of which is not a simple strong, but needs to be a valid xml element using a specific syntax (of varying content... basically I have to put this thing together with string concatenation).

    So naturally, if I piece together the XML string, assign it to the appropriate proxy object property and send it using my proxy stub, the remote end complains that I'm not sending a valid xml element. Looking at the exchange in wireshark, I see that my nicely formatted xml string gets xml formatted (< replaced by &lt; etc.). So, how do I pass my XML string into that object (I don't want to write manual HTTPWebRequests) so that the WCF layer leaves it alone and passes it (and only that one string in one of the generated objects) alone and sends it as it without any additional encoding (while still performing the necessary encoding, assign envelope, etc) for the rest?

    Regards

    Stephan
    Tuesday, July 16, 2013 5:47 PM

Answers

  • Hello Stephan,

    Assuming you are using C# and not BizTalk:

    The simplest solution is to modify the generated proxy to adhere to the service.  I have had to do this occassionally when consuming non-microsoft delivered solutions (e.g., websphere, java).

    Hopefully the above will work depending on how complex the xml is.  Another way would be to modify the message in the WCF stack.  This is easier than it sounds and there are plenty of articles on how to create a custom dispatcher. 


    Jeff

    Wednesday, July 17, 2013 12:19 AM

All replies

  • Hello Stephan,

    Assuming you are using C# and not BizTalk:

    The simplest solution is to modify the generated proxy to adhere to the service.  I have had to do this occassionally when consuming non-microsoft delivered solutions (e.g., websphere, java).

    Hopefully the above will work depending on how complex the xml is.  Another way would be to modify the message in the WCF stack.  This is easier than it sounds and there are plenty of articles on how to create a custom dispatcher. 


    Jeff

    Wednesday, July 17, 2013 12:19 AM
  • Jeff

    Yes I'm using C#. What additional attribute would I have to assign to to the object (just realized the proxy generated says the property is an object, even though the contents will be a string) so that it won't be xml encoded?

    Currently, the property looks as follows in the generated proxy code

            /// <remarks/>
            [System.Xml.Serialization.XmlElementAttribute(Order=1)]
            public object richPresence {
                get {
                    return this.richPresenceField;
                }
                set {
                    this.richPresenceField = value;
                    this.RaisePropertyChanged("richPresence");
                }
            }

    And this is my full object

        /// <remarks/>
        [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.18046")]
        [System.SerializableAttribute()]
        [System.Diagnostics.DebuggerStepThroughAttribute()]
        [System.ComponentModel.DesignerCategoryAttribute("code")]
        [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:cisco:cup:presence:soap")]
        public partial class PresenceInfoType : object, System.ComponentModel.INotifyPropertyChanged {
            
            private string basicPresenceField;
            
            private object richPresenceField;
            
            private bool overrideField;
            
            /// <remarks/>
            [System.Xml.Serialization.XmlElementAttribute(Order=0)]
            public string basicPresence {
                get {
                    return this.basicPresenceField;
                }
                set {
                    this.basicPresenceField = value;
                    this.RaisePropertyChanged("basicPresence");
                }
            }
            
            /// <remarks/>
            [System.Xml.Serialization.XmlElementAttribute(Order=1)]
            public object richPresence {
                get {
                    return this.richPresenceField;
                }
                set {
                    this.richPresenceField = value;
                    this.RaisePropertyChanged("richPresence");
                }
            }
            
            /// <remarks/>
            [System.Xml.Serialization.XmlElementAttribute(Order=2)]
            public bool @override {
                get {
                    return this.overrideField;
                }
                set {
                    this.overrideField = value;
                    this.RaisePropertyChanged("override");
                }
            }
            
            public event System.ComponentModel.PropertyChangedEventHandler PropertyChanged;
            
            protected void RaisePropertyChanged(string propertyName) {
                System.ComponentModel.PropertyChangedEventHandler propertyChanged = this.PropertyChanged;
                if ((propertyChanged != null)) {
                    propertyChanged(this, new System.ComponentModel.PropertyChangedEventArgs(propertyName));
                }
            }
        }


    • Edited by Stephan Steiner Wednesday, July 17, 2013 8:24 AM added full object
    Wednesday, July 17, 2013 7:22 AM
  • Hello Stephan,

    This should be easy enough if you have access to the proxy.  What you can do is implement the IXmlSerializable interface to write custom xml string. 

    Here is a cheesy example but should suffice:

    public partial class PresenceInfoType : object, System.ComponentModel.INotifyPropertyChanged, IXmlSerializable
    {
    /* everything the same and add the following */
    
            public System.Xml.Schema.XmlSchema GetSchema()
            {
                throw new NotImplementedException();
            }
    
            public void ReadXml(XmlReader reader)
            {
                throw new NotImplementedException();
            }
    
            public void WriteXml(XmlWriter writer)
            {
                writer.WriteRaw("<this><is><some>Xml</some></is></this>");   
            }
    }

    Let me know if this works for you.


    Jeff

    Wednesday, July 17, 2013 10:09 PM
  • Hi Jeff

    By the looks of it, this means I have to parse / write the entire object manually. Isn't there a way to limit the "use raw" behavior to just the one attribute. The same object is also return type to two other operations (that are get operations.. my problems is in the set operation). Of course, parsing one object is way better than all the objects, but, well you know.

    Friday, July 19, 2013 8:01 PM
  • Okay, went ahead and implemented my WriteXml - and then when I make the first call to my proxy stub, I get an InvalidOperationException "There was an error reflecting 'setPresence'". setPresence is the command that uses the PresenceInfoType

    /// <remarks/>
        [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.18046")]
        [System.SerializableAttribute()]
        [System.Diagnostics.DebuggerStepThroughAttribute()]
        [System.ComponentModel.DesignerCategoryAttribute("code")]
        [System.Xml.Serialization.XmlTypeAttribute(AnonymousType=true, Namespace="urn:cisco:cup:presence:soap")]
        public partial class setPresence : object, System.ComponentModel.INotifyPropertyChanged {
            
            private string presenceTypeField;
            
            private PresenceInfoType presenceInfoField;
            
            private int expirationField;
            
            /// <remarks/>
            [System.Xml.Serialization.XmlElementAttribute(Order=0)]
            public string presenceType {
                get {
                    return this.presenceTypeField;
                }
                set {
                    this.presenceTypeField = value;
                    this.RaisePropertyChanged("presenceType");
                }
            }
            
            /// <remarks/>
            [System.Xml.Serialization.XmlElementAttribute(Order=1)]
            public PresenceInfoType presenceInfo {
                get {
                    return this.presenceInfoField;
                }
                set {
                    this.presenceInfoField = value;
                    this.RaisePropertyChanged("presenceInfo");
                }
            }
            
            /// <remarks/>
            [System.Xml.Serialization.XmlElementAttribute(Order=2)]
            public int expiration {
                get {
                    return this.expirationField;
                }
                set {
                    this.expirationField = value;
                    this.RaisePropertyChanged("expiration");
                }
            }
            
            public event System.ComponentModel.PropertyChangedEventHandler PropertyChanged;
            
            protected void RaisePropertyChanged(string propertyName) {
                System.ComponentModel.PropertyChangedEventHandler propertyChanged = this.PropertyChanged;
                if ((propertyChanged != null)) {
                    propertyChanged(this, new System.ComponentModel.PropertyChangedEventArgs(propertyName));
                }
            }

    Just to be on the safe side, I set breakpoints in the new methods (I was expecting GetSchema to be hit..), but I saw nothing untowards. So what am I missing?

    Monday, July 22, 2013 8:27 AM
  • Hello Stephan,

    The GetSchema is for metadata so is not referenced as part of normal messaging.  From your text, do you only have access to the client (source code/debugging)?  Did you look at the svctrace to see if the message being sent looks correct?  Do you have an example of a good XML payload?


    Jeff

    Monday, July 22, 2013 8:26 PM
  • Hello Stephan,

    I uploaded a sample project that I hope helps illustrates what I am describing.

    http://gallery.technet.microsoft.com/Serializing-WCF-contract-2a585a00

    Of course, I am making some assumptions as to what you are trying to accomplish so let me know if I am heading in the wrong direction.  Also, make sure to look at the wcf tracing (web.config and app.config).


    Jeff

    Tuesday, July 23, 2013 2:51 AM
  • Unforatunately, my projects come and go and I just only return to this subject.

    I'm afraid I do not understand how your

    presence = client.GetPresence(BuildSimplePresence("some simple content that will be encoded <here> and <there>."));


    ends up xml encoded and 

    presence = client.GetPresence(BuildSimplePresence(xml.OuterXml));


    does not.. and that's what I

    need to be able to control (and I have no control over the server whatsoever). How does xml.OuterXml not get XML encoded?

    This is what I'm trying to send:

    <presence xmlns="urn:ietf:params:xml:ns:pidf" xmlns:rp="urn:ietf:params:xml:ns:pidf:rpid" xmlns:dm="urn:ietf:params:xml:ns:pidf:data-model" xmlns:ce="urn:cisco:params:xml:ns:pidf:rpid" xmlns:so="urn:cisco:params:xml:ns:pidf:source" xmlns:sc="urn:ietf:params:xml:ns:pidf:servcaps" entity="lsste@nxodev.intra"><ce:person id="lsste"></ce:person><tuple id="cisco-pws"><so:source>Presence Web Service</so:source><status><basic>closed</basic></status><activities><busy /></activities><sc:servcaps><sc:audio>true</sc:audio></sc:servcaps></tuple></presence>

    If I send this, this is what goes over the wire:

    POST http://chdevcimp105.nxodev.intra:8082/presence-service/soap HTTP/1.1
    Content-Type: text/xml; charset=utf-8
    VsDebuggerCausalityData: uIDPo1jvkPX6F1hEuDK9B0oO6gEAAAAAkmX6hrc5XkqofRlhAUr7YmyVnaMCxe9LmUMF66dJi04ACQAA
    SOAPAction: "urn:cisco:cup:presence:soap/setPresence"
    Host: chdevcimp105.nxodev.intra:8082
    Content-Length: 1248
    Expect: 100-continue
    Accept-Encoding: gzip, deflate

    <s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/"><s:Header><h:session-key xmlns:h="urn:cisco:cup:presence:soap" xmlns="urn:cisco:cup:presence:soap">548b06f6-dd-38312d92-6ca4-2</h:session-key></s:Header><s:Body xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"><setPresence xmlns="urn:cisco:cup:presence:soap"><presenceType>RICH_PRESENCE</presenceType><presenceInfo><richPresence xsi:type="xsd:string">&lt;presence xmlns="urn:ietf:params:xml:ns:pidf" xmlns:rp="urn:ietf:params:xml:ns:pidf:rpid" xmlns:dm="urn:ietf:params:xml:ns:pidf:data-model" xmlns:ce="urn:cisco:params:xml:ns:pidf:rpid" xmlns:so="urn:cisco:params:xml:ns:pidf:source" xmlns:sc="urn:ietf:params:xml:ns:pidf:servcaps" entity="lsste@nxodev.intra"&gt;&lt;ce:person id="lsste"&gt;&lt;/ce:person&gt;&lt;tuple id="cisco-pws"&gt;&lt;so:source&gt;Presence Web Service&lt;/so:source&gt;&lt;status&gt;&lt;basic&gt;closed&lt;/basic&gt;&lt;/status&gt;&lt;activities&gt;&lt;busy /&gt;&lt;/activities&gt;&lt;sc:servcaps&gt;&lt;sc:audio&gt;true&lt;/sc:audio&gt;&lt;/sc:servcaps&gt;&lt;/tuple&gt;&lt;/presence&gt;</richPresence><override>true</override></presenceInfo><expiration>3600</expiration></setPresence></s:Body></s:Envelope>

    Note that my XML gets XML encoded. What should go over the wire is this:

    POST http://chdevcimp105.nxodev.intra:8082/presence-service/soap HTTP/1.1
    Content-Type: text/xml; charset=utf-8
    VsDebuggerCausalityData: uIDPo1jvkPX6F1hEuDK9B0oO6gEAAAAAkmX6hrc5XkqofRlhAUr7YmyVnaMCxe9LmUMF66dJi04ACQAA
    SOAPAction: "urn:cisco:cup:presence:soap/setPresence"
    Host: chdevcimp105.nxodev.intra:8082
    Content-Length: 1248
    Expect: 100-continue
    Accept-Encoding: gzip, deflate

    <s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/"><s:Header><h:session-key xmlns:h="urn:cisco:cup:presence:soap" xmlns="urn:cisco:cup:presence:soap">548b06f6-dd-38312d92-6ca4-2</h:session-key></s:Header><s:Body xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"><setPresence xmlns="urn:cisco:cup:presence:soap"><presenceType>RICH_PRESENCE</presenceType><presenceInfo><richPresence xsi:type="xsd:string"><presence xmlns="urn:ietf:params:xml:ns:pidf" xmlns:rp="urn:ietf:params:xml:ns:pidf:rpid" xmlns:dm="urn:ietf:params:xml:ns:pidf:data-model" xmlns:ce="urn:cisco:params:xml:ns:pidf:rpid" xmlns:so="urn:cisco:params:xml:ns:pidf:source" xmlns:sc="urn:ietf:params:xml:ns:pidf:servcaps" entity="lsste@nxodev.intra"><ce:person id="lsste"></ce:person><tuple id="cisco-pws"><so:source>Presence Web Service</so:source><status><basic>closed</basic></status><activities><busy /></activities><sc:servcaps><sc:audio>true</sc:audio></sc:servcaps></tuple></presence></richPresence><override>true</override></presenceInfo><expiration>3600</expiration></setPresence></s:Body></s:Envelope>

    And then there's the reverse way that also seems to be a bit problematic. Here's an example what comes over the wire when I ask the server to send my rich presence:

    HTTP/1.1 200 OK
    Date: Fri, 12 Dec 2014 14:53:57 GMT
    Server: Apache/2.2.4 (Unix) DBL2/2.00 IMDB/1.00
    Last-Modified: Fri, 12 Dec 2014 14:53:57 GMT
    Content-Length: 1635
    Content-Type: text/xml; charset=utf-8

    <?xml version="1.0" encoding="UTF-8"?>
    <SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:cup="urn:cisco:cup:presence:soap"><SOAP-ENV:Header></SOAP-ENV:Header><SOAP-ENV:Body><cup:getPolledPresenceResponse><cup:presenceResponse><cup:presenceType>RICH_PRESENCE</cup:presenceType><richPresenceList xmlns="urn:cisco:cup:presence:soap"><presence entity="sip:lsste@nxodev.intra"  xmlns="urn:ietf:params:xml:ns:pidf"><person xmlns="urn:cisco:params:xml:ns:pidf:rpid" id="lsste"><activities><away/><phone-status>unavailable</phone-status><im-status>available</im-status></activities><class>manual</class></person><tuple xmlns="urn:ietf:params:xml:ns:pidf" id="Jabberjabber_13366"><status><basic>open</basic></status><servcaps xmlns="urn:ietf:params:xml:ns:pidf:servcaps"><type>text/plain</type><type>application/x-cisco-cupc+xml</type><text>true</text></servcaps></tuple>  <tuple xmlns="urn:ietf:params:xml:ns:pidf" id="cisco-pws"> <contact priority="0.5">sip:lsste@nxodev.intra</contact> <so:source xmlns:so="urn:cisco:params:xml:ns:pidf:source">Presence Web Service</so:source> <sc:servcaps xmlns:sc="urn:ietf:params:xml:ns:pidf:servcaps"> <sc:audio>false</sc:audio> <sc:video>false</sc:video> <sc:text>false</sc:text> <sc:type>text/plain; charset=UTF-8</sc:type> </sc:servcaps> <status> <basic>closed</basic> </status> </tuple> </presence></richPresenceList></cup:presenceResponse></cup:getPolledPresenceResponse></SOAP-ENV:Body></SOAP-ENV:Envelope>

    You see, it's perfectly formatted XML, not an XML formatted string. 

    The object for the response in the stub is

        /// <remarks/>    [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")]    [System.SerializableAttribute()]    [System.Diagnostics.DebuggerStepThroughAttribute()]    [System.ComponentModel.DesignerCategoryAttribute("code")]    [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:cisco:cup:presence:soap")]    public partial class PresenceResponse : object, System.ComponentModel.INotifyPropertyChanged {                private string presenceTypeField;                private ContactStatusType[] basicPresenceListField;                private object richPresenceListField;                /// <remarks/>        [System.Xml.Serialization.XmlElementAttribute(Order=0)]        public string presenceType {            get {                return this.presenceTypeField;            }            set {                this.presenceTypeField = value;                this.RaisePropertyChanged("presenceType");            }        }                /// <remarks/>        [System.Xml.Serialization.XmlArrayAttribute(Order=1)]        [System.Xml.Serialization.XmlArrayItemAttribute("contact", IsNullable=false)]        public ContactStatusType[] basicPresenceList {            get {                return this.basicPresenceListField;            }            set {                this.basicPresenceListField = value;                this.RaisePropertyChanged("basicPresenceList");            }        }                /// <remarks/>        [System.Xml.Serialization.XmlElementAttribute(Order=2)]        public object richPresenceList {            get {                return this.richPresenceListField;            }            set {                this.richPresenceListField = value;                this.RaisePropertyChanged("richPresenceList");            }        }                public event System.ComponentModel.PropertyChangedEventHandler PropertyChanged;                protected void RaisePropertyChanged(string propertyName) {            System.ComponentModel.PropertyChangedEventHandler propertyChanged = this.PropertyChanged;            if ((propertyChanged != null)) {                propertyChanged(this, new System.ComponentModel.PropertyChangedEventArgs(propertyName));            }        }    }
    And this gets decoded to {System.Xml.XmlNode[2]} which is not at all what I'm looking for. What would be the way to go about getting out the raw xml string so that I can then parse it into a proper object?

    Friday, December 12, 2014 2:56 PM