9

I'm trying to access a SOAP service I don't control. One of the actions is called ProcessMessage. I followed the example and generated a SOAP request, but I got an error back saying that the action doesn't exist. I traced the problem to the way the body of the envelope is generated.

<env:Envelope ... ">
    <env:Header>
        <wsse:Security ... ">
            <wsse:UsernameToken ...">
                <wsse:Username>USER</wsse:Username>
                    <wsse:Nonce>658e702d5feff1777a6c741847239eb5d6d86e48</wsse:Nonce>
                    <wsu:Created>2010-02-18T02:05:25Z</wsu:Created>
                    <wsse:Password ... >password</wsse:Password>
            </wsse:UsernameToken>
        </wsse:Security>
    </env:Header>
    <env:Body>
        <wsdl:ProcessMessage>
            <payload>
                ......
            </payload>
        </wsdl:ProcessMessage>
    </env:Body>
</env:Envelope>     

That ProcessMessage tag should be:

    <ProcessMessage xmlns="http://www.starstandards.org/webservices/2005/10/transport">

That's what it is when it is generated by the sample Java app, and it works. That tag is the only difference between what my Ruby app generates and the sample Java app. Is there any way to get rid of the "wsdl:" namespace in front of that one tag and add an attribute like that. Barring that, is there a way to force the action to be not to be generated by just passed as a string like the rest of the body?

Here is my code:

require 'rubygems'
require 'savon'
client = Savon::Client.new "https://gmservices.pp.gm.com/ProcessMessage?wsdl"

response = client.process_message! do | soap, wsse |
wsse.username = "USER"
wsse.password = "password"
soap.namespace = "http://www.starstandards.org/webservices/2005/10/transport" #makes no difference
soap.action = "ProcessMessage" #makes no difference
soap.input = "ProcessMessage" #makes no difference

#my body at this point is jsut one big xml string

soap.body = "<payload>...</payload>" 
# putting <ProccessMessage> tag here doesn't help as it just creates a duplicate tag in the body, since Savon keeps interjecting  <wsdl:ProcessMessage> tag.

  end

I tried handsoap but it doesn't support HTTPS and is confusing. I tried soap4r but but it's even more confusing than handsoap.

the Tin Man
  • 158,662
  • 42
  • 215
  • 303
konung
  • 6,908
  • 6
  • 54
  • 79
  • a ticket for this was open at: http://github.com/rubiii/savon/issues#issue/39 – rubiii Mar 06 '10 at 17:40
  • Hi Nick, did you get anywhere with this as I am seeing the same issue. – Steve Weet Mar 15 '10 at 15:07
  • Hi Steve. I put this part of the project on the waiting status - as there were other, more important, features needing implementation, and this was on a " nice to have" list. I will try your solution later today and see if works. Thank you for letting me know thou! – konung Mar 16 '10 at 18:23

4 Answers4

10

You need to pass an array to soap.input the second element of which is a hash containing the namespace details.

soap.input = [ 
  "ProcessMessage", 
  {"xmlns" => "http://www.starstandards.org/webservices/2005/10/transport"}
]

This should ensure you end up with the name space declaration as an attribute to the main element.

You will probably also end up with a namespace declaration before the element like so

<env:Body>
    <wsdl:ProcessMessage xmlns="........." >
        <payload>
            ......
        </payload>
    </wsdl:ProcessMessage>
</env:Body>

but this was not an issue for me, it was the lack of the namespace attribute that was the issue, not the presence of the namespace before the element.

Steve Weet
  • 28,126
  • 11
  • 70
  • 86
  • Steve. Thank you for your message - it's not my solution but it got me to thinking and looking at the logs more carefullly. See my own answer. There is not enough space here in comments. :-) – konung Mar 16 '10 at 20:30
  • Thanks your solution worked a charm just now when I was having the exact same problem. – Bo Jeanes Oct 20 '10 at 16:26
  • Your solution worked for me. I was missing the xmlns inside the action! I still get the wsdl: namespace inside the body, but it doesn't affect the SOAP request. – pedrofalcaocosta Jun 22 '11 at 23:49
7

For my web service I needed to get rid of the "wsdl" namespace on top of Steve's solution.

Tested with Savon 0.9.6:

client = Savon::Client.new "https://example.com/webservice/account.asmx?WSDL"
response = client.request "GetAccount" do
  # Gotcha 1: set default namespace for body elements
  soap.input = ["GetAccount", {"xmlns" => "https://example.com/webservice/"}]
  soap.body = {
    "AccountID" => 1234
  }
  # Gotcha 2: get rid of namespace declaration of body elements
  soap.element_form_default = :unqualified
  # Gotcha 3: set SOAPAction different from default
  http.headers["SOAPAction"] = '"https://example.com/webservice/GetAccount"'
end
the Tin Man
  • 158,662
  • 42
  • 215
  • 303
Kenji Noguchi
  • 1,752
  • 2
  • 17
  • 26
4

Steve, you see that wsdl: in front of ProcessMessage tag? - I thought that was the only thing that was throwing me off but its not ( by the way it's hard set in soap.rb in Savon lib on line 160). That even if I don't spacify it in soap.namespaces - it's hard generated and attached in final xml. Which is not allowed by my service.

While the xml that is generated is a valid xml - it's not complete by the requirments of the service I'm trying to talk to. I.e.: in generated xml,

<?xml version="1.0" encoding="UTF-8"?>

tag is missing, also, I need PayloadManifest in the header,plus I need wsu:created and wsu:expires in my wsse: tag, but they are not implemented, etc., etc. a bunch of other little quirks that are too specific to my case. However soap has a private method = xml_body. Also soap lib in to_xml method is checking whether @xml_body was already set, before generating it's own xml. So I ended up slighly modifying behavior of soap. by making soap.xml_body = publicly accessable. So I was able to do:

response = client.process_message! do |soap| 
soap.action = "http://www.starstandards.org/webservices/2005/10/transport/operations/ProcessMessage"
soap.xml_body = "MY XML STRING GENERATED ELSEWHERE GOES HERE"
end

Which finally works!!!!

I'll suggest this to rubii - if this option becomes available that will solve a lot rare cases - where people can generate their custom xml and use the rest of savon lib.

konung
  • 6,908
  • 6
  • 54
  • 79
  • That would be a good solution I think. I found that IIS/.net was complaining about the lack of a namespace but didn't care whether there was an directive at the top of the file. Good luck, it was pretty painful getting to that point. – Steve Weet Mar 17 '10 at 09:53
0

I spent hours trying to find a solution to get rid of:

<wsdl:ProcessMessage>
</wsdl:ProcessMessage>

This does what I wanted:

client = Savon.client(
 :no_message_tag => true
)

Tested in Savon 2.

David
  • 97
  • 9