|
|
|
#1 |
|
Messages: n/a
Hébergeur: |
Hello all,
I posted this question last week in the soap4r group but haven't received any replies. So I'm hoping maybe someone here can . My situation is this; I 've generated the default/driver/ mappingRegistry using wsdl2ruby for a client that will consume .Net web service I have created a customized SOAP::Filter::Handler that takes care of assigning the soap: namespace to the elements, and I've created a customized SOAP::Header::Handler that takes care of the custom auth header elements. So far, so good. I've compared the generated request between a working .Net client and my ruby client, and they are virtually identical with one exception; for the initial authentication call (e.g. signon), there is no payload in the soap:Body. The .Net client generates this empty body as <soap:Body/> (self closing) whereas the ruby version generates <soap:Body></soap:Body>. I realize both are perfectly valid and should be interpreted the same way, but unfortunately, this is not the case. I don''t have access to the source code for this web service, but I was able to decompile the dll, and guess what... Whoever wrote it, has some code that is checking specifically for the existence of a self closed body tag. When the code doesn't see the self closed tag, it assumes there will be a payload, and proceeds to do a substring on it to get a known piece of data out. Unfortunately again, this is causing a .Net exception to be thrown (index out of range type of exception) which blows the whole deal. Ideally, I'd have the web service modified to use an XML DOM parser instead, but I don't have this luxury. So, my question is; Is there any way to override the default behavior in soap4r to make it render the empty body with a self closing tag (<soap:Body/>)? I really hope so because I'd hate to have to scrap this project over something so silly! Thanks in advance! |
|
|
|
#2 |
|
Messages: n/a
Hébergeur: |
jammendolia wrote:
> Hello all, > > I posted this question last week in the soap4r group but haven't > received any replies. So I'm hoping maybe someone here can . > > My situation is this; I 've generated the default/driver/ > mappingRegistry using wsdl2ruby for a client that will consume .Net > web service > > I have created a customized SOAP::Filter::Handler that takes care of > assigning the soap: namespace to the elements, and I've created a > customized SOAP::Header::Handler that takes care of the custom auth > header elements. So far, so good. > > I've compared the generated request between a working .Net client and > my ruby client, and they are virtually identical with one exception; > for the initial authentication call (e.g. signon), there is no payload > in the soap:Body. The .Net client generates this empty body as > <soap:Body/> (self closing) whereas the ruby version generates > <soap:Body></soap:Body>. > ... > So, my question is; Is there any way to override the default behavior > in soap4r to make it render the empty body with a self closing tag > (<soap:Body/>)? > A hack: take the final XML and do a string substitution. final_xml.sub!( '<soap:Body></soap:Body>', '<soap:Body/>') untested, YMMV, etc. -- James Britt http://www.ruby-doc.org - Ruby & Documentation http://www.rubystuff.com - The Ruby Store for Ruby Stuff |
|
|
|
#3 |
|
Messages: n/a
Hébergeur: |
>
> A hack: take the final XML and do a string substitution. > > final_xml.sub!( '<soap:Body></soap:Body>', '<soap:Body/>') > Thanks for the reply James! I had thought of using this approach, and I'm completely open to it, my problem is that I'm not sure where I can intercept the request to make this change. I need to hook in somewhere after it's been generated but before it's sent across the wire. Any suggestions? Thanks again, Joe |
|
|
|
#4 |
|
Messages: n/a
Hébergeur: |
On Mar 31, 4:12 pm, jammendolia <jammendo...@gmail.com> wrote:
> > A hack: take the final XML and do a string substitution. > > > final_xml.sub!( '<soap:Body></soap:Body>', '<soap:Body/>') > > Thanks for the reply James! > > I had thought of using this approach, and I'm completely open to it, > my problem is that I'm not sure where I can intercept the request to > make this change. I need to hook in somewhere after it's been > generated but before it's sent across the wire. > > Any suggestions? > > Thanks again, > > Joe I'm not positive, but I think you could implement James's idea in SOAP::RPC::Proxy#marshal (in /usr/lib/ruby/1.8/soap/rpc/proxy.rb here). I haven't tested this, but I would save this: module SOAP module RPC class Proxy private class Operation private def marshal(env, opt) send_string = Processor.marshal(env, opt) send_string && send_string.sub!('<soap:Body></soap:Body>', '<soap:Body/>') StreamHandler::ConnectionData.new(send_string) end end end end end and require it in your project. I'm not sure I have all the privates in the right place, but that should be close. Jeremy |
|
|
|
#5 |
|
Messages: n/a
Hébergeur: |
On Mar 31, 6:51 pm, yermej <yer...@gmail.com> wrote:
> On Mar 31, 4:12 pm, jammendolia <jammendo...@gmail.com> wrote: > > > > > > A hack: take the final XML and do a string substitution. > > > > final_xml.sub!( '<soap:Body></soap:Body>', '<soap:Body/>') > > > Thanks for the reply James! > > > I had thought of using this approach, and I'm completely open to it, > > my problem is that I'm not sure where I can intercept the request to > > make this change. I need to hook in somewhere after it's been > > generated but before it's sent across the wire. > > > Any suggestions? > > > Thanks again, > > > Joe > > I'm not positive, but I think you could implement James's idea in > SOAP::RPC::Proxy#marshal (in /usr/lib/ruby/1.8/soap/rpc/proxy.rb > here). Sorry. That should be SOAP::RPC::Proxy::Operation#marshal. |
|
|
|
#6 |
|
Messages: n/a
Hébergeur: |
>
> > I'm not positive, but I think you could implement James's idea in > > SOAP::RPC::Proxy#marshal (in /usr/lib/ruby/1.8/soap/rpc/proxy.rb > > here). > > Sorry. That should be SOAP::RPC::Proxy::Operation#marshal. Thanks for the feedback. I managed to get it working by extending the SOAP::RPC::Proxy class like this: require 'soap/rpc/proxy' class CustomProxy < SOAP::RPC::Proxy # Here, I override the route method so that I can generate a self closed body tag. def route(req_header, req_body, reqopt, resopt) req_env = ::SOAP::SOAPEnvelope.new(req_header, req_body) unless reqopt[:envelopenamespace].nil? set_envelopenamespace(req_env, reqopt[:envelopenamespace]) end reqopt[:external_content] = nil conn_data = marshal(req_env, reqopt) #hack to generate self-closed soap:Body tag conn_data.send_string = conn_data.send_string.sub!('<soap:Body></ soap:Body>', '<soap:Body/>') if ! conn_data.send_string.rindex("<soap:Body></soap:Body>").nil? if ext = reqopt[:external_content] mime = MIMEMessage.new ext.each do |k, v| mime.add_attachment(v.data) end mime.add_part(conn_data.send_string + "\r\n") mime.close conn_data.send_string = mime.content_str conn_data.send_contenttype = mime.headers['content-type'].str end conn_data = @streamhandler.send(@endpoint_url, conn_data, reqopt[:soapaction]) if conn_data.receive_string.empty? return nil end unmarshal(conn_data, resopt) end end end And then, to make the soap4r generated driver use it, I modified the generated initializer so that it no longer calls "super". I then implemented the code from the original proxy.rb initialize which includes instantiating the proxy. Bu instead of using the default proxy, I use my custom one. here's an example: Driver.rb def initialize... .... # we do not call the base initialize here because we # need to use a custom proxy. So all of the super # initialize components are performed here # super(endpoint_url, nil) @namespace = nil @soapaction = nil @options = setup_options @wiredump_file_base = nil @proxy = CusromProxy.new(endpoint_url, @soapaction, @options) .... Thanks again for pointing me in the right direction. I hope this will someone else in the future ![]() Joe |
|
![]() |
| Outils de la discussion | |
|
|