Loading ...
Sorry, an error occurred while loading the content.

Passing an object array between a SOAP::Lite client and a VB.net web service

Expand Messages
  • selberg_scott
    I ve been beating my head against this one for a while and not finding any solutions, so I thought I would post mine. Talking to the .net service from SOAP was
    Message 1 of 1 , Jan 16, 2007
    View Source
    • 0 Attachment
      I've been beating my head against this one for a while and not finding
      any solutions, so I thought I would post mine.

      Talking to the .net service from SOAP was easy with all the interop
      stuff. Passing single parameters worked great to; however, when I
      passed an array it would not be de-parsed by .Net. If I tried to use
      the information, the .net service would die with an uninstatitated
      object error. Below is my magic receipe. There may be other
      solutions, but it was the only approach I found which worked. (Of
      course, I stopped looking when I found one.)

      The .Net service is quite simple. It accepts an object array and
      returns it. My goal is to pass parameters in a hash style to avoid
      needing to modify the interfaces when I add or remove parameters.

      <%@ WebService Language="VB" Class="CollectionWebServiceExample" %>
      Imports System.Web.Services

      <WebService(Namespace:="echoCollection")> _
      Public Class CollectionWebServiceExample
      Inherits System.Web.Services.WebService

      <WebMethod( Description := "Example for passing an object array")> _
      Public Function EchoCollection( objectArray() as Object ) As
      Object()
      EchoCollection = objectArray
      End Function

      End Class

      Now, the perl script. What seems to be the magic trick is matching
      the pass parameter variable (objectArray) and making every array item
      have the name "anyType". SOAP::Lite defaults to "item", so every
      member must be explicitly set in a SOAP::Data block.

      #!/usr/bin/perl -w
      ########################################
      =head1 NAME

      echoCollection.pl - a command line client to ping the soap server

      =head1 DESCRIPTION

      =head1 $Author: selberg $

      =head1 $Date: 2006-08-01 11:08:23-07 $

      =head1 $Revision: 1.3 $

      =head1 COPYRIGHT

      Copyright 1/16/2007, Agilent Technologies.

      This program is free software. You may copy,
      modify, or redistribute it under the same terms
      as Perl itself.

      =cut

      ########################################
      use strict "vars";
      use SOAP::Lite;
      use Getopt::Std;
      use Data::Dumper;
      my $soapPipeLine;

      my $function = 'EchoCollection';
      my $server = "http://myserver.mydomain.com/echoCollection.asmx";
      my $port;
      my $nameSpace = 'echoCollection';
      my %options;
      my @results;
      my $i;
      my @args;
      my $array;
      getopt( 'ts:p:n:f:', \%options );

      #Turn on the SOAP::Lite trace
      SOAP::Trace->import( 'debug' ) if defined( $options{'t'} );

      $server = $options{ 's' } if defined( $options{ 's' } );
      $port = $options{ 'p' } if defined( $options{ 'p' } );
      $nameSpace = $options{ 'n' } if defined( $options{ 'n' } );
      $function = $options{ 'f' } if defined( $options{ 'f' } );

      $server =~ s/(\/\/[^:\/]+)(:\d+)?/$1:$port/ if defined( $port );

      push( @args, 'objectArray' );
      push( @args, @ARGV ) if $#ARGV >= 0;
      push( @args, [ 1, 2, 3 ] );

      @results = soapCall( $function, $server, $nameSpace, @args);
      print Dumper( @results );

      sub soapCall
      {
      my $function = shift;
      my $server = shift;
      my $nameSpace = shift;
      my $arrayName = shift;
      my @rawValues = @_;
      my @soapValues;

      my $timeOut; # = 5;
      my $msServer = 1;

      my $soapPipeLine;
      my @results;
      my $error;
      my @parameters;
      my $arg;
      my $callResult;
      my $buffer;

      $soapPipeLine = SOAP::Lite
      -> uri( $nameSpace )
      -> proxy( $server );

      $soapPipeLine-> on_action( sub{ join( '/', @_ ) } ) if defined(
      $msServer ); # microsoft workaround
      $soapPipeLine->transport->timeout( $timeOut ) if defined(
      $timeOut );

      # custom workaround for passing to .Net
      # on the server side (VB.net):
      # <SoapDocumentMethod( Use:=SoapBindingUse.Literal, _
      # ParameterStyle:=SoapParameterStyle.Wrapped, _
      # RequestElementName:="EchoCollection" ), _
      # WebMethod( Description := "Example for passing an object array")> _
      # Public Function EchoCollection( objectArray() as Object ) As Object
      # EchoCollection = objectArray.Length
      # EchoCollection = objectArray(0)
      # End Function

      # $arrayName needs to match the name of the pass parameter variable
      in the .Net service
      # each array item should be labeled "anyType"

      foreach $buffer (@rawValues)
      {
      push( @soapValues, SOAP::Data->name('anyType' => $buffer) )
      }
      $buffer = SOAP::Data->name( $arrayName => \@soapValues );
      push( @parameters, $buffer );

      eval{
      $callResult = $soapPipeLine->call( $function => @parameters );
      };

      if( $@ )
      {
      warn( $@ . "\n" );
      @results = ();
      }
      else
      {
      if( ref( $callResult ) and $callResult->fault )
      {
      $error .= sprintf( "Fault Code: " . $callResult->faultcode
      . "\n" ) if $callResult->faultcode;
      $error .= sprintf( "Fault String: " .
      $callResult->faultstring . "\n" ) if $callResult->faultstring;
      $error .= sprintf( "Fault Detail: " .
      $callResult->faultdetail . "\n" ) if $callResult->faultdetail;
      $error .= sprintf( "Fault Actor: " . $callResult->faultactor
      . "\n" ) if $callResult->faultactor;

      warn( $error );
      @results = ();
      }
      elsif( ref( $callResult ) and defined( $callResult->result ) )
      {
      @results = ( $callResult->result );
      push( @results, $callResult->paramsout ) if(
      $callResult->paramsout );
      }
      }

      @results = @{ $results[0]->{anyType} } if defined( $results[0] );

      return wantarray ? @results : $results[0];
      }
    Your message has been successfully submitted and would be delivered to recipients shortly.