简体   繁体   中英

SOAP Action issue when calling WCF Service in Perl (SOAP Lite)

Using Perl (SOAP Lite), I am trying to call a wcf web service where the SOAPAction name (ProcessMessage) is different to the Envelope/Body/ Request element name (Request) within the soap envelope body. How can a specify a different SOAPAction and Envelope->Body->Request element name? I cannot change the web service.

Here is an example of the SOAP Message I'm trying to replicate and I've highlighed the two areas I'm trying to specify/control independently.

<HttpRequest>
  <Method>POST</Method>
  <QueryString></QueryString>
  <WebHeaders>
<Content-Length>1245</Content-Length>
<Content-Type>text/xml; charset=utf-8</Content-Type>
<Accept-Encoding>gzip, deflate</Accept-Encoding>
<Expect>100-continue</Expect>
<Host>virscwapp01f1.sdpcsf.sdp.net.nz</Host>
<SOAPAction>"urn:sdp:manager:100818.ProfileScopeServiceContract.ProcessMessage"</SOAPAction>
</WebHeaders>
</HttpRequest>
 <s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
  <s:Header>
   <ActivityId CorrelationId="0d113c44-878d-40c4-bc3d-37a1ac9a693e" xmlns="http://schemas.microsoft.com/2004/09/ServiceModel/Diagnostics">00000000-0000-0000-0000-000000000000</ActivityId>
    <To s:mustUnderstand="1" xmlns="http://schemas.microsoft.com/ws/2005/05/addressing/none">http://[hostname]/ProfileManager/100818/ProfileManager.svc</To>
    <Action s:mustUnderstand="1" xmlns="http://schemas.microsoft.com/ws/2005/05/addressing/none">urn:manager:100818.ProfileScopeServiceContract.ProcessMessage</Action>
 </s:Header>
 <s:Body>
     <Request xmlns="urn:managerrequestmanager:100818" xmlns:a="urn:manager:requestmanager" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
  <a:Payload i:type="b:Organisation" xmlns:b="urn:manager:contract:110308">
    <b:OrganisationUnitId>OrgId</b:OrganisationUnitId>
    <b:OrganisationDescription i:nil="true"></b:OrganisationDescription>
  </a:Payload>
  <a:ProcessingInstruction xmlns:b="urn:manager:contract:common:100818">
    <b:Action>GetOrganisationById</b:Action>
    <b:Strategy>
      <b:Name i:nil="true"></b:Name>
      <b:Paging i:nil="true"></b:Paging>
      <b:SearchCriteria i:nil="true"></b:SearchCriteria>
    </b:Strategy>
    <b:Meta i:nil="true"></b:Meta>
  </a:ProcessingInstruction>
</Request>
</s:Body>
</s:Envelope>

Here is an example of the Perl script I am using

#!/usr/bin/perl

package main;
use SOAP::Lite +trace;
use LWP::UserAgent;
use HTTP::Request::Common;

# Variables
my $url = 'http://[hostname]/ProfileManager/100818/ProfileManager.svc?wsdl';
my $url_debug = 'http://localhost:11040/Service1.svc?wsdl';
my $uri = 'urn:::profilemanager:profilemanagerrequestmanager:100818';

my $soap = SOAP::Lite
-> ns( 'http://www.w3.org/2001/XMLSchema-instance', 'xsi' )
-> ns( 'urn:::profilemanager:requestmanager', 'a' )
-> ns( 'urn:::profilemanager:contract:110308', 'b'  )
-> uri($uri)
-> on_action( sub { join '.', 'urn:::profilemanager:requestmanager:100818.ProfileScopeServiceContract', $_[1] } )
-> proxy($url);


my $method = SOAP::Data->name('ProcessMessage')
->attr({xmlns => 'urn:::profilemanager:profilemanagerrequestmanager:100818'});


my @params = ( SOAP::Data->type("b:Organisation")->name("a:Payload")->value(
\SOAP::Data->value(
SOAP::Data->name("b:OrganisationUnitId")->value(""),
SOAP::Data->name("b:OrganisationDescription")->attr( { 'xsi:nil' => "true" } )  
    )
  ),
   SOAP::Data->name("a:ProcessingInstruction")->value(
   \SOAP::Data->value(
     SOAP::Data->name("b:Action")->value("GetOrganisationById"),
SOAP::Data->name("b:Strategy")->value(
    \SOAP::Data->value(
          SOAP::Data->name("b:Name")->attr( { 'xsi:nil' => "true" } ),
     SOAP::Data->name("b:Paging")->attr( { 'xsi:nil' => "true" } ),
     SOAP::Data->name("b:SearchCriteria")->attr( { 'xsi:nil' => "true" } )
     )
      ),
      SOAP::Data->name("b:Meta")->attr( { 'xsi:nil' => "true" } )
)
)
);

print $soap->call($method => @params)->result; 

Dont pay too much attention to my namespaces as I've removed portions of them.

I had to do this to make SOAP::Lite work with WCF:

my $serviceInterface = 'IMyWcfServiceInterface';

# Setup Network Connection
my $service = SOAP::Lite
    ->ns( $namespace, $namespacePrefix )
    ->proxy( $server, credentials => [ "$host:$port", $realm, $username => $password ] )
    ->on_action( sub {
        my $action = sprintf( '%s$serviceInterface/%s', @_ );
        print( "action: '$action'\n" );
        return $action;
    } );

my $response = $service->MyServiceFunction()

In your case, you seem to want the action to be: urn:sdp:manager:100818.ProfileScopeServiceContract.ProcessMessage , so you should probably be able to just use:

...
    ->on_action( 'urn:sdp:manager:100818.ProfileScopeServiceContract.ProcessMessage' )
...

Perl the pom documentation :

on_action(callback)

    $client->on_action(sub { qq("$_[0]") });

Triggered when the transport object sets up the SOAPAction header for an HTTP-based call. The default is to set the header to the string, uri#method, in which URI is the
value set by the uri method described earlier, and method is the name of the method
being called. When called, the routine referenced (or the closure, if specified as in
the example) is given two arguments, uri and method, in that order.

.NET web services usually expect / as separator for uri and method. To change SOAP::Lite's behaviour to use uri/method as SOAPAction header, use the following code:

    $client->on_action( sub { join '/', @_ } );

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM