I have been forced into a crash-course in SOAP to write an application that will post a chunk of XML to a .NET web service. I have read all the issues regarding SOAP::Lite and .NET interoperability (or inter-non-operability), and I appear to be creating the correct output, but I continue to get "400 Bad Request" errors. The developer on the .NET end has tried posting my XML using his non-Perl code and it works for him. Grrrr... Here is what the service expects:
POST /service.asmx HTTP/1.1 Host: foo.com Content-Type: text/xml; charset=utf-8 Content-Length: [length] SOAPAction: "https://foo.com/IntegrateShipmentNotice" <?xml version="1.0" encoding="utf-8"?> <soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" x +mlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schema +s.xmlsoap.org/soap/envelope/"> <soap:Body> <IntegrateShipmentNotice xmlns="https://foo.com/"> <shipmentNotice>[XML]</shipmentNotice> </IntegrateShipmentNotice> </soap:Body> </soap:Envelope>
And here is the output of my script with "debug" turned on (contents redacted for privacy):
SOAP::Transport::new: () SOAP::Serializer::new: () SOAP::Deserializer::new: () SOAP::Parser::new: () SOAP::Lite::new: () SOAP::Transport::HTTP::Client::new: () SOAP::Data::new: () SOAP::Lite::call: () SOAP::Serializer::envelope: () SOAP::Serializer::envelope: IntegrateShipmentNotice SOAP::Data=HASH(0x +89db70c) SOAP::Data::new: () SOAP::Data::new: () SOAP::Data::new: () SOAP::Data::new: () SOAP::Data::new: () SOAP::Transport::HTTP::Client::send_receive: HTTP::Request=HASH(0x89fe +bf0) SOAP::Transport::HTTP::Client::send_receive: POST https://foo.com/serv +ice.asmx HTTP/1.1 Accept: text/xml Accept: multipart/* Accept: application/soap Content-Length: 2194 Content-Type: text/xml SOAPAction: https://foo.com/IntegrateShipmentNotice <?xml version="1.0" encoding="UTF-8"?><soap:Envelope xmlns:xsi="http:/ +/www.w3.org/2001/XMLSchema-instance" xmlns:soapenc="http://schemas.xm +lsoap.org/soap/encoding/" xmlns:xsd="http://www.w3.org/2001/XMLSchema +" soap:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" xmln +s:soap="http://schemas.xmlsoap.org/soap/envelope/"> <soap:Body> <IntegrateShipmentNotice xmlns="https://foo.com/"> <shipmentNotice>[live XML redacted out] </shipmentNotice> </IntegrateShipmentNotice> </soap:Body> </soap:Envelope> SOAP::Transport::HTTP::Client::send_receive: HTTP::Response=HASH(0x8d6 +5ddc) SOAP::Transport::HTTP::Client::send_receive: HTTP/1.1 400 Bad Request Cache-Control: private Date: Tue, 28 Aug 2007 14:02:56 GMT Server: Microsoft-IIS/6.0 Content-Length: 0 Client-Date: Tue, 28 Aug 2007 13:59:27 GMT Client-Peer: Client-Response-Num: 1 Client-SSL-Cert-Issuer: /C=GB/ST=Greater Manchester/L=Salford/O=Comodo + CA Limited/CN=PositiveSSL CA Client-SSL-Cert-Subject: /OU=Domain Control Validated/OU=PositiveSSL/C +N=fulfillment.sciona.com Client-SSL-Cipher: RC4-MD5 Client-SSL-Warning: Peer certificate not verified X-AspNet-Version: 2.0.50727 X-Powered-By: ASP.NET 400 Bad Request at ./procShipAck.SOAP.pl line 80 SOAP::Data::DESTROY: () SOAP::Data::DESTROY: () SOAP::Data::DESTROY: () SOAP::Transport::HTTP::Client::DESTROY: () SOAP::Lite::DESTROY: () SOAP::Deserializer::DESTROY: () SOAP::Parser::DESTROY: () SOAP::Transport::DESTROY: () SOAP::Serializer::DESTROY: () SOAP::Data::DESTROY: () SOAP::Data::DESTROY: () SOAP::Data::DESTROY: ()
So, then, to my script:
#!/usr/bin/perl -w use strict; use SOAP::Lite qw( debug ); $SOAP::Constants::DO_NOT_USE_CHARSET = 1; my $XMLURI = 'https://foo.com/'; my $PROXY = 'https://foo.com/service.asmx'; my @files; # If files have been passed on the command line, use them. if ( @ARGV ) { foreach my $this_file ( @ARGV ) { if ( -e $this_file && $this_file =~ m/\.xml \Z/smxi ) { push @files, $this_file; } } } exit if @files < 1; foreach my $ackfile ( @files ) { # There's gotta be a way to simply pass $ackfile straight to # SOAP::Lite instead of building a string, but I haven't # figured it out yet... open my $fh, "<", $ackfile or die "Can't open $ackfile: $!"; my @xml = <$fh>; close $fh; my $xml = join "", @xml; if ( not $debug ) { my $soap = SOAP::Lite -> uri( $XMLURI ) -> proxy( $PROXY ) -> default_ns( $XMLURI ) -> autotype( 0 ) -> on_action( sub { 'https://foo.com/IntegrateShipmentNotice' +} ) ; print $soap->IntegrateShipmentNotice( SOAP::Data->name( shipmentNotice => $xml ) ) -> result . "\n\n" ; } else { print $xml . "\n"; } }
Now, I can't figure out what I'm doing wrong. The only difference I have been able to find is that SOAP::Lite produces two extra namespaces inside the SOAP envelope: xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" and soap:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" If anyone can lend any help, I would really appreciate it! Even help on how to further debug this would be useful. Unfortunately I do not have control over the server hosting the web service, so I can't access logs and such. Mike
fnord

In reply to SOAP::Lite woes by 23skiddoo

Title:
Use:  <p> text here (a paragraph) </p>
and:  <code> code here </code>
to format your post, it's "PerlMonks-approved HTML":



  • Posts are HTML formatted. Put <p> </p> tags around your paragraphs. Put <code> </code> tags around your code and data!
  • Titles consisting of a single word are discouraged, and in most cases are disallowed outright.
  • Read Where should I post X? if you're not absolutely sure you're posting in the right place.
  • Please read these before you post! —
  • Posts may use any of the Perl Monks Approved HTML tags:
    a, abbr, b, big, blockquote, br, caption, center, col, colgroup, dd, del, details, div, dl, dt, em, font, h1, h2, h3, h4, h5, h6, hr, i, ins, li, ol, p, pre, readmore, small, span, spoiler, strike, strong, sub, summary, sup, table, tbody, td, tfoot, th, thead, tr, tt, u, ul, wbr
  • You may need to use entities for some characters, as follows. (Exception: Within code tags, you can put the characters literally.)
            For:     Use:
    & &amp;
    < &lt;
    > &gt;
    [ &#91;
    ] &#93;
  • Link using PerlMonks shortcuts! What shortcuts can I use for linking?
  • See Writeup Formatting Tips and other pages linked from there for more info.