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

VB.NET client, SOAP::Lite server/service, complex types..

Expand Messages
  • bogusexception
    Group, As promised, I m posting the resolution (sorta) for this problem. This is what works for me, and it is not a solution. It is more like a work-around. I
    Message 1 of 1 , Mar 3, 2006
    View Source
    • 0 Attachment
      Group,

      As promised, I'm posting the resolution (sorta) for this problem.
      This is what works for me, and it is not a solution. It is more like
      a work-around. I really wanted to find a way to make Perl behave
      with .NET, but it was not to be. Such things being this hard don't do
      the Perl community any good.

      So here is the scenario:

      -VB.NET web services client
      -Linux server, Apache, SOAP::Lite
      -MySQL backend database access needed
      -SSL on server (no relevance for this group, but creates with its own
      problems)

      Objective:

      Talk as normally as possible between the client and server, hopefully
      to include complexTypes.

      Solution Overview:

      Send data (complex or otherwise) from VB.NET
      Receive data from SOAP::Lite as a single string(!).

      The problem isn't with the forgiving Perl. Oh no. It is with the
      unforgiving .NET. Errors of ANY kind in the XML, and .NET just sits
      there. No errors, nothing. There is no solution to this to be found
      on the Internet, other than obscure postings hinting that it had been
      done, and to read the docs some more. Well, I can tell you that after
      reading everything and finding no examples online, whoever has
      figured this out is keeping it a secret. It has become the stuff of
      Perl Legends (tm).

      I have had help from a few good souls, Matt L. (solved this with
      comma-delimiters) and Robin K. for pointing the way with his hand-
      rolled XML in a single string. I also borrowed from an example online
      that passes a single string between client and server, and built off
      that.

      WSDL (from the VS IDE):

      <?xml version="1.0" encoding="utf-8"?>
      <wsdl:definitions xmlns:http="http://schemas.xmlsoap.org/wsdl/http/"
      xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
      xmlns:s="http://www.w3.org/2001/XMLSchema"
      xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/"
      xmlns:tns="urn:singleString"
      xmlns:tm="http://microsoft.com/wsdl/mime/textMatching/"
      xmlns:mime="http://schemas.xmlsoap.org/wsdl/mime/"
      targetNamespace="urn:singleString" name="singleString"
      xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/">
      <documentation xmlns="http://schemas.xmlsoap.org/wsdl/">
      The WSDL Spec for singleString
      </documentation>
      <wsdl:types />
      <wsdl:message name="singleStringFuncRequest">
      <wsdl:part name="input" type="s:string" />
      </wsdl:message>
      <wsdl:message name="singleStringFuncResponse">
      <wsdl:part name="singleStringFuncResult" type="s:string" />
      </wsdl:message>
      <wsdl:portType name="singleStringPort">
      <wsdl:operation name="singleStringFunc">
      <wsdl:input message="tns:singleStringFuncRequest" />
      <wsdl:output message="tns:singleStringFuncResponse" />
      </wsdl:operation>
      </wsdl:portType>
      <wsdl:binding name="SOAP" type="tns:singleStringPort">
      <soap:binding transport="http://schemas.xmlsoap.org/soap/http"
      style="rpc" />
      <wsdl:operation name="singleStringFunc">
      <soap:operation
      soapAction="urn:singleString#singleStringFunc" />
      <wsdl:input>
      <soap:body use="encoded" namespace="urn:singleString"
      encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" />
      </wsdl:input>
      <wsdl:output>
      <soap:body use="encoded" namespace="urn:singleString"
      encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" />
      </wsdl:output>
      </wsdl:operation>
      </wsdl:binding>
      <wsdl:service name="singleString">
      <wsdl:port name="singleStringPort" binding="tns:SOAP">
      <soap:address location="https://server/ExSimpleXML.vtg" />
      </wsdl:port>
      </wsdl:service>
      </wsdl:definitions>

      I used CGI initially, as it was quick to setup. I'm now migrating off
      of CGI and onto mod_perl or mod_soap. Here is the CGI file pointed to
      above:

      #!/usr/bin/perl -w
      #
      #
      #
      use SOAP::Transport::HTTP;
      #
      #####
      #
      # direct the SOAP call...
      #
      SOAP::Transport::HTTP::CGI
      ->dispatch_to('singleString')
      ->handle;
      #
      #####

      package singleString;

      sub singleStringFunc {

      my($self, $input) = @_;
      if( not $input ){
      die SOAP::Fault
      ->faultcode('Server.Custom')
      ->faultstring('Nothing sent!');
      }
      #####
      #
      # 1. create the XML to be passed as a string
      #
      use XML::Generator::DBI;
      use XML::Handler::YAWriter;
      use DBI;
      #
      my $ya = XML::Handler::YAWriter->new(AsString => "-");
      my $dbh = DBI->connect("DBI:mysql:DatabaseName", "user", 'password');
      my $generator = XML::Generator::DBI->new(Handler => $ya, dbh => $dbh);
      my $sql = "SELECT * FROM hostInfo";
      my $out = $generator->execute($sql);
      #
      #####
      #
      # 2. pass the XML as a simple string..
      #
      # You must use type and uri on all items for .NET
      #
      return SOAP::Data
      ->name('singleStringFuncResult')
      ->value($out)
      ->type('string')
      ->uri('urn:singleString');
      #
      # end sub singleStringFunc
      #
      }
      #
      #####

      You just can't get database stuff out of a database and into XML any
      faster/easier than that with perl! As you can see, the results ($out)
      are sent as-is right out as a single string.

      There is something to note here.. By default, XML::Generator::DBI
      will make a top level XML tag of <database>, and one below it called
      <select>. Each row returned is <row>. This is fine, but this extra
      info is inappropriate and unneeded when it comes to using the XML
      in .NET. When you go to fill a datagrid, for example, these extra
      tags make it harder.

      To fix this, I initially regex'd them out in the perl module before
      sending to the client. It worked, so now I'm going to put that code
      on the client. The purpose of the project is to offload as much
      processing as possible from the server and put it on the clients.

      My goal is to have absolutely no SQL statements on the RDBMS
      with "WHERE" or "ORDER BY" in them-unless for tiny tables such as
      users. There will be a LOT of data coming back to the client, so I
      need a lean solution. One real positive in this approach is that the
      actual XML returned to VB.NET is really small in comparison with
      strongly typed data that would make SOAP.NET happy. This increase in
      speed is appreciated, as the client may be asking for up to 4GB of
      content per request. Every ounce counts a LOT whe you do it in
      quantity.

      Finally, the VB.NET client. The WSDL file was added ("Add Web
      Reference"), Reference.vb had to be manually edited for SSL
      (grrr...), and this is the client code of interest that fills a
      datagrid:

      Dim r = WS.singleStringFunc(Me.txtSendString.Text)
      Dim dsTest As New DataSet
      Dim srTest As New System.io.StringReader(r)
      dsTest.ReadXml(srTest)
      DataGrid1.DataSource = dsTest.Tables(0)

      This handy snippet of code converts the string-ified XML into real
      XML and pops it into a datagrid. If not obvious, "WS" is the instance
      of the web service described in the ingested WSDL file.

      This really kicks ass, so I'd love to hear from anyone who figured
      out a better way!

      pat
      :)
    Your message has been successfully submitted and would be delivered to recipients shortly.