inzoik has asked for the wisdom of the Perl Monks concerning the following question:

I am trying to migrate a set of web services to run under Apache::SOAP instead of POE::Component::Server::SOAP and am observing a behavior which has halted the whole process.
use POE; use POE::Component::Server::SOAP; POE::Component::Server::SOAP->new( 'ALIAS' => 'MySOAP', 'ADDRESS' => 'localhost', 'PORT' => 32080, ); POE::Session->create( 'inline_states' => { '_start' => \&setup_service, '_stop' => \&shutdown_service, 'hi' => \&hi, }, ); $poe_kernel->run; exit 0; sub setup_service { my $kernel = $_[KERNEL]; $kernel->alias_set( 'Demo' ); $kernel->post( 'MySOAP', 'ADDMETHOD', 'Demo', 'hi' ); } sub shutdown_service { $_[KERNEL]->post( 'MySOAP', 'DELMETHOD', 'Demo', 'hi'); } sub hi { my $response = $_[ARG0]; my $params = $response->soapbody; $response->content( "Hello" ); $_[KERNEL]->post( 'MySOAP', 'DONE', $response ); } 1;
With SOAP::Trace enabled the soap body for the POE code above was
<namesp1:hiResponse xmlns:namesp1="http://127.0.0.1:32080/"> <s-gensym3 xsi:type="xsd:string">Hello</s-gensym3> </namesp1:hiResponse>
Whereas the Apache::SOAP code below
#!/usr/bin/perl use SOAP::Transport::HTTP; SOAP::Transport::HTTP::CGI ->dispatch_to('Demo') ->handle; package Demo; sub hi { return 'Hello'; } 1;
is generating
<hiResponse xmlns="http://127.0.0.1/Demo"> <s-gensym3 xsi:type="xsd:string">Hello</s-gensym3> </hiResponse>
The above difference is preventing a .Net client from reading the response. Any suggestions or pointers would be highly appreciated.

Replies are listed 'Best First'.
Re: Adding namespace in Method Response
by ikegami (Patriarch) on Aug 12, 2010 at 20:53 UTC

    The above difference is preventing a .Net client from reading the response

    There are three differences. To which one are you referring?

    • The different namespace for hiResponse ("http://127.0.0.1/Demo" instead of "http://127.0.0.1:32080/")
    • The different namespace for s-gensym3 ("http://127.0.0.1/Demo" instead of null)
    • The different prefix for the main namespace (none instead of "namesp1")

    By the way, if it's the last one, the client's parser is buggy. It doesn't mean there's no workaround, though.

      .Net needs the namespace to be qualified and not the default - as long as it says namesp1:hiResponse everything is good.

        You must mean "the namespace must be specified using a prefix", item #3. What a stupid parser. I'll look into workarounds tonight.

        Update: Looks like someone already found one.

Re: Adding namespace in Method Response
by Anonymous Monk on Aug 12, 2010 at 21:08 UTC
    See Re^3: How to get SOAP Tags in SOAP::Lite Server (and Re^3: How to get SOAP Tags in SOAP::Lite Server) and Quick Start with SOAP and POE/Component/Server/SOAP.pm
    my $content = SOAP::Serializer->prefix( 's' )->envelope( 'response', SOAP::Data->name( $response->soapmethod() . 'Response' )->uri( + $response->soapuri() ), # Do we need to serialize the content or not? ( $_[STATE] eq 'RAWDONE' ? SOAP::Data->type( 'xml', $response- +>content() ) : $response->content() ), );
    I believe, uri() corresponds to namesp1, so combining all that information I have
    #!/usr/bin/perl -- use strict; use warnings; use SOAP::Lite; my $content = SOAP::Serializer->prefix('s')->envelope( 'response', SOAP::Data->name( 'hi' . 'Response' ) ->uri( 'namesp1' ), 'Hello', ); print $content,"\n"; __END__
    which outputs a body
    $ perl soap-lite-uri-namespace.pl |xml_grep --nowrap soap:Body |xml_pp <soap:Body> <namesp1:hiResponse xmlns:namesp1="namesp1"> <s-gensym3 xsi:type="xsd:string">Hello</s-gensym3> </namesp1:hiResponse> </soap:Body>
      Thank you , thank you, thank you - I cant thank you enough number of times for the example.

      I had probably looked at that piece of code 4-5 times yet it didn't strike me as the relevant.

      So I reviewed what POE is doing in the sub TransactionDone section in http://cpansearch.perl.org/src/APOCAL/POE-Component-Server-SOAP-1.14/lib/POE/Component/Server/SOAP.pm. I also looked at http://cookbook.soaplite.com/#changing%20method%20name%20in%20response including the discussion section and came up with the following cgi which worked perfectly.

      use SOAP::Transport::HTTP; my $server = new SOAP::Transport::HTTP::CGI ->serializer(MySerializer->new) ->dispatch_to('Demo') ->handle(); BEGIN { package MySerializer; @MySerializer::ISA = qw/SOAP::Serializer/; sub envelope { $_[2] = SOAP::Data->name($_[2])->uri($_[0]->uri()) if +$_[1] =~ /^(?:method|response)$/; shift->SUPER::envelope(@_); } } package Demo; use SOAP::Lite; sub hi { return 'Hello'; }

      After that got working perfectly I had to do the following to get it all working under mod_perl

      1. Added a Location section as follows

      <Location /session> Order Deny,Allow SetHandler perl-script PerlHandler SOAP::Apache </Location>
      2. Added the following in my startup handler
      package MySerializer; @MySerializer::ISA = qw/SOAP::Serializer/; sub envelope { $_[2] = SOAP::Data->name($_[2])->uri($_[0]->uri()) if $_[1] =~ + /^(?:method|response)$/; shift->SUPER::envelope(@_); } package SOAP::Apache; use SOAP::Transport::HTTP; my $server = SOAP::Transport::HTTP::Apache ->serializer(MySerializer->new) -> dispatch_to(... ... ...); sub handler { $server->handler(@_) } 1;
      Currently the XML looks great under SOAP::Trace - will have more feedback tomorrow after the .Net client gives it a shot.

      Again thanks a lot for guiding me.